diff --git a/pom.xml b/pom.xml index bf38b3e..37dce0f 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.boot spring-boot-starter-parent - 3.5.11 + 4.0.6 @@ -19,7 +19,8 @@ 17 - 3.1.12 + 3.2.4 + 4.0.6 @@ -29,12 +30,12 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter-webmvc gg.jte - jte-spring-boot-starter-3 + jte-spring-boot-starter-4 ${jte.version} @@ -66,6 +67,11 @@ spring-boot-starter-tomcat provided + + org.springframework.boot + spring-boot-web-server + provided + @@ -73,6 +79,16 @@ spring-boot-starter-test test + + org.springframework.boot + spring-boot-starter-webmvc-test + test + + + org.springframework.boot + spring-boot-starter-jackson-test + test + org.springframework.boot spring-boot-testcontainers @@ -85,12 +101,12 @@ org.testcontainers - junit-jupiter + testcontainers-junit-jupiter test org.testcontainers - mariadb + testcontainers-mariadb test @@ -105,7 +121,7 @@ org.springframework.boot spring-boot-configuration-processor - 3.3.0 + ${spring-boot.version} @@ -171,6 +187,11 @@ org.springframework.boot spring-boot-starter-jdbc + + + org.springframework.boot + spring-boot-starter-flyway + org.flywaydb flyway-core diff --git a/src/main/java/se/su/dsv/oauth2/AuthorizationServer.java b/src/main/java/se/su/dsv/oauth2/AuthorizationServer.java index 0568506..2c9cb56 100644 --- a/src/main/java/se/su/dsv/oauth2/AuthorizationServer.java +++ b/src/main/java/se/su/dsv/oauth2/AuthorizationServer.java @@ -13,6 +13,7 @@ import org.springframework.security.config.Customizer; import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.oauth2.server.authorization.OAuth2AuthorizationServerConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -21,7 +22,6 @@ import org.springframework.security.crypto.password.DelegatingPasswordEncoder; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationProvider; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationConsentAuthenticationProvider; -import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer; import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings; import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext; import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer; @@ -95,7 +95,7 @@ public class AuthorizationServer extends SpringBootServletInitializer { throws Exception { OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = - OAuth2AuthorizationServerConfigurer.authorizationServer(); + new OAuth2AuthorizationServerConfigurer(); String tokenEndpoint = authorizationServerSettings.getTokenEndpoint(); RequestMatcher corsEnabledMatcher = new OrRequestMatcher( diff --git a/src/main/java/se/su/dsv/oauth2/dev/DevConfiguration.java b/src/main/java/se/su/dsv/oauth2/dev/DevConfiguration.java index 914d585..d36aec5 100644 --- a/src/main/java/se/su/dsv/oauth2/dev/DevConfiguration.java +++ b/src/main/java/se/su/dsv/oauth2/dev/DevConfiguration.java @@ -1,7 +1,7 @@ package se.su.dsv.oauth2.dev; import jakarta.servlet.http.HttpFilter; -import org.springframework.boot.autoconfigure.security.SecurityProperties; +import org.springframework.boot.security.autoconfigure.web.servlet.SecurityFilterProperties; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -12,9 +12,9 @@ import se.su.dsv.oauth2.Config; @Profile("dev") public class DevConfiguration { @Bean - public FilterRegistrationBean fakeSSO(SecurityProperties securityProperties, Config config) { + public FilterRegistrationBean fakeSSO(SecurityFilterProperties securityProperties, Config config) { var filter = new FilterRegistrationBean(new FakeSSOFilter(config.developerEntitlement())); - filter.setOrder(securityProperties.getFilter().getOrder() - 1); + filter.setOrder(securityProperties.getOrder() - 1); return filter; } } diff --git a/src/main/java/se/su/dsv/oauth2/shibboleth/ShibbolethAuthenticationDetailsSource.java b/src/main/java/se/su/dsv/oauth2/shibboleth/ShibbolethAuthenticationDetailsSource.java index ecae400..a55870e 100644 --- a/src/main/java/se/su/dsv/oauth2/shibboleth/ShibbolethAuthenticationDetailsSource.java +++ b/src/main/java/se/su/dsv/oauth2/shibboleth/ShibbolethAuthenticationDetailsSource.java @@ -3,6 +3,7 @@ package se.su.dsv.oauth2.shibboleth; import jakarta.servlet.http.HttpServletRequest; import org.springframework.security.authentication.AuthenticationDetailsSource; import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.FactorGrantedAuthority; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -46,6 +47,8 @@ public class ShibbolethAuthenticationDetailsSource implements authorities.add(entitlement); } } + // The authentication performed by Shibboleth is password based. + authorities.add(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY)); return authorities; } } diff --git a/src/main/java/se/su/dsv/oauth2/staging/CustomAuthorizationEndpointFilter.java b/src/main/java/se/su/dsv/oauth2/staging/CustomAuthorizationEndpointFilter.java index 2089b79..e1c6d0c 100644 --- a/src/main/java/se/su/dsv/oauth2/staging/CustomAuthorizationEndpointFilter.java +++ b/src/main/java/se/su/dsv/oauth2/staging/CustomAuthorizationEndpointFilter.java @@ -7,7 +7,6 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpFilter; import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletRequestWrapper; import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AuthenticationManager; @@ -34,10 +33,7 @@ import se.su.dsv.oauth2.shibboleth.ShibbolethAuthenticationDetails; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Collection; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -100,7 +96,8 @@ public class CustomAuthorizationEndpointFilter extends HttpFilter { authenticationConverter.convert(request); String authorizationUrl = getAuthorizationUrl(request); - JteModel view = templates.authorize(authorizationUrl, loggedInUser.getName(), (ShibbolethAuthenticationDetails) loggedInUser.getDetails()); + Map parameters = request.getParameterMap(); + JteModel view = templates.authorize(authorizationUrl, parameters, loggedInUser.getName(), (ShibbolethAuthenticationDetails) loggedInUser.getDetails()); respondWithTemplate(response, view); } else if (Objects.equals(request.getMethod(), "POST")) { handleIncomingCustomAuthorizationRequest(request, response, loggedInUser); @@ -119,14 +116,15 @@ public class CustomAuthorizationEndpointFilter extends HttpFilter { principal.setDetails(buildShibbolethDetails(request)); Authentication authenticatedPrincipal = authenticationManager.authenticate(principal); - Authentication normalCodeRequest = authenticationConverter.convert(withGetMethod(request)); + Authentication normalCodeRequest = authenticationConverter.convert(request); OAuth2AuthorizationCodeRequestAuthenticationToken codeRequestAuthenticationToken = (OAuth2AuthorizationCodeRequestAuthenticationToken) normalCodeRequest; Authentication codeRequest = overridePrincipal(authenticatedPrincipal, codeRequestAuthenticationToken); Authentication authenticatedCodeRequest = authenticationManager.authenticate(codeRequest); if (!authenticatedCodeRequest.isAuthenticated()) { String authorizationUrl = getAuthorizationUrl(request); - respondWithTemplate(response, templates.authorize(authorizationUrl, loggedInUser.getName(), (ShibbolethAuthenticationDetails) authenticatedPrincipal)); + Map parameters = request.getParameterMap(); + respondWithTemplate(response, templates.authorize(authorizationUrl, parameters, loggedInUser.getName(), (ShibbolethAuthenticationDetails) authenticatedPrincipal)); } else { if (authenticatedCodeRequest instanceof OAuth2AuthorizationCodeRequestAuthenticationToken authenticatedCodeRequestAuthenticationToken) { sendAuthorizationResponse(request, response, authenticatedCodeRequestAuthenticationToken); @@ -139,16 +137,7 @@ public class CustomAuthorizationEndpointFilter extends HttpFilter { } private static String getAuthorizationUrl(final HttpServletRequest request) { - return request.getRequestURL().append('?').append(request.getQueryString()).toString(); - } - - private HttpServletRequest withGetMethod(final HttpServletRequest request) { - return new HttpServletRequestWrapper(request) { - @Override - public String getMethod() { - return "GET"; - } - }; + return request.getRequestURL().toString(); } private Authentication overridePrincipal( diff --git a/src/main/resources/templates/authorize.jte b/src/main/resources/templates/authorize.jte index 3974f92..7081991 100644 --- a/src/main/resources/templates/authorize.jte +++ b/src/main/resources/templates/authorize.jte @@ -1,8 +1,10 @@ @import se.su.dsv.oauth2.shibboleth.Entitlement @import se.su.dsv.oauth2.shibboleth.ShibbolethAuthenticationDetails +@import java.util.Map @import java.util.stream.Collectors @param String authorizationUrl +@param Map parameters @param String principalName @param ShibbolethAuthenticationDetails shibbolethDetails @@ -15,6 +17,11 @@

+ @for (var entry : parameters.entrySet()) + @for (var value : entry.getValue()) + + @endfor + @endfor

Issue custom token

@@ -51,6 +58,11 @@

+ @for (var entry : parameters.entrySet()) + @for (var value : entry.getValue()) + + @endfor + @endfor

Continue as yourself

Principal
diff --git a/src/test/java/se/su/dsv/oauth2/AbstractMetadataCodeFlowTest.java b/src/test/java/se/su/dsv/oauth2/AbstractMetadataCodeFlowTest.java index 0da2d84..ec962cb 100644 --- a/src/test/java/se/su/dsv/oauth2/AbstractMetadataCodeFlowTest.java +++ b/src/test/java/se/su/dsv/oauth2/AbstractMetadataCodeFlowTest.java @@ -1,11 +1,11 @@ package se.su.dsv.oauth2; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; -import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.mariadb.MariaDBContainer; import java.util.function.Consumer; import java.util.regex.Matcher; @@ -24,25 +24,35 @@ import static se.su.dsv.oauth2.TestRegisteredClientConfiguration.REDIRECT_URI; public abstract class AbstractMetadataCodeFlowTest extends AbstractMetadataTest { @ServiceConnection - static MariaDBContainer mariaDBContainer = new MariaDBContainer<>("mariadb:10.11"); + static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11"); protected TokenResponse authorize(Consumer consumer) throws Exception { - return getTokenResponse(get(getAuthorizationEndpoint()), consumer); + return getTokenResponse(get(getAuthorizationEndpoint()), consumer, true); } protected TokenResponse authorizePost(Consumer consumer) throws Exception { - return getTokenResponse(post(getAuthorizationEndpoint()), consumer); + return getTokenResponse(post(getAuthorizationEndpoint()), consumer, false); } private TokenResponse getTokenResponse( final MockHttpServletRequestBuilder builder, - final Consumer customizer) + final Consumer customizer, + final boolean isGet) throws Exception { - MockHttpServletRequestBuilder requestBuilder = builder - .queryParam("response_type", "code") - .queryParam("client_id", CLIENT_ID) - .queryParam("redirect_uri", REDIRECT_URI); + MockHttpServletRequestBuilder requestBuilder; + if (isGet) { + requestBuilder = builder + .queryParam("response_type", "code") + .queryParam("client_id", CLIENT_ID) + .queryParam("redirect_uri", REDIRECT_URI); + } + else { + requestBuilder = builder + .formField("response_type", "code") + .formField("client_id", CLIENT_ID) + .formField("redirect_uri", REDIRECT_URI); + } customizer.accept(requestBuilder); MvcResult authorizationResult = mockMvc.perform(requestBuilder) diff --git a/src/test/java/se/su/dsv/oauth2/AbstractMetadataTest.java b/src/test/java/se/su/dsv/oauth2/AbstractMetadataTest.java index 998ffa7..05b98a4 100644 --- a/src/test/java/se/su/dsv/oauth2/AbstractMetadataTest.java +++ b/src/test/java/se/su/dsv/oauth2/AbstractMetadataTest.java @@ -1,7 +1,5 @@ package se.su.dsv.oauth2; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.jwk.source.JWKSource; import com.nimbusds.jose.jwk.source.JWKSourceBuilder; @@ -12,10 +10,12 @@ import com.nimbusds.jwt.proc.ConfigurableJWTProcessor; import com.nimbusds.jwt.proc.DefaultJWTProcessor; import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; +import tools.jackson.databind.JsonNode; +import tools.jackson.databind.json.JsonMapper; import java.net.URI; import java.net.URL; @@ -29,7 +29,7 @@ public class AbstractMetadataTest { @Autowired protected MockMvc mockMvc; @Autowired - protected ObjectMapper objectMapper; + protected JsonMapper objectMapper; private JsonNode metadata; private ConfigurableJWTProcessor processor; @@ -45,7 +45,7 @@ public class AbstractMetadataTest { metadata = objectMapper.readTree(responseBody); // 2. Get JWKS - URL jwksUri = URI.create(metadata.required("jwks_uri").asText()).toURL(); + URL jwksUri = URI.create(metadata.required("jwks_uri").asString()).toURL(); JWKSource jwkSource = JWKSourceBuilder .create(jwksUri, new MockMvcResourceRetriever(mockMvc)) .build(); @@ -58,19 +58,19 @@ public class AbstractMetadataTest { } protected String getAuthorizationEndpoint() { - return metadata.get("authorization_endpoint").asText(); + return metadata.get("authorization_endpoint").asString(); } protected String getTokenEndpoint() { - return metadata.get("token_endpoint").asText(); + return metadata.get("token_endpoint").asString(); } protected String getIntrospectionEndpoint() { - return metadata.get("introspection_endpoint").asText(); + return metadata.get("introspection_endpoint").asString(); } protected String getUserInfoEndpoint() { - return metadata.get("userinfo_endpoint").asText(); + return metadata.get("userinfo_endpoint").asString(); } protected JWTClaimsSet verifyToken(String token) throws Exception { diff --git a/src/test/java/se/su/dsv/oauth2/AuthorizationCodeFlowTest.java b/src/test/java/se/su/dsv/oauth2/AuthorizationCodeFlowTest.java index 3095d21..18490d4 100644 --- a/src/test/java/se/su/dsv/oauth2/AuthorizationCodeFlowTest.java +++ b/src/test/java/se/su/dsv/oauth2/AuthorizationCodeFlowTest.java @@ -1,15 +1,15 @@ package se.su.dsv.oauth2; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; -import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.mariadb.MariaDBContainer; +import tools.jackson.databind.JsonNode; +import tools.jackson.databind.json.JsonMapper; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -26,13 +26,13 @@ import static se.su.dsv.oauth2.TestRegisteredClientConfiguration.*; public class AuthorizationCodeFlowTest { @ServiceConnection - static MariaDBContainer mariaDBContainer = new MariaDBContainer<>("mariadb:10.11"); + static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11"); @Autowired MockMvc mockMvc; @Autowired - ObjectMapper objectMapper; + JsonMapper objectMapper; @Test public void authorize_code_exchange_introspect() throws Exception { @@ -72,7 +72,7 @@ public class AuthorizationCodeFlowTest { String content = codeExchangeResult.getResponse().getContentAsString(); JsonNode jsonNode = objectMapper.readTree(content); - String accessToken = jsonNode.get("access_token").asText(); + String accessToken = jsonNode.get("access_token").asString(); // 3. Introspect mockMvc.perform(post("/oauth2/introspect") diff --git a/src/test/java/se/su/dsv/oauth2/AuthorizationServerTest.java b/src/test/java/se/su/dsv/oauth2/AuthorizationServerTest.java index 597ea63..79f9cd4 100644 --- a/src/test/java/se/su/dsv/oauth2/AuthorizationServerTest.java +++ b/src/test/java/se/su/dsv/oauth2/AuthorizationServerTest.java @@ -3,7 +3,7 @@ package se.su.dsv.oauth2; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; -import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.mariadb.MariaDBContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -13,7 +13,7 @@ class AuthorizationServerTest { @Container @ServiceConnection - static MariaDBContainer mariaDBContainer = new MariaDBContainer<>("mariadb:10.11"); + static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11"); @Test void contextLoads() { diff --git a/src/test/java/se/su/dsv/oauth2/ConsentFlowCustomAuthorizationTest.java b/src/test/java/se/su/dsv/oauth2/ConsentFlowCustomAuthorizationTest.java index 4386a38..1b1a4a0 100644 --- a/src/test/java/se/su/dsv/oauth2/ConsentFlowCustomAuthorizationTest.java +++ b/src/test/java/se/su/dsv/oauth2/ConsentFlowCustomAuthorizationTest.java @@ -1,6 +1,5 @@ package se.su.dsv.oauth2; -import com.fasterxml.jackson.databind.JsonNode; import com.nimbusds.jwt.JWTClaimsSet; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @@ -9,7 +8,8 @@ import org.springframework.test.context.ActiveProfiles; import org.springframework.test.web.servlet.MvcResult; import org.springframework.util.MultiValueMap; import org.springframework.web.util.UriComponentsBuilder; -import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.mariadb.MariaDBContainer; +import tools.jackson.databind.JsonNode; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; @@ -32,7 +32,7 @@ public class ConsentFlowCustomAuthorizationTest extends AbstractMetadataTest { public static final String DEVELOPER_ENTITLEMENT = "developer"; @ServiceConnection - static MariaDBContainer mariaDBContainer = new MariaDBContainer<>("mariadb:10.11"); + static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11"); @Test public void consent_is_disabled_for_developers() throws Exception { @@ -42,8 +42,8 @@ public class ConsentFlowCustomAuthorizationTest extends AbstractMetadataTest { MvcResult authorizationResult = mockMvc.perform(post(getAuthorizationEndpoint()) .with(remoteUser(developerPrincipal) .entitlement(DEVELOPER_ENTITLEMENT)) - .queryParam("client_id", ConsentFlowTest.TestConfig.CLIENT_ID) - .queryParam("response_type", "code") + .formField("client_id", ConsentFlowTest.TestConfig.CLIENT_ID) + .formField("response_type", "code") .formField("principal", customPrincipal)) .andExpect(status().is3xxRedirection()) .andExpect(redirectedUrlPattern(ConsentFlowTest.TestConfig.REDIRECT_URI + "?*")) @@ -66,7 +66,7 @@ public class ConsentFlowCustomAuthorizationTest extends AbstractMetadataTest { .andReturn(); JsonNode tokenResponse = objectMapper.readTree(tokenResult.getResponse().getContentAsString()); - JWTClaimsSet claims = verifyToken(tokenResponse.required("access_token").asText()); + JWTClaimsSet claims = verifyToken(tokenResponse.required("access_token").asString()); assertEquals(customPrincipal, claims.getSubject()); } diff --git a/src/test/java/se/su/dsv/oauth2/ConsentFlowTest.java b/src/test/java/se/su/dsv/oauth2/ConsentFlowTest.java index 712f200..d799c8b 100644 --- a/src/test/java/se/su/dsv/oauth2/ConsentFlowTest.java +++ b/src/test/java/se/su/dsv/oauth2/ConsentFlowTest.java @@ -15,7 +15,7 @@ import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultActions; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; -import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.mariadb.MariaDBContainer; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; @@ -35,7 +35,7 @@ import static se.su.dsv.oauth2.ShibbolethRequestProcessor.remoteUser; public class ConsentFlowTest extends AbstractMetadataTest { @ServiceConnection - static MariaDBContainer mariaDBContainer = new MariaDBContainer<>("mariadb:10.11"); + static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11"); @Test public void asks_end_user_for_consent() throws Exception { @@ -195,6 +195,7 @@ public class ConsentFlowTest extends AbstractMetadataTest { .scope(OidcScopes.EMAIL) .clientSettings(ClientSettings.builder() .requireAuthorizationConsent(true) + .requireProofKey(false) .build()) .build(); diff --git a/src/test/java/se/su/dsv/oauth2/EmbeddedContainerTest.java b/src/test/java/se/su/dsv/oauth2/EmbeddedContainerTest.java index fb27112..6ec2c96 100644 --- a/src/test/java/se/su/dsv/oauth2/EmbeddedContainerTest.java +++ b/src/test/java/se/su/dsv/oauth2/EmbeddedContainerTest.java @@ -104,13 +104,13 @@ public class EmbeddedContainerTest { final MultiValueMap form = new LinkedMultiValueMap<>(); form.put("principal", List.of("test")); + form.put("response_type", List.of("code")); + form.put("client_id", List.of(CLIENT_ID)); + form.put("redirect_uri", List.of(CLIENT_REDIRECT_URI)); + form.put("scope", List.of("openid profile email")); String authorizationEndpoint = parsedMetadata.required("authorization_endpoint").asText(); String authorizeUri = UriComponentsBuilder.fromUriString(authorizationEndpoint) - .queryParam("response_type", "code") - .queryParam("client_id", CLIENT_ID) - .queryParam("redirect_uri", CLIENT_REDIRECT_URI) - .queryParam("scope", "openid profile email") .build() .toUriString(); diff --git a/src/test/java/se/su/dsv/oauth2/PublicClientCodeFlowTest.java b/src/test/java/se/su/dsv/oauth2/PublicClientCodeFlowTest.java index fa92270..852afcb 100644 --- a/src/test/java/se/su/dsv/oauth2/PublicClientCodeFlowTest.java +++ b/src/test/java/se/su/dsv/oauth2/PublicClientCodeFlowTest.java @@ -3,11 +3,11 @@ package se.su.dsv.oauth2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.test.web.servlet.MvcResult; -import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.mariadb.MariaDBContainer; import se.su.dsv.oauth2.admin.ClientData; import se.su.dsv.oauth2.admin.ClientManagementService; import se.su.dsv.oauth2.admin.NewClient; @@ -34,7 +34,7 @@ public class PublicClientCodeFlowTest extends AbstractMetadataCodeFlowTest { private static final String REDIRECT_URI = "http://localhost/public"; @ServiceConnection - static MariaDBContainer mariaDBContainer = new MariaDBContainer<>("mariadb:10.11"); + static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11"); @Autowired private ClientManagementService clientManagementService; diff --git a/src/test/java/se/su/dsv/oauth2/ResourceServerRegisteredClientTest.java b/src/test/java/se/su/dsv/oauth2/ResourceServerRegisteredClientTest.java index 76d6bd6..a4235d9 100644 --- a/src/test/java/se/su/dsv/oauth2/ResourceServerRegisteredClientTest.java +++ b/src/test/java/se/su/dsv/oauth2/ResourceServerRegisteredClientTest.java @@ -2,8 +2,8 @@ package se.su.dsv.oauth2; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.http.HttpHeaders; import org.springframework.test.web.servlet.MvcResult; import se.su.dsv.oauth2.admin.ClientData; diff --git a/src/test/java/se/su/dsv/oauth2/ShibbolethRequestProcessor.java b/src/test/java/se/su/dsv/oauth2/ShibbolethRequestProcessor.java index 78f88fc..5c3df50 100644 --- a/src/test/java/se/su/dsv/oauth2/ShibbolethRequestProcessor.java +++ b/src/test/java/se/su/dsv/oauth2/ShibbolethRequestProcessor.java @@ -1,7 +1,7 @@ package se.su.dsv.oauth2; import org.apache.catalina.realm.GenericPrincipal; -import org.springframework.lang.NonNull; +import org.jspecify.annotations.NonNull; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.test.web.servlet.request.RequestPostProcessor; diff --git a/src/test/java/se/su/dsv/oauth2/StagingProfileTest.java b/src/test/java/se/su/dsv/oauth2/StagingProfileTest.java index 6da5cf4..90b6f66 100644 --- a/src/test/java/se/su/dsv/oauth2/StagingProfileTest.java +++ b/src/test/java/se/su/dsv/oauth2/StagingProfileTest.java @@ -64,7 +64,7 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest { TokenResponse tokenResponse = authorizePost(request -> request .with(remoteUser(principal) .entitlement(DEVELOPER_ENTITLEMENT)) - .queryParam("scope", "openid profile") + .formField("scope", "openid profile") .formField("principal", principal) .formField("displayName", customDisplayName)); @@ -85,7 +85,7 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest { TokenResponse tokenResponse = authorizePost(request -> request .with(remoteUser(principal) .entitlement(DEVELOPER_ENTITLEMENT)) - .queryParam("scope", "openid email") + .formField("scope", "openid email") .formField("principal", principal) .formField("mail", customMail)); @@ -106,7 +106,7 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest { TokenResponse tokenResponse = authorizePost(request -> request .with(remoteUser(principal) .entitlement(DEVELOPER_ENTITLEMENT)) - .queryParam("scope", "openid profile") + .formField("scope", "openid profile") .formField("principal", principal) .formField("givenName", customGivenName)); @@ -127,7 +127,7 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest { TokenResponse tokenResponse = authorizePost(request -> request .with(remoteUser(principal) .entitlement(DEVELOPER_ENTITLEMENT)) - .queryParam("scope", "openid profile") + .formField("scope", "openid profile") .formField("principal", principal) .formField("sn", customFamilyName)); @@ -148,7 +148,7 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest { TokenResponse tokenResponse = authorizePost(request -> request .with(remoteUser(principal) .entitlement(DEVELOPER_ENTITLEMENT)) - .queryParam("scope", "openid profile") + .formField("scope", "openid profile") .formField("principal", principal) .formField("entitlements", customEntitlement)); @@ -168,8 +168,8 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest { mockMvc.perform(post(getAuthorizationEndpoint()) .with(remoteUser("developer") .entitlement(DEVELOPER_ENTITLEMENT)) - .queryParam("client_id", CLIENT_ID) - .queryParam("redirect_uri", REDIRECT_URI) + .formField("client_id", CLIENT_ID) + .formField("redirect_uri", REDIRECT_URI) .formField("principal", "developer")) .andExpect(status().isBadRequest()) .andExpect(status().reason(containsString("response_type"))); @@ -180,10 +180,10 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest { mockMvc.perform(post(getAuthorizationEndpoint()) .with(remoteUser("developer") .entitlement(DEVELOPER_ENTITLEMENT)) - .queryParam("response_type", "code") - .queryParam("client_id", CLIENT_ID) - .queryParam("redirect_uri", REDIRECT_URI) - .queryParam("scope", "invalid") + .formField("response_type", "code") + .formField("client_id", CLIENT_ID) + .formField("redirect_uri", REDIRECT_URI) + .formField("scope", "invalid") .formField("principal", "developer")) .andExpect(status().is3xxRedirection()) .andExpect(result -> { @@ -197,9 +197,9 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest { mockMvc.perform(post(getAuthorizationEndpoint()) .with(remoteUser("developer") .entitlement(DEVELOPER_ENTITLEMENT)) - .queryParam("response_type", "code") - .queryParam("client_id", "invalid-client-id") - .queryParam("redirect_uri", REDIRECT_URI) + .formField("response_type", "code") + .formField("client_id", "invalid-client-id") + .formField("redirect_uri", REDIRECT_URI) .formField("principal", "developer")) .andExpect(status().isBadRequest()) .andExpect(status().reason(containsString("client_id"))); @@ -212,11 +212,11 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest { mockMvc.perform(post(getAuthorizationEndpoint()) .with(remoteUser("developer") .entitlement(DEVELOPER_ENTITLEMENT)) - .queryParam("response_type", "code") - .queryParam("client_id", CLIENT_ID) - .queryParam("redirect_uri", REDIRECT_URI) - .queryParam("state", state) - .queryParam("scope", "invalid") + .formField("response_type", "code") + .formField("client_id", CLIENT_ID) + .formField("redirect_uri", REDIRECT_URI) + .formField("state", state) + .formField("scope", "invalid") .formField("principal", "developer")) .andExpect(status().is3xxRedirection()) .andExpect(result -> { diff --git a/src/test/java/se/su/dsv/oauth2/TestRegisteredClientConfiguration.java b/src/test/java/se/su/dsv/oauth2/TestRegisteredClientConfiguration.java index 38d2c6a..148a06f 100644 --- a/src/test/java/se/su/dsv/oauth2/TestRegisteredClientConfiguration.java +++ b/src/test/java/se/su/dsv/oauth2/TestRegisteredClientConfiguration.java @@ -8,6 +8,7 @@ import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.oidc.OidcScopes; import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; +import org.springframework.security.oauth2.server.authorization.settings.ClientSettings; @TestConfiguration public class TestRegisteredClientConfiguration { @@ -21,6 +22,9 @@ public class TestRegisteredClientConfiguration { InMemoryRegisteredClientRepository testRegisteredClientRepository() { RegisteredClient registeredClient = RegisteredClient.withId("id") .clientId(CLIENT_ID) + .clientSettings(ClientSettings.builder() + .requireProofKey(false) + .build()) .clientSecret("{noop}" + CLIENT_SECRET) .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .redirectUri(REDIRECT_URI) diff --git a/src/test/java/se/su/dsv/oauth2/UserInfoEndpointTest.java b/src/test/java/se/su/dsv/oauth2/UserInfoEndpointTest.java index bc2a672..6d87325 100644 --- a/src/test/java/se/su/dsv/oauth2/UserInfoEndpointTest.java +++ b/src/test/java/se/su/dsv/oauth2/UserInfoEndpointTest.java @@ -1,10 +1,10 @@ package se.su.dsv.oauth2; -import com.fasterxml.jackson.databind.JsonNode; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.security.oauth2.core.oidc.OidcScopes; import org.springframework.test.web.servlet.MvcResult; +import tools.jackson.databind.JsonNode; import java.net.URI; @@ -26,7 +26,7 @@ public class UserInfoEndpointTest extends AbstractMetadataCodeFlowTest { JsonNode openidConfiguration = objectMapper.readTree(mvcResult.getResponse().getContentAsString()); - String userinfoEndpoint = openidConfiguration.required("userinfo_endpoint").asText(); + String userinfoEndpoint = openidConfiguration.required("userinfo_endpoint").asString(); URI userInfoUri = URI.create(userinfoEndpoint); assertEquals("/oidc/userinfo", userInfoUri.getPath()); diff --git a/src/test/java/se/su/dsv/oauth2/web/AdminControllerTest.java b/src/test/java/se/su/dsv/oauth2/web/AdminControllerTest.java index ddc9337..552f984 100644 --- a/src/test/java/se/su/dsv/oauth2/web/AdminControllerTest.java +++ b/src/test/java/se/su/dsv/oauth2/web/AdminControllerTest.java @@ -2,11 +2,11 @@ package se.su.dsv.oauth2.web; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.test.web.servlet.MockMvc; -import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.mariadb.MariaDBContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -20,7 +20,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. class AdminControllerTest { @Container @ServiceConnection - static MariaDBContainer mariaDBContainer = new MariaDBContainer<>("mariadb:10.11"); + static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11"); @Autowired MockMvc mockMvc; @@ -28,7 +28,7 @@ class AdminControllerTest { @Test void is_protected() throws Exception { mockMvc.perform(get("/admin")) - .andExpect(redirectedUrl("http://localhost/login")); + .andExpect(redirectedUrl("/login")); } @Test diff --git a/src/test/java/se/su/dsv/oauth2/web/client/ClientAdminControllerTest.java b/src/test/java/se/su/dsv/oauth2/web/client/ClientAdminControllerTest.java index 3ab26bd..ddf5526 100644 --- a/src/test/java/se/su/dsv/oauth2/web/client/ClientAdminControllerTest.java +++ b/src/test/java/se/su/dsv/oauth2/web/client/ClientAdminControllerTest.java @@ -2,14 +2,14 @@ package se.su.dsv.oauth2.web.client; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; import org.springframework.test.annotation.Rollback; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.transaction.annotation.Transactional; -import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.mariadb.MariaDBContainer; import se.su.dsv.oauth2.admin.Client; import se.su.dsv.oauth2.admin.ClientManagementService; @@ -35,7 +35,7 @@ public class ClientAdminControllerTest { public static final String DEVELOPER_ENTITLEMENT = "developer"; @ServiceConnection - static MariaDBContainer mariaDBContainer = new MariaDBContainer<>("mariadb:10.11"); + static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11"); @Autowired MockMvc mockMvc;