Upgrade to Spring Boot 4.0 #18
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.5.11</version>
|
||||
<version>4.0.6</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<jte.version>3.1.12</jte.version>
|
||||
<jte.version>3.2.4</jte.version>
|
||||
<spring-boot.version>4.0.6</spring-boot.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -29,12 +30,12 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<artifactId>spring-boot-starter-webmvc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>gg.jte</groupId>
|
||||
<artifactId>jte-spring-boot-starter-3</artifactId>
|
||||
<artifactId>jte-spring-boot-starter-4</artifactId>
|
||||
<version>${jte.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -66,6 +67,11 @@
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-web-server</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Testing -->
|
||||
<dependency>
|
||||
@@ -73,6 +79,16 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webmvc-test</artifactId>
|
||||
|
stne3960 marked this conversation as resolved
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jackson-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-testcontainers</artifactId>
|
||||
@@ -85,12 +101,12 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<artifactId>testcontainers-junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>mariadb</artifactId>
|
||||
<artifactId>testcontainers-mariadb</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -105,7 +121,7 @@
|
||||
<path>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>${spring-boot.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
@@ -171,6 +187,11 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-flyway</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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<HttpFilter> fakeSSO(SecurityProperties securityProperties, Config config) {
|
||||
public FilterRegistrationBean<HttpFilter> fakeSSO(SecurityFilterProperties securityProperties, Config config) {
|
||||
var filter = new FilterRegistrationBean<HttpFilter>(new FakeSSOFilter(config.developerEntitlement()));
|
||||
filter.setOrder(securityProperties.getFilter().getOrder() - 1);
|
||||
filter.setOrder(securityProperties.getOrder() - 1);
|
||||
return filter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String, String[]> 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<String, String[]> 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(
|
||||
|
||||
@@ -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<String, String[]> parameters
|
||||
@param String principalName
|
||||
@param ShibbolethAuthenticationDetails shibbolethDetails
|
||||
|
||||
@@ -15,6 +17,11 @@
|
||||
</p>
|
||||
<div class="d-flex justify-content-between flex-md-row flex-column mb-3">
|
||||
<form action="${authorizationUrl}" method="post" class="flex-grow-1">
|
||||
@for (var entry : parameters.entrySet())
|
||||
@for (var value : entry.getValue())
|
||||
<input type="hidden" name="${entry.getKey()}" value="${value}">
|
||||
@endfor
|
||||
@endfor
|
||||
<h2>Issue custom token</h2>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="principal">Principal</label>
|
||||
@@ -51,6 +58,11 @@
|
||||
<div class="vr mx-3 d-none d-md-block"></div>
|
||||
<hr class="d-md-none">
|
||||
<form action="${authorizationUrl}" method="post" class="flex-grow-1">
|
||||
@for (var entry : parameters.entrySet())
|
||||
@for (var value : entry.getValue())
|
||||
<input type="hidden" name="${entry.getKey()}" value="${value}">
|
||||
@endfor
|
||||
@endfor
|
||||
<h2>Continue as yourself</h2>
|
||||
<dl>
|
||||
<dt>Principal</dt>
|
||||
|
||||
@@ -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<MockHttpServletRequestBuilder> consumer) throws Exception {
|
||||
return getTokenResponse(get(getAuthorizationEndpoint()), consumer);
|
||||
return getTokenResponse(get(getAuthorizationEndpoint()), consumer, true);
|
||||
}
|
||||
|
||||
protected TokenResponse authorizePost(Consumer<MockHttpServletRequestBuilder> consumer) throws Exception {
|
||||
return getTokenResponse(post(getAuthorizationEndpoint()), consumer);
|
||||
return getTokenResponse(post(getAuthorizationEndpoint()), consumer, false);
|
||||
}
|
||||
|
||||
private TokenResponse getTokenResponse(
|
||||
final MockHttpServletRequestBuilder builder,
|
||||
final Consumer<MockHttpServletRequestBuilder> customizer)
|
||||
final Consumer<MockHttpServletRequestBuilder> 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)
|
||||
|
||||
@@ -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<SecurityContext> 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<SecurityContext> 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 {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -104,13 +104,13 @@ public class EmbeddedContainerTest {
|
||||
|
||||
final MultiValueMap<String, Object> 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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 -> {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user
Shouldn't this be
<scope>test</scope>?