Browse Source

Polish tests using AuthorizationCodeGrantFlow

Steve Riesenberg 3 years ago
parent
commit
51d00742f3

+ 9 - 99
docs/src/docs/asciidoc/examples/src/test/java/sample/gettingStarted/SecurityConfigTests.java

@@ -15,17 +15,12 @@
  */
 package sample.gettingStarted;
 
-import java.net.URLDecoder;
-import java.nio.charset.StandardCharsets;
 import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import org.assertj.core.api.ObjectAssert;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import sample.AuthorizationCodeGrantFlow;
 import sample.test.SpringTestContext;
 import sample.test.SpringTestContextExtension;
 
@@ -34,13 +29,9 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Import;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
-import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.security.oauth2.core.OAuth2TokenType;
-import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
 import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
 import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService;
@@ -53,21 +44,9 @@ import org.springframework.security.oauth2.server.authorization.client.InMemoryR
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
 import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.MvcResult;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
 import org.springframework.util.StringUtils;
-import org.springframework.web.util.UriComponents;
-import org.springframework.web.util.UriComponentsBuilder;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.hamcrest.Matchers.containsString;
-import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 
 /**
  * Tests for the Getting Started section of the reference documentation.
@@ -76,10 +55,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
  */
 @ExtendWith(SpringTestContextExtension.class)
 public class SecurityConfigTests {
-	private static final Pattern HIDDEN_STATE_INPUT_PATTERN = Pattern.compile(".+<input type=\"hidden\" name=\"state\" value=\"([^\"]+)\">.+");
-	private static final TypeReference<Map<String, Object>> TOKEN_RESPONSE_TYPE_REFERENCE = new TypeReference<Map<String, Object>>() {
-	};
-
 	public final SpringTestContext spring = new SpringTestContext(this);
 
 	@Autowired
@@ -104,15 +79,20 @@ public class SecurityConfigTests {
 		RegisteredClient registeredClient = this.registeredClientRepository.findByClientId("messaging-client");
 		assertThat(registeredClient).isNotNull();
 
-		String state = performAuthorizationCodeRequest(registeredClient);
+		AuthorizationCodeGrantFlow authorizationCodeGrantFlow = new AuthorizationCodeGrantFlow(this.mockMvc);
+		authorizationCodeGrantFlow.setUsername("user");
+		authorizationCodeGrantFlow.addScope("message.read");
+		authorizationCodeGrantFlow.addScope("message.write");
+
+		String state = authorizationCodeGrantFlow.authorize(registeredClient);
 		assertThatAuthorization(state, OAuth2ParameterNames.STATE).isNotNull();
 		assertThatAuthorization(state, null).isNotNull();
 
-		String authorizationCode = performAuthorizationConsentRequest(registeredClient, state);
+		String authorizationCode = authorizationCodeGrantFlow.submitConsent(registeredClient, state);
 		assertThatAuthorization(authorizationCode, OAuth2ParameterNames.CODE).isNotNull();
 		assertThatAuthorization(authorizationCode, null).isNotNull();
 
-		Map<String, Object> tokenResponse = performTokenRequest(registeredClient, authorizationCode);
+		Map<String, Object> tokenResponse = authorizationCodeGrantFlow.getTokenResponse(registeredClient, authorizationCode);
 		String accessToken = (String) tokenResponse.get(OAuth2ParameterNames.ACCESS_TOKEN);
 		assertThatAuthorization(accessToken, OAuth2ParameterNames.ACCESS_TOKEN).isNotNull();
 		assertThatAuthorization(accessToken, null).isNotNull();
@@ -143,76 +123,6 @@ public class SecurityConfigTests {
 		return this.authorizationService.findByToken(token, tokenType == null ? null : new OAuth2TokenType(tokenType));
 	}
 
-	private String performAuthorizationCodeRequest(RegisteredClient registeredClient) throws Exception {
-		MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
-		parameters.set(OAuth2ParameterNames.RESPONSE_TYPE, OAuth2AuthorizationResponseType.CODE.getValue());
-		parameters.set(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId());
-		parameters.set(OAuth2ParameterNames.REDIRECT_URI, registeredClient.getRedirectUris().iterator().next());
-		parameters.set(OAuth2ParameterNames.SCOPE,
-				StringUtils.collectionToDelimitedString(registeredClient.getScopes(), " "));
-		parameters.set(OAuth2ParameterNames.STATE, "state");
-
-		MvcResult mvcResult = this.mockMvc.perform(get("/oauth2/authorize")
-				.params(parameters)
-				.with(user("user").roles("USER")))
-				.andExpect(status().isOk())
-				.andExpect(header().string("content-type", containsString(MediaType.TEXT_HTML_VALUE)))
-				.andReturn();
-		String responseHtml = mvcResult.getResponse().getContentAsString();
-		Matcher matcher = HIDDEN_STATE_INPUT_PATTERN.matcher(responseHtml);
-
-		return matcher.matches() ? matcher.group(1) : null;
-	}
-
-	private String performAuthorizationConsentRequest(RegisteredClient registeredClient, String state) throws Exception {
-		MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
-		parameters.set(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId());
-		parameters.set(OAuth2ParameterNames.STATE, state);
-		parameters.add(OAuth2ParameterNames.SCOPE, "message.read");
-		parameters.add(OAuth2ParameterNames.SCOPE, "message.write");
-
-		MvcResult mvcResult = this.mockMvc.perform(post("/oauth2/authorize")
-				.params(parameters)
-				.with(user("user").roles("USER")))
-				.andExpect(status().is3xxRedirection())
-				.andReturn();
-		String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
-		assertThat(redirectedUrl).isNotNull();
-		assertThat(redirectedUrl).matches("http://127.0.0.1:8080/authorized\\?code=.{15,}&state=state");
-
-		String locationHeader = URLDecoder.decode(redirectedUrl, StandardCharsets.UTF_8.name());
-		UriComponents uriComponents = UriComponentsBuilder.fromUriString(locationHeader).build();
-
-		return uriComponents.getQueryParams().getFirst("code");
-	}
-
-	private Map<String, Object> performTokenRequest(RegisteredClient registeredClient, String authorizationCode) throws Exception {
-		MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
-		parameters.set(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
-		parameters.set(OAuth2ParameterNames.CODE, authorizationCode);
-		parameters.set(OAuth2ParameterNames.REDIRECT_URI, registeredClient.getRedirectUris().iterator().next());
-
-		HttpHeaders basicAuth = new HttpHeaders();
-		basicAuth.setBasicAuth(registeredClient.getClientId(), "secret");
-
-		MvcResult mvcResult = this.mockMvc.perform(post("/oauth2/token")
-				.params(parameters)
-				.headers(basicAuth))
-				.andExpect(status().isOk())
-				.andExpect(header().string(HttpHeaders.CONTENT_TYPE, containsString(MediaType.APPLICATION_JSON_VALUE)))
-				.andExpect(jsonPath("$.access_token").isNotEmpty())
-				.andExpect(jsonPath("$.token_type").isNotEmpty())
-				.andExpect(jsonPath("$.expires_in").isNotEmpty())
-				.andExpect(jsonPath("$.refresh_token").isNotEmpty())
-				.andExpect(jsonPath("$.scope").isNotEmpty())
-				.andExpect(jsonPath("$.id_token").isNotEmpty())
-				.andReturn();
-
-		ObjectMapper objectMapper = new ObjectMapper();
-		String responseJson = mvcResult.getResponse().getContentAsString();
-		return objectMapper.readValue(responseJson, TOKEN_RESPONSE_TYPE_REFERENCE);
-	}
-
 	@EnableWebSecurity
 	@EnableAutoConfiguration
 	@ComponentScan

+ 9 - 100
docs/src/docs/asciidoc/examples/src/test/java/sample/jpa/JpaTests.java

@@ -15,14 +15,8 @@
  */
 package sample.jpa;
 
-import java.net.URLDecoder;
-import java.nio.charset.StandardCharsets;
 import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.nimbusds.jose.jwk.JWKSet;
 import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
 import com.nimbusds.jose.jwk.source.JWKSource;
@@ -30,6 +24,7 @@ import com.nimbusds.jose.proc.SecurityContext;
 import org.assertj.core.api.ObjectAssert;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import sample.AuthorizationCodeGrantFlow;
 import sample.jose.TestJwks;
 import sample.test.SpringTestContext;
 import sample.test.SpringTestContextExtension;
@@ -39,13 +34,9 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Import;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 import org.springframework.security.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
-import org.springframework.security.oauth2.core.AuthorizationGrantType;
 import org.springframework.security.oauth2.core.OAuth2TokenType;
-import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationResponseType;
 import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
 import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
 import org.springframework.security.oauth2.jwt.JwtDecoder;
@@ -56,21 +47,9 @@ import org.springframework.security.oauth2.server.authorization.OAuth2Authorizat
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
 import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
 import org.springframework.test.web.servlet.MockMvc;
-import org.springframework.test.web.servlet.MvcResult;
-import org.springframework.util.LinkedMultiValueMap;
-import org.springframework.util.MultiValueMap;
 import org.springframework.util.StringUtils;
-import org.springframework.web.util.UriComponents;
-import org.springframework.web.util.UriComponentsBuilder;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.hamcrest.Matchers.containsString;
-import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
 import static sample.util.RegisteredClients.messagingClient;
 
 /**
@@ -80,11 +59,6 @@ import static sample.util.RegisteredClients.messagingClient;
  */
 @ExtendWith(SpringTestContextExtension.class)
 public class JpaTests {
-
-	private static final Pattern HIDDEN_STATE_INPUT_PATTERN = Pattern.compile(".+<input type=\"hidden\" name=\"state\" value=\"([^\"]+)\">.+");
-	private static final TypeReference<Map<String, Object>> TOKEN_RESPONSE_TYPE_REFERENCE = new TypeReference<Map<String, Object>>() {
-	};
-
 	public final SpringTestContext spring = new SpringTestContext(this);
 
 	@Autowired
@@ -109,15 +83,20 @@ public class JpaTests {
 		RegisteredClient registeredClient = messagingClient();
 		this.registeredClientRepository.save(registeredClient);
 
-		String state = performAuthorizationCodeRequest(registeredClient);
+		AuthorizationCodeGrantFlow authorizationCodeGrantFlow = new AuthorizationCodeGrantFlow(this.mockMvc);
+		authorizationCodeGrantFlow.setUsername("user");
+		authorizationCodeGrantFlow.addScope("message.read");
+		authorizationCodeGrantFlow.addScope("message.write");
+
+		String state = authorizationCodeGrantFlow.authorize(registeredClient);
 		assertThatAuthorization(state, OAuth2ParameterNames.STATE).isNotNull();
 		assertThatAuthorization(state, null).isNotNull();
 
-		String authorizationCode = performAuthorizationConsentRequest(registeredClient, state);
+		String authorizationCode = authorizationCodeGrantFlow.submitConsent(registeredClient, state);
 		assertThatAuthorization(authorizationCode, OAuth2ParameterNames.CODE).isNotNull();
 		assertThatAuthorization(authorizationCode, null).isNotNull();
 
-		Map<String, Object> tokenResponse = performTokenRequest(registeredClient, authorizationCode);
+		Map<String, Object> tokenResponse = authorizationCodeGrantFlow.getTokenResponse(registeredClient, authorizationCode);
 		String accessToken = (String) tokenResponse.get(OAuth2ParameterNames.ACCESS_TOKEN);
 		assertThatAuthorization(accessToken, OAuth2ParameterNames.ACCESS_TOKEN).isNotNull();
 		assertThatAuthorization(accessToken, null).isNotNull();
@@ -148,76 +127,6 @@ public class JpaTests {
 		return this.authorizationService.findByToken(token, tokenType == null ? null : new OAuth2TokenType(tokenType));
 	}
 
-	private String performAuthorizationCodeRequest(RegisteredClient registeredClient) throws Exception {
-		MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
-		parameters.set(OAuth2ParameterNames.RESPONSE_TYPE, OAuth2AuthorizationResponseType.CODE.getValue());
-		parameters.set(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId());
-		parameters.set(OAuth2ParameterNames.REDIRECT_URI, registeredClient.getRedirectUris().iterator().next());
-		parameters.set(OAuth2ParameterNames.SCOPE,
-				StringUtils.collectionToDelimitedString(registeredClient.getScopes(), " "));
-		parameters.set(OAuth2ParameterNames.STATE, "state");
-
-		MvcResult mvcResult = this.mockMvc.perform(get("/oauth2/authorize")
-				.params(parameters)
-				.with(user("user").roles("USER")))
-				.andExpect(status().isOk())
-				.andExpect(header().string("content-type", containsString(MediaType.TEXT_HTML_VALUE)))
-				.andReturn();
-		String responseHtml = mvcResult.getResponse().getContentAsString();
-		Matcher matcher = HIDDEN_STATE_INPUT_PATTERN.matcher(responseHtml);
-
-		return matcher.matches() ? matcher.group(1) : null;
-	}
-
-	private String performAuthorizationConsentRequest(RegisteredClient registeredClient, String state) throws Exception {
-		MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
-		parameters.set(OAuth2ParameterNames.CLIENT_ID, registeredClient.getClientId());
-		parameters.set(OAuth2ParameterNames.STATE, state);
-		parameters.add(OAuth2ParameterNames.SCOPE, "message.read");
-		parameters.add(OAuth2ParameterNames.SCOPE, "message.write");
-
-		MvcResult mvcResult = this.mockMvc.perform(post("/oauth2/authorize")
-				.params(parameters)
-				.with(user("user").roles("USER")))
-				.andExpect(status().is3xxRedirection())
-				.andReturn();
-		String redirectedUrl = mvcResult.getResponse().getRedirectedUrl();
-		assertThat(redirectedUrl).isNotNull();
-		assertThat(redirectedUrl).matches("http://127.0.0.1:8080/authorized\\?code=.{15,}&state=state");
-
-		String locationHeader = URLDecoder.decode(redirectedUrl, StandardCharsets.UTF_8.name());
-		UriComponents uriComponents = UriComponentsBuilder.fromUriString(locationHeader).build();
-
-		return uriComponents.getQueryParams().getFirst("code");
-	}
-
-	private Map<String, Object> performTokenRequest(RegisteredClient registeredClient, String authorizationCode) throws Exception {
-		MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
-		parameters.set(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.AUTHORIZATION_CODE.getValue());
-		parameters.set(OAuth2ParameterNames.CODE, authorizationCode);
-		parameters.set(OAuth2ParameterNames.REDIRECT_URI, registeredClient.getRedirectUris().iterator().next());
-
-		HttpHeaders basicAuth = new HttpHeaders();
-		basicAuth.setBasicAuth(registeredClient.getClientId(), "secret");
-
-		MvcResult mvcResult = this.mockMvc.perform(post("/oauth2/token")
-				.params(parameters)
-				.headers(basicAuth))
-				.andExpect(status().isOk())
-				.andExpect(header().string(HttpHeaders.CONTENT_TYPE, containsString(MediaType.APPLICATION_JSON_VALUE)))
-				.andExpect(jsonPath("$.access_token").isNotEmpty())
-				.andExpect(jsonPath("$.token_type").isNotEmpty())
-				.andExpect(jsonPath("$.expires_in").isNotEmpty())
-				.andExpect(jsonPath("$.refresh_token").isNotEmpty())
-				.andExpect(jsonPath("$.scope").isNotEmpty())
-				.andExpect(jsonPath("$.id_token").isNotEmpty())
-				.andReturn();
-
-		ObjectMapper objectMapper = new ObjectMapper();
-		String responseJson = mvcResult.getResponse().getContentAsString();
-		return objectMapper.readValue(responseJson, TOKEN_RESPONSE_TYPE_REFERENCE);
-	}
-
 	@EnableWebSecurity
 	@EnableAutoConfiguration
 	@ComponentScan