| 
					
				 | 
			
			
				@@ -0,0 +1,474 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Copyright 2002-2020 the original author or authors. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Licensed under the Apache License, Version 2.0 (the "License"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * you may not use this file except in compliance with the License. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * You may obtain a copy of the License at 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ *      https://www.apache.org/licenses/LICENSE-2.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Unless required by applicable law or agreed to in writing, software 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * distributed under the License is distributed on an "AS IS" BASIS, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * See the License for the specific language governing permissions and 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * limitations under the License. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+package org.springframework.security.oauth2.client; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.junit.After; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.junit.Before; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.junit.Test; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.dao.DataRetrievalFailureException; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.dao.DuplicateKeyException; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.jdbc.core.ArgumentPreparedStatementSetter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.jdbc.core.JdbcOperations; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.jdbc.core.JdbcTemplate; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.jdbc.core.PreparedStatementSetter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.jdbc.core.RowMapper; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.jdbc.core.SqlParameterValue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.authentication.TestingAuthenticationToken; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.core.Authentication; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.oauth2.client.registration.ClientRegistration; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.oauth2.client.registration.TestClientRegistrations; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.oauth2.core.OAuth2AccessToken; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.oauth2.core.OAuth2RefreshToken; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.oauth2.core.TestOAuth2AccessTokens; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.security.oauth2.core.TestOAuth2RefreshTokens; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.util.Assert; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.util.StringUtils; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.nio.charset.StandardCharsets; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.sql.ResultSet; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.sql.SQLException; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.sql.Timestamp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.sql.Types; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.time.Instant; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.Collections; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.List; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.Set; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import static org.assertj.core.api.Assertions.assertThat; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import static org.assertj.core.api.Assertions.assertThatThrownBy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import static org.mockito.ArgumentMatchers.any; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import static org.mockito.ArgumentMatchers.anyInt; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import static org.mockito.Mockito.mock; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import static org.mockito.Mockito.spy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import static org.mockito.Mockito.verify; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import static org.mockito.Mockito.when; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Tests for {@link JdbcOAuth2AuthorizedClientService}. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @author Joe Grandja 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+public class JdbcOAuth2AuthorizedClientServiceTests { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private static final String OAUTH2_CLIENT_SCHEMA_SQL_RESOURCE = "org/springframework/security/oauth2/client/oauth2-client-schema.sql"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private static int principalId = 1000; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private ClientRegistration clientRegistration; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private ClientRegistrationRepository clientRegistrationRepository; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private EmbeddedDatabase db; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private JdbcOperations jdbcOperations; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private JdbcOAuth2AuthorizedClientService authorizedClientService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Before 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void setUp() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.clientRegistration = TestClientRegistrations.clientRegistration().build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.clientRegistrationRepository = mock(ClientRegistrationRepository.class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(this.clientRegistration); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.db = createDb(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.jdbcOperations = new JdbcTemplate(this.db); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.authorizedClientService = new JdbcOAuth2AuthorizedClientService( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.jdbcOperations, this.clientRegistrationRepository); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@After 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void tearDown() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.db.shutdown(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void constructorWhenJdbcOperationsIsNullThenThrowIllegalArgumentException() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThatThrownBy(() -> new JdbcOAuth2AuthorizedClientService(null, this.clientRegistrationRepository)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.isInstanceOf(IllegalArgumentException.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.hasMessage("jdbcOperations cannot be null"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void constructorWhenClientRegistrationRepositoryIsNullThenThrowIllegalArgumentException() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThatThrownBy(() -> new JdbcOAuth2AuthorizedClientService(this.jdbcOperations, null)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.isInstanceOf(IllegalArgumentException.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.hasMessage("clientRegistrationRepository cannot be null"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void setAuthorizedClientRowMapperWhenNullThenThrowIllegalArgumentException() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThatThrownBy(() -> this.authorizedClientService.setAuthorizedClientRowMapper(null)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.isInstanceOf(IllegalArgumentException.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.hasMessage("authorizedClientRowMapper cannot be null"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void setAuthorizedClientParametersMapperWhenNullThenThrowIllegalArgumentException() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThatThrownBy(() -> this.authorizedClientService.setAuthorizedClientParametersMapper(null)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.isInstanceOf(IllegalArgumentException.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.hasMessage("authorizedClientParametersMapper cannot be null"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void loadAuthorizedClientWhenClientRegistrationIdIsNullThenThrowIllegalArgumentException() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThatThrownBy(() -> this.authorizedClientService.loadAuthorizedClient(null, "principalName")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.isInstanceOf(IllegalArgumentException.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.hasMessage("clientRegistrationId cannot be empty"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void loadAuthorizedClientWhenPrincipalNameIsNullThenThrowIllegalArgumentException() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThatThrownBy(() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistration.getRegistrationId(), null)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.isInstanceOf(IllegalArgumentException.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.hasMessage("principalName cannot be empty"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void loadAuthorizedClientWhenDoesNotExistThenReturnNull() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AuthorizedClient authorizedClient = this.authorizedClientService.loadAuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"registration-not-found", "principalName"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient).isNull(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void loadAuthorizedClientWhenExistsThenReturnAuthorizedClient() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Authentication principal = createPrincipal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AuthorizedClient expected = createAuthorizedClient(principal, this.clientRegistration); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.authorizedClientService.saveAuthorizedClient(expected, principal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AuthorizedClient authorizedClient = this.authorizedClientService.loadAuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.clientRegistration.getRegistrationId(), principal.getName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient).isNotNull(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getClientRegistration()).isEqualTo(expected.getClientRegistration()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getPrincipalName()).isEqualTo(expected.getPrincipalName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getTokenType()).isEqualTo(expected.getAccessToken().getTokenType()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getTokenValue()).isEqualTo(expected.getAccessToken().getTokenValue()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getIssuedAt()).isEqualTo(expected.getAccessToken().getIssuedAt()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getExpiresAt()).isEqualTo(expected.getAccessToken().getExpiresAt()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getScopes()).isEqualTo(expected.getAccessToken().getScopes()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getRefreshToken().getTokenValue()).isEqualTo(expected.getRefreshToken().getTokenValue()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getRefreshToken().getIssuedAt()).isEqualTo(expected.getRefreshToken().getIssuedAt()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void loadAuthorizedClientWhenExistsButNotFoundInClientRegistrationRepositoryThenThrowDataRetrievalFailureException() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		when(this.clientRegistrationRepository.findByRegistrationId(any())).thenReturn(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Authentication principal = createPrincipal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AuthorizedClient expected = createAuthorizedClient(principal, this.clientRegistration); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.authorizedClientService.saveAuthorizedClient(expected, principal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThatThrownBy(() -> this.authorizedClientService.loadAuthorizedClient(this.clientRegistration.getRegistrationId(), principal.getName())) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.isInstanceOf(DataRetrievalFailureException.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.hasMessage("The ClientRegistration with id '" + this.clientRegistration.getRegistrationId() + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						"' exists in the data source, however, it was not found in the ClientRegistrationRepository."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void saveAuthorizedClientWhenAuthorizedClientIsNullThenThrowIllegalArgumentException() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Authentication principal = createPrincipal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThatThrownBy(() -> this.authorizedClientService.saveAuthorizedClient(null, principal)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.isInstanceOf(IllegalArgumentException.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.hasMessage("authorizedClient cannot be null"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void saveAuthorizedClientWhenPrincipalIsNullThenThrowIllegalArgumentException() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Authentication principal = createPrincipal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AuthorizedClient authorizedClient = createAuthorizedClient(principal, this.clientRegistration); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThatThrownBy(() -> this.authorizedClientService.saveAuthorizedClient(authorizedClient, null)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.isInstanceOf(IllegalArgumentException.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.hasMessage("principal cannot be null"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void saveAuthorizedClientWhenSaveThenLoadReturnsSaved() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Authentication principal = createPrincipal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AuthorizedClient expected = createAuthorizedClient(principal, this.clientRegistration); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.authorizedClientService.saveAuthorizedClient(expected, principal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AuthorizedClient authorizedClient = this.authorizedClientService.loadAuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.clientRegistration.getRegistrationId(), principal.getName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient).isNotNull(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getClientRegistration()).isEqualTo(expected.getClientRegistration()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getPrincipalName()).isEqualTo(expected.getPrincipalName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getTokenType()).isEqualTo(expected.getAccessToken().getTokenType()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getTokenValue()).isEqualTo(expected.getAccessToken().getTokenValue()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getIssuedAt()).isEqualTo(expected.getAccessToken().getIssuedAt()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getExpiresAt()).isEqualTo(expected.getAccessToken().getExpiresAt()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getScopes()).isEqualTo(expected.getAccessToken().getScopes()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getRefreshToken().getTokenValue()).isEqualTo(expected.getRefreshToken().getTokenValue()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getRefreshToken().getIssuedAt()).isEqualTo(expected.getRefreshToken().getIssuedAt()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// Test save/load of NOT NULL attributes only 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		principal = createPrincipal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		expected = createAuthorizedClient(principal, this.clientRegistration, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.authorizedClientService.saveAuthorizedClient(expected, principal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		authorizedClient = this.authorizedClientService.loadAuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.clientRegistration.getRegistrationId(), principal.getName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient).isNotNull(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getClientRegistration()).isEqualTo(expected.getClientRegistration()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getPrincipalName()).isEqualTo(expected.getPrincipalName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getTokenType()).isEqualTo(expected.getAccessToken().getTokenType()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getTokenValue()).isEqualTo(expected.getAccessToken().getTokenValue()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getIssuedAt()).isEqualTo(expected.getAccessToken().getIssuedAt()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getExpiresAt()).isEqualTo(expected.getAccessToken().getExpiresAt()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getAccessToken().getScopes()).isEmpty(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient.getRefreshToken()).isNull(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void saveAuthorizedClientWhenSaveDuplicateThenThrowDuplicateKeyException() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Authentication principal = createPrincipal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AuthorizedClient authorizedClient = createAuthorizedClient(principal, this.clientRegistration); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.authorizedClientService.saveAuthorizedClient(authorizedClient, principal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThatThrownBy(() -> this.authorizedClientService.saveAuthorizedClient(authorizedClient, principal)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.isInstanceOf(DuplicateKeyException.class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void saveLoadAuthorizedClientWhenCustomStrategiesSetThenCalled() throws Exception { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		JdbcOAuth2AuthorizedClientService.OAuth2AuthorizedClientRowMapper authorizedClientRowMapper = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				spy(new JdbcOAuth2AuthorizedClientService.OAuth2AuthorizedClientRowMapper(this.clientRegistrationRepository)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.authorizedClientService.setAuthorizedClientRowMapper(authorizedClientRowMapper); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		JdbcOAuth2AuthorizedClientService.OAuth2AuthorizedClientParametersMapper authorizedClientParametersMapper = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				spy(new JdbcOAuth2AuthorizedClientService.OAuth2AuthorizedClientParametersMapper()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.authorizedClientService.setAuthorizedClientParametersMapper(authorizedClientParametersMapper); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Authentication principal = createPrincipal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AuthorizedClient authorizedClient = createAuthorizedClient(principal, this.clientRegistration); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.authorizedClientService.saveAuthorizedClient(authorizedClient, principal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.authorizedClientService.loadAuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.clientRegistration.getRegistrationId(), principal.getName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		verify(authorizedClientRowMapper).mapRow(any(), anyInt()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		verify(authorizedClientParametersMapper).apply(any()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void removeAuthorizedClientWhenClientRegistrationIdIsNullThenThrowIllegalArgumentException() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThatThrownBy(() -> this.authorizedClientService.removeAuthorizedClient(null, "principalName")) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.isInstanceOf(IllegalArgumentException.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.hasMessage("clientRegistrationId cannot be empty"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void removeAuthorizedClientWhenPrincipalNameIsNullThenThrowIllegalArgumentException() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThatThrownBy(() -> this.authorizedClientService.removeAuthorizedClient(this.clientRegistration.getRegistrationId(), null)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.isInstanceOf(IllegalArgumentException.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.hasMessage("principalName cannot be empty"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void removeAuthorizedClientWhenExistsThenRemoved() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Authentication principal = createPrincipal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AuthorizedClient authorizedClient = createAuthorizedClient(principal, this.clientRegistration); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.authorizedClientService.saveAuthorizedClient(authorizedClient, principal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		authorizedClient = this.authorizedClientService.loadAuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.clientRegistration.getRegistrationId(), principal.getName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient).isNotNull(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.authorizedClientService.removeAuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.clientRegistration.getRegistrationId(), principal.getName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		authorizedClient = this.authorizedClientService.loadAuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.clientRegistration.getRegistrationId(), principal.getName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient).isNull(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	@Test 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public void tableDefinitionWhenCustomThenAbleToOverride() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		CustomTableDefinitionJdbcOAuth2AuthorizedClientService customAuthorizedClientService = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				new CustomTableDefinitionJdbcOAuth2AuthorizedClientService( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						new JdbcTemplate(createDb("custom-oauth2-client-schema.sql")), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						this.clientRegistrationRepository); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Authentication principal = createPrincipal(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AuthorizedClient authorizedClient = createAuthorizedClient(principal, this.clientRegistration); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		customAuthorizedClientService.saveAuthorizedClient(authorizedClient, principal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		authorizedClient = customAuthorizedClientService.loadAuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.clientRegistration.getRegistrationId(), principal.getName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient).isNotNull(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		customAuthorizedClientService.removeAuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.clientRegistration.getRegistrationId(), principal.getName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		authorizedClient = customAuthorizedClientService.loadAuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.clientRegistration.getRegistrationId(), principal.getName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		assertThat(authorizedClient).isNull(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private static EmbeddedDatabase createDb() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return createDb(OAUTH2_CLIENT_SCHEMA_SQL_RESOURCE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private static EmbeddedDatabase createDb(String schema) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return new EmbeddedDatabaseBuilder() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.generateUniqueName(true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.setType(EmbeddedDatabaseType.HSQL) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.setScriptEncoding("UTF-8") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.addScript(schema) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				.build(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private static Authentication createPrincipal() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return new TestingAuthenticationToken("principal-" + principalId++, "password"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private static OAuth2AuthorizedClient createAuthorizedClient(Authentication principal, ClientRegistration clientRegistration) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return createAuthorizedClient(principal, clientRegistration, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private static OAuth2AuthorizedClient createAuthorizedClient(Authentication principal, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			ClientRegistration clientRegistration, boolean requiredAttributesOnly) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2AccessToken accessToken; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (!requiredAttributesOnly) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			accessToken = TestOAuth2AccessTokens.scopes("read", "write"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			accessToken = TestOAuth2AccessTokens.noScopes(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		OAuth2RefreshToken refreshToken = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (!requiredAttributesOnly) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			refreshToken = TestOAuth2RefreshTokens.refreshToken(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return new OAuth2AuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				clientRegistration, principal.getName(), accessToken, refreshToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private static class CustomTableDefinitionJdbcOAuth2AuthorizedClientService extends JdbcOAuth2AuthorizedClientService { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		private static final String COLUMN_NAMES = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"clientRegistrationId, " + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"principalName, " + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"accessTokenType, " + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"accessTokenValue, " + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"accessTokenIssuedAt, " + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"accessTokenExpiresAt, " + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"accessTokenScopes, " + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"refreshTokenValue, " + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				"refreshTokenIssuedAt"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		private static final String TABLE_NAME = "oauth2AuthorizedClient"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		private static final String PK_FILTER = "clientRegistrationId = ? AND principalName = ?"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		private static final String LOAD_AUTHORIZED_CLIENT_SQL = "SELECT " + COLUMN_NAMES + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				" FROM " + TABLE_NAME + " WHERE " + PK_FILTER; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		private static final String SAVE_AUTHORIZED_CLIENT_SQL = "INSERT INTO " + TABLE_NAME + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				" (" + COLUMN_NAMES + ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		private static final String REMOVE_AUTHORIZED_CLIENT_SQL = "DELETE FROM " + TABLE_NAME + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				" WHERE " + PK_FILTER; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		private CustomTableDefinitionJdbcOAuth2AuthorizedClientService( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				JdbcOperations jdbcOperations, ClientRegistrationRepository clientRegistrationRepository) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			super(jdbcOperations, clientRegistrationRepository); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			setAuthorizedClientRowMapper(new OAuth2AuthorizedClientRowMapper(clientRegistrationRepository)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		@Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		@SuppressWarnings("unchecked") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		public <T extends OAuth2AuthorizedClient> T loadAuthorizedClient(String clientRegistrationId, String principalName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			SqlParameterValue[] parameters = new SqlParameterValue[] { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					new SqlParameterValue(Types.VARCHAR, clientRegistrationId), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					new SqlParameterValue(Types.VARCHAR, principalName) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PreparedStatementSetter pss = new ArgumentPreparedStatementSetter(parameters); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			List<OAuth2AuthorizedClient> result = this.jdbcOperations.query( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					LOAD_AUTHORIZED_CLIENT_SQL, pss, this.authorizedClientRowMapper); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return !result.isEmpty() ? (T) result.get(0) : null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		@Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		public void saveAuthorizedClient(OAuth2AuthorizedClient authorizedClient, Authentication principal) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			List<SqlParameterValue> parameters = this.authorizedClientParametersMapper.apply( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					new OAuth2AuthorizedClientHolder(authorizedClient, principal)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PreparedStatementSetter pss = new ArgumentPreparedStatementSetter(parameters.toArray()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			this.jdbcOperations.update(SAVE_AUTHORIZED_CLIENT_SQL, pss); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		@Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		public void removeAuthorizedClient(String clientRegistrationId, String principalName) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			SqlParameterValue[] parameters = new SqlParameterValue[] { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					new SqlParameterValue(Types.VARCHAR, clientRegistrationId), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					new SqlParameterValue(Types.VARCHAR, principalName) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			PreparedStatementSetter pss = new ArgumentPreparedStatementSetter(parameters); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			this.jdbcOperations.update(REMOVE_AUTHORIZED_CLIENT_SQL, pss); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		private static class OAuth2AuthorizedClientRowMapper implements RowMapper<OAuth2AuthorizedClient> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			private final ClientRegistrationRepository clientRegistrationRepository; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			private OAuth2AuthorizedClientRowMapper(ClientRegistrationRepository clientRegistrationRepository) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.clientRegistrationRepository = clientRegistrationRepository; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			@Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			public OAuth2AuthorizedClient mapRow(ResultSet rs, int rowNum) throws SQLException { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				String clientRegistrationId = rs.getString("clientRegistrationId"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						clientRegistrationId); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (clientRegistration == null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					throw new DataRetrievalFailureException("The ClientRegistration with id '" + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							clientRegistrationId + "' exists in the data source, " + 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							"however, it was not found in the ClientRegistrationRepository."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				OAuth2AccessToken.TokenType tokenType = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (OAuth2AccessToken.TokenType.BEARER.getValue().equalsIgnoreCase( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						rs.getString("accessTokenType"))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					tokenType = OAuth2AccessToken.TokenType.BEARER; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				String tokenValue = new String(rs.getBytes("accessTokenValue"), StandardCharsets.UTF_8); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				Instant issuedAt = rs.getTimestamp("accessTokenIssuedAt").toInstant(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				Instant expiresAt = rs.getTimestamp("accessTokenExpiresAt").toInstant(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				Set<String> scopes = Collections.emptySet(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				String accessTokenScopes = rs.getString("accessTokenScopes"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (accessTokenScopes != null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					scopes = StringUtils.commaDelimitedListToSet(accessTokenScopes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				OAuth2AccessToken accessToken = new OAuth2AccessToken( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						tokenType, tokenValue, issuedAt, expiresAt, scopes); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				OAuth2RefreshToken refreshToken = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				byte[] refreshTokenValue = rs.getBytes("refreshTokenValue"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (refreshTokenValue != null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					tokenValue = new String(refreshTokenValue, StandardCharsets.UTF_8); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					issuedAt = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					Timestamp refreshTokenIssuedAt = rs.getTimestamp("refreshTokenIssuedAt"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if (refreshTokenIssuedAt != null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						issuedAt = refreshTokenIssuedAt.toInstant(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					refreshToken = new OAuth2RefreshToken(tokenValue, issuedAt); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				String principalName = rs.getString("principalName"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return new OAuth2AuthorizedClient( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						clientRegistration, principalName, accessToken, refreshToken); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |