Browse Source

Merge custom-consent-authorizationserver into featured-authorizationserver

Issue gh-1189
pull/1210/head
Joe Grandja 3 years ago
parent
commit
1485135325
  1. 1
      samples/custom-consent-authorizationserver/gradle.properties
  2. 26
      samples/custom-consent-authorizationserver/samples-custom-consent-authorizationserver.gradle
  3. 31
      samples/custom-consent-authorizationserver/src/main/java/sample/CustomConsentAuthorizationServerApplication.java
  4. 131
      samples/custom-consent-authorizationserver/src/main/java/sample/config/AuthorizationServerConfig.java
  5. 74
      samples/custom-consent-authorizationserver/src/main/java/sample/config/DefaultSecurityConfig.java
  6. 73
      samples/custom-consent-authorizationserver/src/main/java/sample/jose/Jwks.java
  7. 84
      samples/custom-consent-authorizationserver/src/main/java/sample/jose/KeyGeneratorUtils.java
  8. 10
      samples/custom-consent-authorizationserver/src/main/resources/application.yml
  9. 126
      samples/custom-consent-authorizationserver/src/test/java/sample/CustomConsentAuthorizationServerTests.java
  10. 1
      samples/featured-authorizationserver/samples-featured-authorizationserver.gradle
  11. 5
      samples/featured-authorizationserver/src/main/java/sample/config/AuthorizationServerConfig.java
  12. 3
      samples/featured-authorizationserver/src/main/java/sample/web/AuthorizationConsentController.java
  13. 5
      samples/featured-authorizationserver/src/main/resources/templates/consent.html
  14. 4
      samples/featured-authorizationserver/src/test/java/sample/FeaturedAuthorizationServerConsentTests.java

1
samples/custom-consent-authorizationserver/gradle.properties

@ -1 +0,0 @@ @@ -1 +0,0 @@
spring-security.version=6.1.0-RC1

26
samples/custom-consent-authorizationserver/samples-custom-consent-authorizationserver.gradle

@ -1,26 +0,0 @@ @@ -1,26 +0,0 @@
plugins {
id "org.springframework.boot" version "3.0.0"
id "io.spring.dependency-management" version "1.0.11.RELEASE"
id "java"
}
group = project.rootProject.group
version = project.rootProject.version
sourceCompatibility = "17"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
implementation "org.springframework.boot:spring-boot-starter-web"
implementation "org.springframework.boot:spring-boot-starter-thymeleaf"
implementation "org.springframework.boot:spring-boot-starter-security"
implementation project(":spring-security-oauth2-authorization-server")
testImplementation "org.springframework.boot:spring-boot-starter-test"
testImplementation "org.springframework.security:spring-security-test"
testImplementation "org.junit.jupiter:junit-jupiter"
testImplementation "net.sourceforge.htmlunit:htmlunit"
}

31
samples/custom-consent-authorizationserver/src/main/java/sample/CustomConsentAuthorizationServerApplication.java

@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
/*
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author Daniel Garnier-Moiroux
*/
@SpringBootApplication
public class CustomConsentAuthorizationServerApplication {
public static void main(String[] args) {
SpringApplication.run(CustomConsentAuthorizationServerApplication.class, args);
}
}

131
samples/custom-consent-authorizationserver/src/main/java/sample/config/AuthorizationServerConfig.java

@ -1,131 +0,0 @@ @@ -1,131 +0,0 @@
/*
* Copyright 2020-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.config;
import java.util.UUID;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import sample.jose.Jwks;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.core.oidc.OidcScopes;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
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.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
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.ClientSettings;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* @author Joe Grandja
* @author Daniel Garnier-Moiroux
*/
@Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {
private static final String CUSTOM_CONSENT_PAGE_URI = "/oauth2/consent";
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
new OAuth2AuthorizationServerConfigurer();
authorizationServerConfigurer
.authorizationEndpoint(authorizationEndpoint ->
authorizationEndpoint.consentPage(CUSTOM_CONSENT_PAGE_URI))
.oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0
RequestMatcher endpointsMatcher = authorizationServerConfigurer
.getEndpointsMatcher();
http
.securityMatcher(endpointsMatcher)
.authorizeHttpRequests(authorize ->
authorize.anyRequest().authenticated()
)
.csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
.exceptionHandling(exceptions ->
exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
)
.oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
.apply(authorizationServerConfigurer);
return http.build();
}
// @formatter:off
@Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("messaging-client")
.clientSecret("{noop}secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
.redirectUri("http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc")
.redirectUri("http://127.0.0.1:8080/authorized")
.postLogoutRedirectUri("http://127.0.0.1:8080/logged-out")
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.scope("message.read")
.scope("message.write")
.clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).build())
.build();
return new InMemoryRegisteredClientRepository(registeredClient);
}
// @formatter:on
@Bean
public JWKSource<SecurityContext> jwkSource() {
RSAKey rsaKey = Jwks.generateRsa();
JWKSet jwkSet = new JWKSet(rsaKey);
return (jwkSelector, securityContext) -> jwkSelector.select(jwkSet);
}
@Bean
public JwtDecoder jwtDecoder(JWKSource<SecurityContext> jwkSource) {
return OAuth2AuthorizationServerConfiguration.jwtDecoder(jwkSource);
}
@Bean
public AuthorizationServerSettings authorizationServerSettings() {
return AuthorizationServerSettings.builder().build();
}
@Bean
public OAuth2AuthorizationConsentService authorizationConsentService() {
// Will be used by the ConsentController
return new InMemoryOAuth2AuthorizationConsentService();
}
}

74
samples/custom-consent-authorizationserver/src/main/java/sample/config/DefaultSecurityConfig.java

@ -1,74 +0,0 @@ @@ -1,74 +0,0 @@
/*
* Copyright 2020-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import static org.springframework.security.config.Customizer.withDefaults;
/**
* @author Joe Grandja
*/
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class DefaultSecurityConfig {
// @formatter:off
@Bean
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize ->
authorize.anyRequest().authenticated()
)
.formLogin(withDefaults());
return http.build();
}
// @formatter:on
// @formatter:off
@Bean
UserDetailsService users() {
UserDetails user = User.withDefaultPasswordEncoder()
.username("user1")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
// @formatter:on
@Bean
SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
}

73
samples/custom-consent-authorizationserver/src/main/java/sample/jose/Jwks.java

