Upgrade to Spring Boot 4.0 #18
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
<version>3.5.11</version>
|
<version>4.0.6</version>
|
||||||
<relativePath/> <!-- lookup parent from repository -->
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -19,7 +19,8 @@
|
|||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>17</java.version>
|
<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>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -29,12 +30,12 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-webmvc</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>gg.jte</groupId>
|
<groupId>gg.jte</groupId>
|
||||||
<artifactId>jte-spring-boot-starter-3</artifactId>
|
<artifactId>jte-spring-boot-starter-4</artifactId>
|
||||||
<version>${jte.version}</version>
|
<version>${jte.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -66,6 +67,11 @@
|
|||||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-web-server</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Testing -->
|
<!-- Testing -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -73,6 +79,15 @@
|
|||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-webmvc-test</artifactId>
|
||||||
|
stne3960 marked this conversation as resolved
|
|||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-jackson-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-testcontainers</artifactId>
|
<artifactId>spring-boot-testcontainers</artifactId>
|
||||||
@@ -85,12 +100,12 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.testcontainers</groupId>
|
<groupId>org.testcontainers</groupId>
|
||||||
<artifactId>junit-jupiter</artifactId>
|
<artifactId>testcontainers-junit-jupiter</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.testcontainers</groupId>
|
<groupId>org.testcontainers</groupId>
|
||||||
<artifactId>mariadb</artifactId>
|
<artifactId>testcontainers-mariadb</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -105,7 +120,7 @@
|
|||||||
<path>
|
<path>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
<version>3.3.0</version>
|
<version>${spring-boot.version}</version>
|
||||||
</path>
|
</path>
|
||||||
</annotationProcessorPaths>
|
</annotationProcessorPaths>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -171,6 +186,11 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-flyway</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.flywaydb</groupId>
|
<groupId>org.flywaydb</groupId>
|
||||||
<artifactId>flyway-core</artifactId>
|
<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.ObjectPostProcessor;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
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.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.config.http.SessionCreationPolicy;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
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.crypto.password.NoOpPasswordEncoder;
|
||||||
import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationProvider;
|
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.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.settings.AuthorizationServerSettings;
|
||||||
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
|
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
|
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
|
||||||
@@ -95,7 +95,7 @@ public class AuthorizationServer extends SpringBootServletInitializer {
|
|||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
|
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
|
||||||
OAuth2AuthorizationServerConfigurer.authorizationServer();
|
new OAuth2AuthorizationServerConfigurer();
|
||||||
|
|
||||||
String tokenEndpoint = authorizationServerSettings.getTokenEndpoint();
|
String tokenEndpoint = authorizationServerSettings.getTokenEndpoint();
|
||||||
RequestMatcher corsEnabledMatcher = new OrRequestMatcher(
|
RequestMatcher corsEnabledMatcher = new OrRequestMatcher(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package se.su.dsv.oauth2.dev;
|
package se.su.dsv.oauth2.dev;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpFilter;
|
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.boot.web.servlet.FilterRegistrationBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@@ -12,9 +12,9 @@ import se.su.dsv.oauth2.Config;
|
|||||||
@Profile("dev")
|
@Profile("dev")
|
||||||
public class DevConfiguration {
|
public class DevConfiguration {
|
||||||
@Bean
|
@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()));
|
var filter = new FilterRegistrationBean<HttpFilter>(new FakeSSOFilter(config.developerEntitlement()));
|
||||||
filter.setOrder(securityProperties.getFilter().getOrder() - 1);
|
filter.setOrder(securityProperties.getOrder() - 1);
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package se.su.dsv.oauth2.shibboleth;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
import org.springframework.security.authentication.AuthenticationDetailsSource;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
import org.springframework.security.core.authority.FactorGrantedAuthority;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -46,6 +47,8 @@ public class ShibbolethAuthenticationDetailsSource implements
|
|||||||
authorities.add(entitlement);
|
authorities.add(entitlement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// The authentication performed by Shibboleth is password based.
|
||||||
|
authorities.add(FactorGrantedAuthority.fromAuthority(FactorGrantedAuthority.PASSWORD_AUTHORITY));
|
||||||
return authorities;
|
return authorities;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import jakarta.servlet.FilterChain;
|
|||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpFilter;
|
import jakarta.servlet.http.HttpFilter;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletRequestWrapper;
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
@@ -34,10 +33,7 @@ import se.su.dsv.oauth2.shibboleth.ShibbolethAuthenticationDetails;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -100,7 +96,8 @@ public class CustomAuthorizationEndpointFilter extends HttpFilter {
|
|||||||
authenticationConverter.convert(request);
|
authenticationConverter.convert(request);
|
||||||
|
|
||||||
String authorizationUrl = getAuthorizationUrl(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);
|
respondWithTemplate(response, view);
|
||||||
} else if (Objects.equals(request.getMethod(), "POST")) {
|
} else if (Objects.equals(request.getMethod(), "POST")) {
|
||||||
handleIncomingCustomAuthorizationRequest(request, response, loggedInUser);
|
handleIncomingCustomAuthorizationRequest(request, response, loggedInUser);
|
||||||
@@ -119,14 +116,15 @@ public class CustomAuthorizationEndpointFilter extends HttpFilter {
|
|||||||
principal.setDetails(buildShibbolethDetails(request));
|
principal.setDetails(buildShibbolethDetails(request));
|
||||||
Authentication authenticatedPrincipal = authenticationManager.authenticate(principal);
|
Authentication authenticatedPrincipal = authenticationManager.authenticate(principal);
|
||||||
|
|
||||||
Authentication normalCodeRequest = authenticationConverter.convert(withGetMethod(request));
|
Authentication normalCodeRequest = authenticationConverter.convert(request);
|
||||||
OAuth2AuthorizationCodeRequestAuthenticationToken codeRequestAuthenticationToken = (OAuth2AuthorizationCodeRequestAuthenticationToken) normalCodeRequest;
|
OAuth2AuthorizationCodeRequestAuthenticationToken codeRequestAuthenticationToken = (OAuth2AuthorizationCodeRequestAuthenticationToken) normalCodeRequest;
|
||||||
Authentication codeRequest = overridePrincipal(authenticatedPrincipal, codeRequestAuthenticationToken);
|
Authentication codeRequest = overridePrincipal(authenticatedPrincipal, codeRequestAuthenticationToken);
|
||||||
Authentication authenticatedCodeRequest = authenticationManager.authenticate(codeRequest);
|
Authentication authenticatedCodeRequest = authenticationManager.authenticate(codeRequest);
|
||||||
|
|
||||||
if (!authenticatedCodeRequest.isAuthenticated()) {
|
if (!authenticatedCodeRequest.isAuthenticated()) {
|
||||||
String authorizationUrl = getAuthorizationUrl(request);
|
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 {
|
} else {
|
||||||
if (authenticatedCodeRequest instanceof OAuth2AuthorizationCodeRequestAuthenticationToken authenticatedCodeRequestAuthenticationToken) {
|
if (authenticatedCodeRequest instanceof OAuth2AuthorizationCodeRequestAuthenticationToken authenticatedCodeRequestAuthenticationToken) {
|
||||||
sendAuthorizationResponse(request, response, authenticatedCodeRequestAuthenticationToken);
|
sendAuthorizationResponse(request, response, authenticatedCodeRequestAuthenticationToken);
|
||||||
@@ -139,16 +137,7 @@ public class CustomAuthorizationEndpointFilter extends HttpFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static String getAuthorizationUrl(final HttpServletRequest request) {
|
private static String getAuthorizationUrl(final HttpServletRequest request) {
|
||||||
return request.getRequestURL().append('?').append(request.getQueryString()).toString();
|
return request.getRequestURL().toString();
|
||||||
}
|
|
||||||
|
|
||||||
private HttpServletRequest withGetMethod(final HttpServletRequest request) {
|
|
||||||
return new HttpServletRequestWrapper(request) {
|
|
||||||
@Override
|
|
||||||
public String getMethod() {
|
|
||||||
return "GET";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Authentication overridePrincipal(
|
private Authentication overridePrincipal(
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
@import se.su.dsv.oauth2.shibboleth.Entitlement
|
@import se.su.dsv.oauth2.shibboleth.Entitlement
|
||||||
@import se.su.dsv.oauth2.shibboleth.ShibbolethAuthenticationDetails
|
@import se.su.dsv.oauth2.shibboleth.ShibbolethAuthenticationDetails
|
||||||
|
@import java.util.Map
|
||||||
@import java.util.stream.Collectors
|
@import java.util.stream.Collectors
|
||||||
|
|
||||||
@param String authorizationUrl
|
@param String authorizationUrl
|
||||||
|
@param Map<String, String[]> parameters
|
||||||
@param String principalName
|
@param String principalName
|
||||||
@param ShibbolethAuthenticationDetails shibbolethDetails
|
@param ShibbolethAuthenticationDetails shibbolethDetails
|
||||||
|
|
||||||
@@ -15,6 +17,11 @@
|
|||||||
</p>
|
</p>
|
||||||
<div class="d-flex justify-content-between flex-md-row flex-column mb-3">
|
<div class="d-flex justify-content-between flex-md-row flex-column mb-3">
|
||||||
<form action="${authorizationUrl}" method="post" class="flex-grow-1">
|
<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>
|
<h2>Issue custom token</h2>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label class="form-label" for="principal">Principal</label>
|
<label class="form-label" for="principal">Principal</label>
|
||||||
@@ -51,6 +58,11 @@
|
|||||||
<div class="vr mx-3 d-none d-md-block"></div>
|
<div class="vr mx-3 d-none d-md-block"></div>
|
||||||
<hr class="d-md-none">
|
<hr class="d-md-none">
|
||||||
<form action="${authorizationUrl}" method="post" class="flex-grow-1">
|
<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>
|
<h2>Continue as yourself</h2>
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Principal</dt>
|
<dt>Principal</dt>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package se.su.dsv.oauth2;
|
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.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
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.MvcResult;
|
||||||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
|
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.function.Consumer;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
@@ -24,25 +24,35 @@ import static se.su.dsv.oauth2.TestRegisteredClientConfiguration.REDIRECT_URI;
|
|||||||
public abstract class AbstractMetadataCodeFlowTest extends AbstractMetadataTest {
|
public abstract class AbstractMetadataCodeFlowTest extends AbstractMetadataTest {
|
||||||
|
|
||||||
@ServiceConnection
|
@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 {
|
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 {
|
protected TokenResponse authorizePost(Consumer<MockHttpServletRequestBuilder> consumer) throws Exception {
|
||||||
return getTokenResponse(post(getAuthorizationEndpoint()), consumer);
|
return getTokenResponse(post(getAuthorizationEndpoint()), consumer, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TokenResponse getTokenResponse(
|
private TokenResponse getTokenResponse(
|
||||||
final MockHttpServletRequestBuilder builder,
|
final MockHttpServletRequestBuilder builder,
|
||||||
final Consumer<MockHttpServletRequestBuilder> customizer)
|
final Consumer<MockHttpServletRequestBuilder> customizer,
|
||||||
|
final boolean isGet)
|
||||||
throws Exception
|
throws Exception
|
||||||
{
|
{
|
||||||
MockHttpServletRequestBuilder requestBuilder = builder
|
MockHttpServletRequestBuilder requestBuilder;
|
||||||
.queryParam("response_type", "code")
|
if (isGet) {
|
||||||
.queryParam("client_id", CLIENT_ID)
|
requestBuilder = builder
|
||||||
.queryParam("redirect_uri", REDIRECT_URI);
|
.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);
|
customizer.accept(requestBuilder);
|
||||||
|
|
||||||
MvcResult authorizationResult = mockMvc.perform(requestBuilder)
|
MvcResult authorizationResult = mockMvc.perform(requestBuilder)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package se.su.dsv.oauth2;
|
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.JWSAlgorithm;
|
||||||
import com.nimbusds.jose.jwk.source.JWKSource;
|
import com.nimbusds.jose.jwk.source.JWKSource;
|
||||||
import com.nimbusds.jose.jwk.source.JWKSourceBuilder;
|
import com.nimbusds.jose.jwk.source.JWKSourceBuilder;
|
||||||
@@ -12,10 +10,12 @@ import com.nimbusds.jwt.proc.ConfigurableJWTProcessor;
|
|||||||
import com.nimbusds.jwt.proc.DefaultJWTProcessor;
|
import com.nimbusds.jwt.proc.DefaultJWTProcessor;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
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.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@@ -29,7 +29,7 @@ public class AbstractMetadataTest {
|
|||||||
@Autowired
|
@Autowired
|
||||||
protected MockMvc mockMvc;
|
protected MockMvc mockMvc;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected ObjectMapper objectMapper;
|
protected JsonMapper objectMapper;
|
||||||
|
|
||||||
private JsonNode metadata;
|
private JsonNode metadata;
|
||||||
private ConfigurableJWTProcessor<SecurityContext> processor;
|
private ConfigurableJWTProcessor<SecurityContext> processor;
|
||||||
@@ -45,7 +45,7 @@ public class AbstractMetadataTest {
|
|||||||
metadata = objectMapper.readTree(responseBody);
|
metadata = objectMapper.readTree(responseBody);
|
||||||
|
|
||||||
// 2. Get JWKS
|
// 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
|
JWKSource<SecurityContext> jwkSource = JWKSourceBuilder
|
||||||
.create(jwksUri, new MockMvcResourceRetriever(mockMvc))
|
.create(jwksUri, new MockMvcResourceRetriever(mockMvc))
|
||||||
.build();
|
.build();
|
||||||
@@ -58,19 +58,19 @@ public class AbstractMetadataTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String getAuthorizationEndpoint() {
|
protected String getAuthorizationEndpoint() {
|
||||||
return metadata.get("authorization_endpoint").asText();
|
return metadata.get("authorization_endpoint").asString();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getTokenEndpoint() {
|
protected String getTokenEndpoint() {
|
||||||
return metadata.get("token_endpoint").asText();
|
return metadata.get("token_endpoint").asString();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getIntrospectionEndpoint() {
|
protected String getIntrospectionEndpoint() {
|
||||||
return metadata.get("introspection_endpoint").asText();
|
return metadata.get("introspection_endpoint").asString();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getUserInfoEndpoint() {
|
protected String getUserInfoEndpoint() {
|
||||||
return metadata.get("userinfo_endpoint").asText();
|
return metadata.get("userinfo_endpoint").asString();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JWTClaimsSet verifyToken(String token) throws Exception {
|
protected JWTClaimsSet verifyToken(String token) throws Exception {
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
package se.su.dsv.oauth2;
|
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.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
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.MockMvc;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
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.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@@ -26,13 +26,13 @@ import static se.su.dsv.oauth2.TestRegisteredClientConfiguration.*;
|
|||||||
public class AuthorizationCodeFlowTest {
|
public class AuthorizationCodeFlowTest {
|
||||||
|
|
||||||
@ServiceConnection
|
@ServiceConnection
|
||||||
static MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("mariadb:10.11");
|
static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11");
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
MockMvc mockMvc;
|
MockMvc mockMvc;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
ObjectMapper objectMapper;
|
JsonMapper objectMapper;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void authorize_code_exchange_introspect() throws Exception {
|
public void authorize_code_exchange_introspect() throws Exception {
|
||||||
@@ -72,7 +72,7 @@ public class AuthorizationCodeFlowTest {
|
|||||||
|
|
||||||
String content = codeExchangeResult.getResponse().getContentAsString();
|
String content = codeExchangeResult.getResponse().getContentAsString();
|
||||||
JsonNode jsonNode = objectMapper.readTree(content);
|
JsonNode jsonNode = objectMapper.readTree(content);
|
||||||
String accessToken = jsonNode.get("access_token").asText();
|
String accessToken = jsonNode.get("access_token").asString();
|
||||||
|
|
||||||
// 3. Introspect
|
// 3. Introspect
|
||||||
mockMvc.perform(post("/oauth2/introspect")
|
mockMvc.perform(post("/oauth2/introspect")
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package se.su.dsv.oauth2;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
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.Container;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ class AuthorizationServerTest {
|
|||||||
|
|
||||||
@Container
|
@Container
|
||||||
@ServiceConnection
|
@ServiceConnection
|
||||||
static MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("mariadb:10.11");
|
static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void contextLoads() {
|
void contextLoads() {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package se.su.dsv.oauth2;
|
package se.su.dsv.oauth2;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.nimbusds.jwt.JWTClaimsSet;
|
import com.nimbusds.jwt.JWTClaimsSet;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
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.test.web.servlet.MvcResult;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
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.net.URLDecoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -32,7 +32,7 @@ public class ConsentFlowCustomAuthorizationTest extends AbstractMetadataTest {
|
|||||||
public static final String DEVELOPER_ENTITLEMENT = "developer";
|
public static final String DEVELOPER_ENTITLEMENT = "developer";
|
||||||
|
|
||||||
@ServiceConnection
|
@ServiceConnection
|
||||||
static MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("mariadb:10.11");
|
static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void consent_is_disabled_for_developers() throws Exception {
|
public void consent_is_disabled_for_developers() throws Exception {
|
||||||
@@ -42,8 +42,8 @@ public class ConsentFlowCustomAuthorizationTest extends AbstractMetadataTest {
|
|||||||
MvcResult authorizationResult = mockMvc.perform(post(getAuthorizationEndpoint())
|
MvcResult authorizationResult = mockMvc.perform(post(getAuthorizationEndpoint())
|
||||||
.with(remoteUser(developerPrincipal)
|
.with(remoteUser(developerPrincipal)
|
||||||
.entitlement(DEVELOPER_ENTITLEMENT))
|
.entitlement(DEVELOPER_ENTITLEMENT))
|
||||||
.queryParam("client_id", ConsentFlowTest.TestConfig.CLIENT_ID)
|
.formField("client_id", ConsentFlowTest.TestConfig.CLIENT_ID)
|
||||||
.queryParam("response_type", "code")
|
.formField("response_type", "code")
|
||||||
.formField("principal", customPrincipal))
|
.formField("principal", customPrincipal))
|
||||||
.andExpect(status().is3xxRedirection())
|
.andExpect(status().is3xxRedirection())
|
||||||
.andExpect(redirectedUrlPattern(ConsentFlowTest.TestConfig.REDIRECT_URI + "?*"))
|
.andExpect(redirectedUrlPattern(ConsentFlowTest.TestConfig.REDIRECT_URI + "?*"))
|
||||||
@@ -66,7 +66,7 @@ public class ConsentFlowCustomAuthorizationTest extends AbstractMetadataTest {
|
|||||||
.andReturn();
|
.andReturn();
|
||||||
|
|
||||||
JsonNode tokenResponse = objectMapper.readTree(tokenResult.getResponse().getContentAsString());
|
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());
|
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.test.web.servlet.ResultActions;
|
||||||
import org.springframework.web.util.UriComponents;
|
import org.springframework.web.util.UriComponents;
|
||||||
import org.springframework.web.util.UriComponentsBuilder;
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
import org.testcontainers.containers.MariaDBContainer;
|
import org.testcontainers.mariadb.MariaDBContainer;
|
||||||
|
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
@@ -35,7 +35,7 @@ import static se.su.dsv.oauth2.ShibbolethRequestProcessor.remoteUser;
|
|||||||
public class ConsentFlowTest extends AbstractMetadataTest {
|
public class ConsentFlowTest extends AbstractMetadataTest {
|
||||||
|
|
||||||
@ServiceConnection
|
@ServiceConnection
|
||||||
static MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("mariadb:10.11");
|
static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void asks_end_user_for_consent() throws Exception {
|
public void asks_end_user_for_consent() throws Exception {
|
||||||
@@ -195,6 +195,7 @@ public class ConsentFlowTest extends AbstractMetadataTest {
|
|||||||
.scope(OidcScopes.EMAIL)
|
.scope(OidcScopes.EMAIL)
|
||||||
.clientSettings(ClientSettings.builder()
|
.clientSettings(ClientSettings.builder()
|
||||||
.requireAuthorizationConsent(true)
|
.requireAuthorizationConsent(true)
|
||||||
|
.requireProofKey(false)
|
||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|||||||
@@ -104,13 +104,13 @@ public class EmbeddedContainerTest {
|
|||||||
|
|
||||||
final MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
|
final MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
|
||||||
form.put("principal", List.of("test"));
|
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 authorizationEndpoint = parsedMetadata.required("authorization_endpoint").asText();
|
||||||
String authorizeUri = UriComponentsBuilder.fromUriString(authorizationEndpoint)
|
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()
|
.build()
|
||||||
.toUriString();
|
.toUriString();
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package se.su.dsv.oauth2;
|
|||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
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.MvcResult;
|
||||||
import org.testcontainers.containers.MariaDBContainer;
|
import org.testcontainers.mariadb.MariaDBContainer;
|
||||||
import se.su.dsv.oauth2.admin.ClientData;
|
import se.su.dsv.oauth2.admin.ClientData;
|
||||||
import se.su.dsv.oauth2.admin.ClientManagementService;
|
import se.su.dsv.oauth2.admin.ClientManagementService;
|
||||||
import se.su.dsv.oauth2.admin.NewClient;
|
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";
|
private static final String REDIRECT_URI = "http://localhost/public";
|
||||||
|
|
||||||
@ServiceConnection
|
@ServiceConnection
|
||||||
static MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("mariadb:10.11");
|
static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11");
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ClientManagementService clientManagementService;
|
private ClientManagementService clientManagementService;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package se.su.dsv.oauth2;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
import se.su.dsv.oauth2.admin.ClientData;
|
import se.su.dsv.oauth2.admin.ClientData;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package se.su.dsv.oauth2;
|
package se.su.dsv.oauth2;
|
||||||
|
|
||||||
import org.apache.catalina.realm.GenericPrincipal;
|
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.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest {
|
|||||||
TokenResponse tokenResponse = authorizePost(request -> request
|
TokenResponse tokenResponse = authorizePost(request -> request
|
||||||
.with(remoteUser(principal)
|
.with(remoteUser(principal)
|
||||||
.entitlement(DEVELOPER_ENTITLEMENT))
|
.entitlement(DEVELOPER_ENTITLEMENT))
|
||||||
.queryParam("scope", "openid profile")
|
.formField("scope", "openid profile")
|
||||||
.formField("principal", principal)
|
.formField("principal", principal)
|
||||||
.formField("displayName", customDisplayName));
|
.formField("displayName", customDisplayName));
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest {
|
|||||||
TokenResponse tokenResponse = authorizePost(request -> request
|
TokenResponse tokenResponse = authorizePost(request -> request
|
||||||
.with(remoteUser(principal)
|
.with(remoteUser(principal)
|
||||||
.entitlement(DEVELOPER_ENTITLEMENT))
|
.entitlement(DEVELOPER_ENTITLEMENT))
|
||||||
.queryParam("scope", "openid email")
|
.formField("scope", "openid email")
|
||||||
.formField("principal", principal)
|
.formField("principal", principal)
|
||||||
.formField("mail", customMail));
|
.formField("mail", customMail));
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest {
|
|||||||
TokenResponse tokenResponse = authorizePost(request -> request
|
TokenResponse tokenResponse = authorizePost(request -> request
|
||||||
.with(remoteUser(principal)
|
.with(remoteUser(principal)
|
||||||
.entitlement(DEVELOPER_ENTITLEMENT))
|
.entitlement(DEVELOPER_ENTITLEMENT))
|
||||||
.queryParam("scope", "openid profile")
|
.formField("scope", "openid profile")
|
||||||
.formField("principal", principal)
|
.formField("principal", principal)
|
||||||
.formField("givenName", customGivenName));
|
.formField("givenName", customGivenName));
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest {
|
|||||||
TokenResponse tokenResponse = authorizePost(request -> request
|
TokenResponse tokenResponse = authorizePost(request -> request
|
||||||
.with(remoteUser(principal)
|
.with(remoteUser(principal)
|
||||||
.entitlement(DEVELOPER_ENTITLEMENT))
|
.entitlement(DEVELOPER_ENTITLEMENT))
|
||||||
.queryParam("scope", "openid profile")
|
.formField("scope", "openid profile")
|
||||||
.formField("principal", principal)
|
.formField("principal", principal)
|
||||||
.formField("sn", customFamilyName));
|
.formField("sn", customFamilyName));
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest {
|
|||||||
TokenResponse tokenResponse = authorizePost(request -> request
|
TokenResponse tokenResponse = authorizePost(request -> request
|
||||||
.with(remoteUser(principal)
|
.with(remoteUser(principal)
|
||||||
.entitlement(DEVELOPER_ENTITLEMENT))
|
.entitlement(DEVELOPER_ENTITLEMENT))
|
||||||
.queryParam("scope", "openid profile")
|
.formField("scope", "openid profile")
|
||||||
.formField("principal", principal)
|
.formField("principal", principal)
|
||||||
.formField("entitlements", customEntitlement));
|
.formField("entitlements", customEntitlement));
|
||||||
|
|
||||||
@@ -168,8 +168,8 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest {
|
|||||||
mockMvc.perform(post(getAuthorizationEndpoint())
|
mockMvc.perform(post(getAuthorizationEndpoint())
|
||||||
.with(remoteUser("developer")
|
.with(remoteUser("developer")
|
||||||
.entitlement(DEVELOPER_ENTITLEMENT))
|
.entitlement(DEVELOPER_ENTITLEMENT))
|
||||||
.queryParam("client_id", CLIENT_ID)
|
.formField("client_id", CLIENT_ID)
|
||||||
.queryParam("redirect_uri", REDIRECT_URI)
|
.formField("redirect_uri", REDIRECT_URI)
|
||||||
.formField("principal", "developer"))
|
.formField("principal", "developer"))
|
||||||
.andExpect(status().isBadRequest())
|
.andExpect(status().isBadRequest())
|
||||||
.andExpect(status().reason(containsString("response_type")));
|
.andExpect(status().reason(containsString("response_type")));
|
||||||
@@ -180,10 +180,10 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest {
|
|||||||
mockMvc.perform(post(getAuthorizationEndpoint())
|
mockMvc.perform(post(getAuthorizationEndpoint())
|
||||||
.with(remoteUser("developer")
|
.with(remoteUser("developer")
|
||||||
.entitlement(DEVELOPER_ENTITLEMENT))
|
.entitlement(DEVELOPER_ENTITLEMENT))
|
||||||
.queryParam("response_type", "code")
|
.formField("response_type", "code")
|
||||||
.queryParam("client_id", CLIENT_ID)
|
.formField("client_id", CLIENT_ID)
|
||||||
.queryParam("redirect_uri", REDIRECT_URI)
|
.formField("redirect_uri", REDIRECT_URI)
|
||||||
.queryParam("scope", "invalid")
|
.formField("scope", "invalid")
|
||||||
.formField("principal", "developer"))
|
.formField("principal", "developer"))
|
||||||
.andExpect(status().is3xxRedirection())
|
.andExpect(status().is3xxRedirection())
|
||||||
.andExpect(result -> {
|
.andExpect(result -> {
|
||||||
@@ -197,9 +197,9 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest {
|
|||||||
mockMvc.perform(post(getAuthorizationEndpoint())
|
mockMvc.perform(post(getAuthorizationEndpoint())
|
||||||
.with(remoteUser("developer")
|
.with(remoteUser("developer")
|
||||||
.entitlement(DEVELOPER_ENTITLEMENT))
|
.entitlement(DEVELOPER_ENTITLEMENT))
|
||||||
.queryParam("response_type", "code")
|
.formField("response_type", "code")
|
||||||
.queryParam("client_id", "invalid-client-id")
|
.formField("client_id", "invalid-client-id")
|
||||||
.queryParam("redirect_uri", REDIRECT_URI)
|
.formField("redirect_uri", REDIRECT_URI)
|
||||||
.formField("principal", "developer"))
|
.formField("principal", "developer"))
|
||||||
.andExpect(status().isBadRequest())
|
.andExpect(status().isBadRequest())
|
||||||
.andExpect(status().reason(containsString("client_id")));
|
.andExpect(status().reason(containsString("client_id")));
|
||||||
@@ -212,11 +212,11 @@ public class StagingProfileTest extends AbstractMetadataCodeFlowTest {
|
|||||||
mockMvc.perform(post(getAuthorizationEndpoint())
|
mockMvc.perform(post(getAuthorizationEndpoint())
|
||||||
.with(remoteUser("developer")
|
.with(remoteUser("developer")
|
||||||
.entitlement(DEVELOPER_ENTITLEMENT))
|
.entitlement(DEVELOPER_ENTITLEMENT))
|
||||||
.queryParam("response_type", "code")
|
.formField("response_type", "code")
|
||||||
.queryParam("client_id", CLIENT_ID)
|
.formField("client_id", CLIENT_ID)
|
||||||
.queryParam("redirect_uri", REDIRECT_URI)
|
.formField("redirect_uri", REDIRECT_URI)
|
||||||
.queryParam("state", state)
|
.formField("state", state)
|
||||||
.queryParam("scope", "invalid")
|
.formField("scope", "invalid")
|
||||||
.formField("principal", "developer"))
|
.formField("principal", "developer"))
|
||||||
.andExpect(status().is3xxRedirection())
|
.andExpect(status().is3xxRedirection())
|
||||||
.andExpect(result -> {
|
.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.core.oidc.OidcScopes;
|
||||||
import org.springframework.security.oauth2.server.authorization.client.InMemoryRegisteredClientRepository;
|
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.client.RegisteredClient;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
|
||||||
|
|
||||||
@TestConfiguration
|
@TestConfiguration
|
||||||
public class TestRegisteredClientConfiguration {
|
public class TestRegisteredClientConfiguration {
|
||||||
@@ -21,6 +22,9 @@ public class TestRegisteredClientConfiguration {
|
|||||||
InMemoryRegisteredClientRepository testRegisteredClientRepository() {
|
InMemoryRegisteredClientRepository testRegisteredClientRepository() {
|
||||||
RegisteredClient registeredClient = RegisteredClient.withId("id")
|
RegisteredClient registeredClient = RegisteredClient.withId("id")
|
||||||
.clientId(CLIENT_ID)
|
.clientId(CLIENT_ID)
|
||||||
|
.clientSettings(ClientSettings.builder()
|
||||||
|
.requireProofKey(false)
|
||||||
|
.build())
|
||||||
.clientSecret("{noop}" + CLIENT_SECRET)
|
.clientSecret("{noop}" + CLIENT_SECRET)
|
||||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||||
.redirectUri(REDIRECT_URI)
|
.redirectUri(REDIRECT_URI)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
package se.su.dsv.oauth2;
|
package se.su.dsv.oauth2;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
import org.springframework.security.oauth2.core.oidc.OidcScopes;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
|
import tools.jackson.databind.JsonNode;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ public class UserInfoEndpointTest extends AbstractMetadataCodeFlowTest {
|
|||||||
|
|
||||||
JsonNode openidConfiguration = objectMapper.readTree(mvcResult.getResponse().getContentAsString());
|
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);
|
URI userInfoUri = URI.create(userinfoEndpoint);
|
||||||
|
|
||||||
assertEquals("/oidc/userinfo", userInfoUri.getPath());
|
assertEquals("/oidc/userinfo", userInfoUri.getPath());
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ package se.su.dsv.oauth2.web;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
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.MockMvc;
|
||||||
import org.testcontainers.containers.MariaDBContainer;
|
import org.testcontainers.mariadb.MariaDBContainer;
|
||||||
import org.testcontainers.junit.jupiter.Container;
|
import org.testcontainers.junit.jupiter.Container;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||||||
class AdminControllerTest {
|
class AdminControllerTest {
|
||||||
@Container
|
@Container
|
||||||
@ServiceConnection
|
@ServiceConnection
|
||||||
static MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("mariadb:10.11");
|
static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11");
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
MockMvc mockMvc;
|
MockMvc mockMvc;
|
||||||
@@ -28,7 +28,7 @@ class AdminControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
void is_protected() throws Exception {
|
void is_protected() throws Exception {
|
||||||
mockMvc.perform(get("/admin"))
|
mockMvc.perform(get("/admin"))
|
||||||
.andExpect(redirectedUrl("http://localhost/login"));
|
.andExpect(redirectedUrl("/login"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ package se.su.dsv.oauth2.web.client;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.test.context.SpringBootTest;
|
||||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
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.annotation.Rollback;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
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.Client;
|
||||||
import se.su.dsv.oauth2.admin.ClientManagementService;
|
import se.su.dsv.oauth2.admin.ClientManagementService;
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ public class ClientAdminControllerTest {
|
|||||||
public static final String DEVELOPER_ENTITLEMENT = "developer";
|
public static final String DEVELOPER_ENTITLEMENT = "developer";
|
||||||
|
|
||||||
@ServiceConnection
|
@ServiceConnection
|
||||||
static MariaDBContainer<?> mariaDBContainer = new MariaDBContainer<>("mariadb:10.11");
|
static MariaDBContainer mariaDBContainer = new MariaDBContainer("mariadb:10.11");
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
MockMvc mockMvc;
|
MockMvc mockMvc;
|
||||||
|
|||||||
Reference in New Issue
Block a user
Shouldn't this be
<scope>test</scope>?