@ -1,73 +0,0 @@ @@ -1,73 +0,0 @@
/*
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.jose;
import java.security.KeyPair;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;
import javax.crypto.SecretKey;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.OctetSequenceKey;
import com.nimbusds.jose.jwk.RSAKey;
/**
* @author Joe Grandja
*/
public final class Jwks {
private Jwks() {
}
public static RSAKey generateRsa() {
KeyPair keyPair = KeyGeneratorUtils.generateRsaKey();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
// @formatter:off
return new RSAKey.Builder(publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
// @formatter:on
}
public static ECKey generateEc() {
KeyPair keyPair = KeyGeneratorUtils.generateEcKey();
ECPublicKey publicKey = (ECPublicKey) keyPair.getPublic();
ECPrivateKey privateKey = (ECPrivateKey) keyPair.getPrivate();
Curve curve = Curve.forECParameterSpec(publicKey.getParams());
// @formatter:off
return new ECKey.Builder(curve, publicKey)
.privateKey(privateKey)
.keyID(UUID.randomUUID().toString())
.build();
// @formatter:on
}
public static OctetSequenceKey generateSecret() {
SecretKey secretKey = KeyGeneratorUtils.generateSecretKey();
// @formatter:off
return new OctetSequenceKey.Builder(secretKey)
.keyID(UUID.randomUUID().toString())
.build();
// @formatter:on
}
}

84
samples/custom-consent-authorizationserver/src/main/java/sample/jose/KeyGeneratorUtils.java

@ -1,84 +0,0 @@ @@ -1,84 +0,0 @@
/*
* Copyright 2020-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.jose;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
/**
* @author Joe Grandja
*/
final class KeyGeneratorUtils {
private KeyGeneratorUtils() {
}
static SecretKey generateSecretKey() {
SecretKey hmacKey;
try {
hmacKey = KeyGenerator.getInstance("HmacSha256").generateKey();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return hmacKey;
}
static KeyPair generateRsaKey() {
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
static KeyPair generateEcKey() {
EllipticCurve ellipticCurve = new EllipticCurve(
new ECFieldFp(
new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951")),
new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853948"),
new BigInteger("41058363725152142129326129780047268409114441015993725554835256314039467401291"));
ECPoint ecPoint = new ECPoint(
new BigInteger("48439561293906451759052585252797914202762949526041747995844080717082404635286"),
new BigInteger("36134250956749795798585127919587881956611106672985015071877198253568414405109"));
ECParameterSpec ecParameterSpec = new ECParameterSpec(
ellipticCurve,
ecPoint,
new BigInteger("115792089210356248762697446949407573529996955224135760342422259061068512044369"),
1);
KeyPair keyPair;
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(ecParameterSpec);
keyPair = keyPairGenerator.generateKeyPair();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
return keyPair;
}
}

10
samples/custom-consent-authorizationserver/src/main/resources/application.yml

@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
server:
port: 9000
logging:
level:
root: INFO
org.springframework.web: INFO
org.springframework.security: INFO
org.springframework.security.oauth2: INFO
# org.springframework.boot.autoconfigure: DEBUG

126
samples/custom-consent-authorizationserver/src/test/java/sample/CustomConsentAuthorizationServerTests.java

@ -1,126 +0,0 @@ @@ -1,126 +0,0 @@
/*
* Copyright 2020-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebResponse;
import com.gargoylesoftware.htmlunit.html.DomElement;
import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
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.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationConsentService;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.web.util.UriComponentsBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
/**
* Consent page integration tests for the sample Authorization Server serving a custom Consent page.
*
* @author Dmitriy Dubson
*/
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class CustomConsentAuthorizationServerTests {
@Autowired
private WebClient webClient;
@MockBean
private OAuth2AuthorizationConsentService authorizationConsentService;
private final String redirectUri = "http://127.0.0.1/login/oauth2/code/messaging-client-oidc";
private final String authorizationRequestUri = UriComponentsBuilder
.fromPath("/oauth2/authorize")
.queryParam("response_type", "code")
.queryParam("client_id", "messaging-client")
.queryParam("scope", "openid message.read message.write")
.queryParam("state", "state")
.queryParam("redirect_uri", this.redirectUri)
.toUriString();
@BeforeEach
public void setUp() {
this.webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
this.webClient.getOptions().setRedirectEnabled(true);
this.webClient.getCookieManager().clearCookies();
when(this.authorizationConsentService.findById(any(), any())).thenReturn(null);
}
@Test
@WithMockUser("user1")
public void whenUserConsentsToAllScopesThenReturnAuthorizationCode() throws IOException {
final HtmlPage consentPage = this.webClient.getPage(this.authorizationRequestUri);
assertThat(consentPage.getTitleText()).isEqualTo("Custom consent page - Consent required");
List<HtmlCheckBoxInput> scopes = new ArrayList<>();
consentPage.querySelectorAll("input[name='scope']").forEach(scope ->
scopes.add((HtmlCheckBoxInput) scope));
for (HtmlCheckBoxInput scope : scopes) {
scope.click();
}
List<String> scopeIds = new ArrayList<>();
scopes.forEach(scope -> {
assertThat(scope.isChecked()).isTrue();
scopeIds.add(scope.getId());
});
assertThat(scopeIds).containsExactlyInAnyOrder("message.read", "message.write");
DomElement submitConsentButton = consentPage.querySelector("button[id='submit-consent']");
this.webClient.getOptions().setRedirectEnabled(false);
WebResponse approveConsentResponse = submitConsentButton.click().getWebResponse();
assertThat(approveConsentResponse.getStatusCode()).isEqualTo(HttpStatus.MOVED_PERMANENTLY.value());
String location = approveConsentResponse.getResponseHeaderValue("location");
assertThat(location).startsWith(this.redirectUri);
assertThat(location).contains("code=");
}
@Test
@WithMockUser("user1")
public void whenUserCancelsConsentThenReturnAccessDeniedError() throws IOException {
final HtmlPage consentPage = this.webClient.getPage(this.authorizationRequestUri);
assertThat(consentPage.getTitleText()).isEqualTo("Custom consent page - Consent required");
DomElement cancelConsentButton = consentPage.querySelector("button[id='cancel-consent']");
this.webClient.getOptions().setRedirectEnabled(false);
WebResponse cancelConsentResponse = cancelConsentButton.click().getWebResponse();
assertThat(cancelConsentResponse.getStatusCode()).isEqualTo(HttpStatus.MOVED_PERMANENTLY.value());
String location = cancelConsentResponse.getResponseHeaderValue("location");
assertThat(location).startsWith(this.redirectUri);
assertThat(location).contains("error=access_denied");
}
}

1
samples/featured-authorizationserver/samples-featured-authorizationserver.gradle

@ -15,6 +15,7 @@ repositories { @@ -15,6 +15,7 @@ repositories {
dependencies {
implementation "org.springframework.boot:spring-boot-starter-web"
implementation "org.springframework.boot:spring-boot-starter-thymeleaf"
implementation "org.springframework.boot:spring-boot-starter-security"
implementation "org.springframework.boot:spring-boot-starter-jdbc"
implementation project(":spring-security-oauth2-authorization-server")

5
samples/featured-authorizationserver/src/main/java/sample/config/AuthorizationServerConfig.java

@ -53,16 +53,20 @@ import org.springframework.security.web.authentication.LoginUrlAuthenticationEnt @@ -53,16 +53,20 @@ import org.springframework.security.web.authentication.LoginUrlAuthenticationEnt
/**
* @author Joe Grandja
* @author Daniel Garnier-Moiroux
* @since 1.1.0
*/
@Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {
private static final String CUSTOM_CONSENT_PAGE_URI = "/oauth2/consent";
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.authorizationEndpoint(authorizationEndpoint ->
authorizationEndpoint.consentPage(CUSTOM_CONSENT_PAGE_URI))
.oidc(Customizer.withDefaults()); // Enable OpenID Connect 1.0
// @formatter:off
@ -113,6 +117,7 @@ public class AuthorizationServerConfig { @@ -113,6 +117,7 @@ public class AuthorizationServerConfig {
@Bean
public OAuth2AuthorizationConsentService authorizationConsentService(JdbcTemplate jdbcTemplate,
RegisteredClientRepository registeredClientRepository) {
// Will be used by the ConsentController
return new JdbcOAuth2AuthorizationConsentService(jdbcTemplate, registeredClientRepository);
}

3
samples/custom-consent-authorizationserver/src/main/java/sample/web/AuthorizationConsentController.java → samples/featured-authorizationserver/src/main/java/sample/web/AuthorizationConsentController.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2020-2022 the original author or authors.
* Copyright 2020-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -125,4 +125,5 @@ public class AuthorizationConsentController { @@ -125,4 +125,5 @@ public class AuthorizationConsentController {
this.description = scopeDescriptions.getOrDefault(scope, DEFAULT_DESCRIPTION);
}
}
}

5
samples/custom-consent-authorizationserver/src/main/resources/templates/consent.html → samples/featured-authorizationserver/src/main/resources/templates/consent.html

@ -6,11 +6,6 @@ @@ -6,11 +6,6 @@
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<title>Custom consent page - Consent required</title>
<style>
body {
background-color: aliceblue;
}
</style>
<script>
function cancelConsent() {
document.consent_form.reset();

4
samples/featured-authorizationserver/src/test/java/sample/FeaturedAuthorizationServerConsentTests.java

@ -81,7 +81,7 @@ public class FeaturedAuthorizationServerConsentTests { @@ -81,7 +81,7 @@ public class FeaturedAuthorizationServerConsentTests {
@WithMockUser("user1")
public void whenUserConsentsToAllScopesThenReturnAuthorizationCode() throws IOException {
final HtmlPage consentPage = this.webClient.getPage(this.authorizationRequestUri);
assertThat(consentPage.getTitleText()).isEqualTo("Consent required");
assertThat(consentPage.getTitleText()).isEqualTo("Custom consent page - Consent required");
List<HtmlCheckBoxInput> scopes = new ArrayList<>();
consentPage.querySelectorAll("input[name='scope']").forEach(scope ->
@ -111,7 +111,7 @@ public class FeaturedAuthorizationServerConsentTests { @@ -111,7 +111,7 @@ public class FeaturedAuthorizationServerConsentTests {
@WithMockUser("user1")
public void whenUserCancelsConsentThenReturnAccessDeniedError() throws IOException {
final HtmlPage consentPage = this.webClient.getPage(this.authorizationRequestUri);
assertThat(consentPage.getTitleText()).isEqualTo("Consent required");
assertThat(consentPage.getTitleText()).isEqualTo("Custom consent page - Consent required");
DomElement cancelConsentButton = consentPage.querySelector("button[id='cancel-consent']");
this.webClient.getOptions().setRedirectEnabled(false);

Loading…
Cancel
Save