Set iss claim in Jwt using configured issuer
Closes gh-223
This commit is contained in:
parent
afd5491ced
commit
c9afc3e061
@ -1,123 +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 org.springframework.security.oauth2.server.authorization.authentication;
|
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.springframework.security.oauth2.core.OAuth2TokenType;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
|
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
|
||||||
import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames;
|
|
||||||
import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames;
|
|
||||||
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
|
|
||||||
import org.springframework.security.oauth2.jwt.JoseHeader;
|
|
||||||
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
|
||||||
import org.springframework.security.oauth2.server.authorization.token.JwtEncodingContext;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Joe Grandja
|
|
||||||
* @since 0.1.0
|
|
||||||
*/
|
|
||||||
final class JwtEncodingContextUtils {
|
|
||||||
private static final OAuth2TokenType ID_TOKEN_TOKEN_TYPE = new OAuth2TokenType(OidcParameterNames.ID_TOKEN);
|
|
||||||
|
|
||||||
private JwtEncodingContextUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
static JwtEncodingContext.Builder accessTokenContext(RegisteredClient registeredClient, OAuth2Authorization authorization) {
|
|
||||||
// @formatter:off
|
|
||||||
return accessTokenContext(registeredClient, authorization,
|
|
||||||
authorization.getAttribute(OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME));
|
|
||||||
// @formatter:on
|
|
||||||
}
|
|
||||||
|
|
||||||
static JwtEncodingContext.Builder accessTokenContext(RegisteredClient registeredClient, OAuth2Authorization authorization,
|
|
||||||
Set<String> authorizedScopes) {
|
|
||||||
// @formatter:off
|
|
||||||
return accessTokenContext(registeredClient, authorization.getPrincipalName(), authorizedScopes)
|
|
||||||
.authorization(authorization);
|
|
||||||
// @formatter:on
|
|
||||||
}
|
|
||||||
|
|
||||||
static JwtEncodingContext.Builder accessTokenContext(RegisteredClient registeredClient,
|
|
||||||
String principalName, Set<String> authorizedScopes) {
|
|
||||||
|
|
||||||
JoseHeader.Builder headersBuilder = JoseHeader.withAlgorithm(SignatureAlgorithm.RS256);
|
|
||||||
|
|
||||||
String issuer = "http://auth-server:9000"; // TODO Allow configuration for issuer claim
|
|
||||||
Instant issuedAt = Instant.now();
|
|
||||||
Instant expiresAt = issuedAt.plus(registeredClient.getTokenSettings().accessTokenTimeToLive());
|
|
||||||
|
|
||||||
// @formatter:off
|
|
||||||
JwtClaimsSet.Builder claimsBuilder = JwtClaimsSet.builder()
|
|
||||||
.issuer(issuer)
|
|
||||||
.subject(principalName)
|
|
||||||
.audience(Collections.singletonList(registeredClient.getClientId()))
|
|
||||||
.issuedAt(issuedAt)
|
|
||||||
.expiresAt(expiresAt)
|
|
||||||
.notBefore(issuedAt);
|
|
||||||
if (!CollectionUtils.isEmpty(authorizedScopes)) {
|
|
||||||
claimsBuilder.claim(OAuth2ParameterNames.SCOPE, authorizedScopes);
|
|
||||||
}
|
|
||||||
// @formatter:on
|
|
||||||
|
|
||||||
// @formatter:off
|
|
||||||
return JwtEncodingContext.with(headersBuilder, claimsBuilder)
|
|
||||||
.registeredClient(registeredClient)
|
|
||||||
.tokenType(OAuth2TokenType.ACCESS_TOKEN);
|
|
||||||
// @formatter:on
|
|
||||||
}
|
|
||||||
|
|
||||||
static JwtEncodingContext.Builder idTokenContext(RegisteredClient registeredClient, OAuth2Authorization authorization) {
|
|
||||||
JoseHeader.Builder headersBuilder = JoseHeader.withAlgorithm(SignatureAlgorithm.RS256);
|
|
||||||
|
|
||||||
String issuer = "http://auth-server:9000"; // TODO Allow configuration for issuer claim
|
|
||||||
Instant issuedAt = Instant.now();
|
|
||||||
Instant expiresAt = issuedAt.plus(30, ChronoUnit.MINUTES); // TODO Allow configuration for id token time-to-live
|
|
||||||
OAuth2AuthorizationRequest authorizationRequest = authorization.getAttribute(
|
|
||||||
OAuth2AuthorizationRequest.class.getName());
|
|
||||||
String nonce = (String) authorizationRequest.getAdditionalParameters().get(OidcParameterNames.NONCE);
|
|
||||||
|
|
||||||
// @formatter:off
|
|
||||||
JwtClaimsSet.Builder claimsBuilder = JwtClaimsSet.builder()
|
|
||||||
.issuer(issuer)
|
|
||||||
.subject(authorization.getPrincipalName())
|
|
||||||
.audience(Collections.singletonList(registeredClient.getClientId()))
|
|
||||||
.issuedAt(issuedAt)
|
|
||||||
.expiresAt(expiresAt)
|
|
||||||
.claim(IdTokenClaimNames.AZP, registeredClient.getClientId());
|
|
||||||
if (StringUtils.hasText(nonce)) {
|
|
||||||
claimsBuilder.claim(IdTokenClaimNames.NONCE, nonce);
|
|
||||||
}
|
|
||||||
// TODO Add 'auth_time' claim
|
|
||||||
// @formatter:on
|
|
||||||
|
|
||||||
// @formatter:off
|
|
||||||
return JwtEncodingContext.with(headersBuilder, claimsBuilder)
|
|
||||||
.registeredClient(registeredClient)
|
|
||||||
.authorization(authorization)
|
|
||||||
.tokenType(ID_TOKEN_TOKEN_TYPE);
|
|
||||||
// @formatter:on
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* 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 org.springframework.security.oauth2.server.authorization.authentication;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
|
import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames;
|
||||||
|
import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm;
|
||||||
|
import org.springframework.security.oauth2.jwt.JoseHeader;
|
||||||
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
|
||||||
|
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility methods used by the {@link AuthenticationProvider}'s when issuing {@link Jwt}'s.
|
||||||
|
*
|
||||||
|
* @author Joe Grandja
|
||||||
|
* @since 0.1.0
|
||||||
|
*/
|
||||||
|
final class JwtUtils {
|
||||||
|
|
||||||
|
private JwtUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static JoseHeader.Builder headers() {
|
||||||
|
return JoseHeader.withAlgorithm(SignatureAlgorithm.RS256);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JwtClaimsSet.Builder accessTokenClaims(RegisteredClient registeredClient,
|
||||||
|
String issuer, String subject, Set<String> authorizedScopes) {
|
||||||
|
|
||||||
|
Instant issuedAt = Instant.now();
|
||||||
|
Instant expiresAt = issuedAt.plus(registeredClient.getTokenSettings().accessTokenTimeToLive());
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
JwtClaimsSet.Builder claimsBuilder = JwtClaimsSet.builder();
|
||||||
|
if (StringUtils.hasText(issuer)) {
|
||||||
|
claimsBuilder.issuer(issuer);
|
||||||
|
}
|
||||||
|
claimsBuilder
|
||||||
|
.subject(subject)
|
||||||
|
.audience(Collections.singletonList(registeredClient.getClientId()))
|
||||||
|
.issuedAt(issuedAt)
|
||||||
|
.expiresAt(expiresAt)
|
||||||
|
.notBefore(issuedAt);
|
||||||
|
if (!CollectionUtils.isEmpty(authorizedScopes)) {
|
||||||
|
claimsBuilder.claim(OAuth2ParameterNames.SCOPE, authorizedScopes);
|
||||||
|
}
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
return claimsBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
static JwtClaimsSet.Builder idTokenClaims(RegisteredClient registeredClient,
|
||||||
|
String issuer, String subject, String nonce) {
|
||||||
|
|
||||||
|
Instant issuedAt = Instant.now();
|
||||||
|
// TODO Allow configuration for ID Token time-to-live
|
||||||
|
Instant expiresAt = issuedAt.plus(30, ChronoUnit.MINUTES);
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
JwtClaimsSet.Builder claimsBuilder = JwtClaimsSet.builder();
|
||||||
|
if (StringUtils.hasText(issuer)) {
|
||||||
|
claimsBuilder.issuer(issuer);
|
||||||
|
}
|
||||||
|
claimsBuilder
|
||||||
|
.subject(subject)
|
||||||
|
.audience(Collections.singletonList(registeredClient.getClientId()))
|
||||||
|
.issuedAt(issuedAt)
|
||||||
|
.expiresAt(expiresAt)
|
||||||
|
.claim(IdTokenClaimNames.AZP, registeredClient.getClientId());
|
||||||
|
if (StringUtils.hasText(nonce)) {
|
||||||
|
claimsBuilder.claim(IdTokenClaimNames.NONCE, nonce);
|
||||||
|
}
|
||||||
|
// TODO Add 'auth_time' claim
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
return claimsBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -19,7 +19,9 @@ import java.security.Principal;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
@ -42,6 +44,7 @@ import org.springframework.security.oauth2.jwt.JwtEncoder;
|
|||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||||
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.config.ProviderSettings;
|
||||||
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.OAuth2AuthorizationCode;
|
import org.springframework.security.oauth2.server.authorization.token.OAuth2AuthorizationCode;
|
||||||
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
|
import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenCustomizer;
|
||||||
@ -66,10 +69,14 @@ import static org.springframework.security.oauth2.server.authorization.authentic
|
|||||||
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.3">Section 4.1.3 Access Token Request</a>
|
* @see <a target="_blank" href="https://tools.ietf.org/html/rfc6749#section-4.1.3">Section 4.1.3 Access Token Request</a>
|
||||||
*/
|
*/
|
||||||
public class OAuth2AuthorizationCodeAuthenticationProvider implements AuthenticationProvider {
|
public class OAuth2AuthorizationCodeAuthenticationProvider implements AuthenticationProvider {
|
||||||
private static final OAuth2TokenType AUTHORIZATION_CODE_TOKEN_TYPE = new OAuth2TokenType(OAuth2ParameterNames.CODE);
|
private static final OAuth2TokenType AUTHORIZATION_CODE_TOKEN_TYPE =
|
||||||
|
new OAuth2TokenType(OAuth2ParameterNames.CODE);
|
||||||
|
private static final OAuth2TokenType ID_TOKEN_TOKEN_TYPE =
|
||||||
|
new OAuth2TokenType(OidcParameterNames.ID_TOKEN);
|
||||||
private final OAuth2AuthorizationService authorizationService;
|
private final OAuth2AuthorizationService authorizationService;
|
||||||
private final JwtEncoder jwtEncoder;
|
private final JwtEncoder jwtEncoder;
|
||||||
private OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = (context) -> {};
|
private OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = (context) -> {};
|
||||||
|
private ProviderSettings providerSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an {@code OAuth2AuthorizationCodeAuthenticationProvider} using the provided parameters.
|
* Constructs an {@code OAuth2AuthorizationCodeAuthenticationProvider} using the provided parameters.
|
||||||
@ -89,6 +96,11 @@ public class OAuth2AuthorizationCodeAuthenticationProvider implements Authentica
|
|||||||
this.jwtCustomizer = jwtCustomizer;
|
this.jwtCustomizer = jwtCustomizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
protected void setProviderSettings(ProviderSettings providerSettings) {
|
||||||
|
this.providerSettings = providerSettings;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication =
|
OAuth2AuthorizationCodeAuthenticationToken authorizationCodeAuthentication =
|
||||||
@ -127,13 +139,25 @@ public class OAuth2AuthorizationCodeAuthenticationProvider implements Authentica
|
|||||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
|
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String issuer = this.providerSettings != null ? this.providerSettings.issuer() : null;
|
||||||
|
Set<String> authorizedScopes = authorization.getAttribute(
|
||||||
|
OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME);
|
||||||
|
|
||||||
|
JoseHeader.Builder headersBuilder = JwtUtils.headers();
|
||||||
|
JwtClaimsSet.Builder claimsBuilder = JwtUtils.accessTokenClaims(
|
||||||
|
registeredClient, issuer, authorization.getPrincipalName(), authorizedScopes);
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
JwtEncodingContext context = JwtEncodingContextUtils.accessTokenContext(registeredClient, authorization)
|
JwtEncodingContext context = JwtEncodingContext.with(headersBuilder, claimsBuilder)
|
||||||
|
.registeredClient(registeredClient)
|
||||||
.principal(authorization.getAttribute(Principal.class.getName()))
|
.principal(authorization.getAttribute(Principal.class.getName()))
|
||||||
|
.authorization(authorization)
|
||||||
|
.tokenType(OAuth2TokenType.ACCESS_TOKEN)
|
||||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||||
.authorizationGrant(authorizationCodeAuthentication)
|
.authorizationGrant(authorizationCodeAuthentication)
|
||||||
.build();
|
.build();
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
this.jwtCustomizer.customize(context);
|
this.jwtCustomizer.customize(context);
|
||||||
|
|
||||||
JoseHeader headers = context.getHeaders().build();
|
JoseHeader headers = context.getHeaders().build();
|
||||||
@ -152,13 +176,23 @@ public class OAuth2AuthorizationCodeAuthenticationProvider implements Authentica
|
|||||||
|
|
||||||
Jwt jwtIdToken = null;
|
Jwt jwtIdToken = null;
|
||||||
if (authorizationRequest.getScopes().contains(OidcScopes.OPENID)) {
|
if (authorizationRequest.getScopes().contains(OidcScopes.OPENID)) {
|
||||||
|
String nonce = (String) authorizationRequest.getAdditionalParameters().get(OidcParameterNames.NONCE);
|
||||||
|
|
||||||
|
headersBuilder = JwtUtils.headers();
|
||||||
|
claimsBuilder = JwtUtils.idTokenClaims(
|
||||||
|
registeredClient, issuer, authorization.getPrincipalName(), nonce);
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
context = JwtEncodingContextUtils.idTokenContext(registeredClient, authorization)
|
context = JwtEncodingContext.with(headersBuilder, claimsBuilder)
|
||||||
|
.registeredClient(registeredClient)
|
||||||
.principal(authorization.getAttribute(Principal.class.getName()))
|
.principal(authorization.getAttribute(Principal.class.getName()))
|
||||||
|
.authorization(authorization)
|
||||||
|
.tokenType(ID_TOKEN_TOKEN_TYPE)
|
||||||
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
|
||||||
.authorizationGrant(authorizationCodeAuthentication)
|
.authorizationGrant(authorizationCodeAuthentication)
|
||||||
.build();
|
.build();
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
this.jwtCustomizer.customize(context);
|
this.jwtCustomizer.customize(context);
|
||||||
|
|
||||||
headers = context.getHeaders().build();
|
headers = context.getHeaders().build();
|
||||||
|
@ -19,6 +19,7 @@ import java.util.LinkedHashSet;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
@ -27,6 +28,7 @@ import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
|||||||
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
|
||||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2TokenType;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
import org.springframework.security.oauth2.jwt.JoseHeader;
|
import org.springframework.security.oauth2.jwt.JoseHeader;
|
||||||
import org.springframework.security.oauth2.jwt.Jwt;
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
@ -35,6 +37,7 @@ import org.springframework.security.oauth2.jwt.JwtEncoder;
|
|||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||||
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.config.ProviderSettings;
|
||||||
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;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
@ -61,6 +64,7 @@ public class OAuth2ClientCredentialsAuthenticationProvider implements Authentica
|
|||||||
private final OAuth2AuthorizationService authorizationService;
|
private final OAuth2AuthorizationService authorizationService;
|
||||||
private final JwtEncoder jwtEncoder;
|
private final JwtEncoder jwtEncoder;
|
||||||
private OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = (context) -> {};
|
private OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = (context) -> {};
|
||||||
|
private ProviderSettings providerSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an {@code OAuth2ClientCredentialsAuthenticationProvider} using the provided parameters.
|
* Constructs an {@code OAuth2ClientCredentialsAuthenticationProvider} using the provided parameters.
|
||||||
@ -81,6 +85,11 @@ public class OAuth2ClientCredentialsAuthenticationProvider implements Authentica
|
|||||||
this.jwtCustomizer = jwtCustomizer;
|
this.jwtCustomizer = jwtCustomizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
protected void setProviderSettings(ProviderSettings providerSettings) {
|
||||||
|
this.providerSettings = providerSettings;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthentication =
|
OAuth2ClientCredentialsAuthenticationToken clientCredentialsAuthentication =
|
||||||
@ -105,13 +114,22 @@ public class OAuth2ClientCredentialsAuthenticationProvider implements Authentica
|
|||||||
scopes = new LinkedHashSet<>(clientCredentialsAuthentication.getScopes());
|
scopes = new LinkedHashSet<>(clientCredentialsAuthentication.getScopes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String issuer = this.providerSettings != null ? this.providerSettings.issuer() : null;
|
||||||
|
|
||||||
|
JoseHeader.Builder headersBuilder = JwtUtils.headers();
|
||||||
|
JwtClaimsSet.Builder claimsBuilder = JwtUtils.accessTokenClaims(
|
||||||
|
registeredClient, issuer, clientPrincipal.getName(), scopes);
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
JwtEncodingContext context = JwtEncodingContextUtils.accessTokenContext(registeredClient, clientPrincipal.getName(), scopes)
|
JwtEncodingContext context = JwtEncodingContext.with(headersBuilder, claimsBuilder)
|
||||||
|
.registeredClient(registeredClient)
|
||||||
.principal(clientPrincipal)
|
.principal(clientPrincipal)
|
||||||
|
.tokenType(OAuth2TokenType.ACCESS_TOKEN)
|
||||||
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)
|
||||||
.authorizationGrant(clientCredentialsAuthentication)
|
.authorizationGrant(clientCredentialsAuthentication)
|
||||||
.build();
|
.build();
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
this.jwtCustomizer.customize(context);
|
this.jwtCustomizer.customize(context);
|
||||||
|
|
||||||
JoseHeader headers = context.getHeaders().build();
|
JoseHeader headers = context.getHeaders().build();
|
||||||
|
@ -21,6 +21,7 @@ import java.time.Instant;
|
|||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.authentication.AuthenticationProvider;
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.core.AuthenticationException;
|
||||||
@ -33,6 +34,7 @@ import org.springframework.security.oauth2.core.OAuth2Error;
|
|||||||
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
import org.springframework.security.oauth2.core.OAuth2ErrorCodes;
|
||||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken2;
|
import org.springframework.security.oauth2.core.OAuth2RefreshToken2;
|
||||||
|
import org.springframework.security.oauth2.core.OAuth2TokenType;
|
||||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||||
import org.springframework.security.oauth2.jwt.JoseHeader;
|
import org.springframework.security.oauth2.jwt.JoseHeader;
|
||||||
import org.springframework.security.oauth2.jwt.Jwt;
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
@ -40,8 +42,8 @@ import org.springframework.security.oauth2.jwt.JwtClaimsSet;
|
|||||||
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
import org.springframework.security.oauth2.jwt.JwtEncoder;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
|
||||||
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService;
|
||||||
import org.springframework.security.oauth2.core.OAuth2TokenType;
|
|
||||||
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.config.ProviderSettings;
|
||||||
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
|
import org.springframework.security.oauth2.server.authorization.config.TokenSettings;
|
||||||
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;
|
||||||
@ -69,6 +71,7 @@ public class OAuth2RefreshTokenAuthenticationProvider implements AuthenticationP
|
|||||||
private final OAuth2AuthorizationService authorizationService;
|
private final OAuth2AuthorizationService authorizationService;
|
||||||
private final JwtEncoder jwtEncoder;
|
private final JwtEncoder jwtEncoder;
|
||||||
private OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = (context) -> {};
|
private OAuth2TokenCustomizer<JwtEncodingContext> jwtCustomizer = (context) -> {};
|
||||||
|
private ProviderSettings providerSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an {@code OAuth2RefreshTokenAuthenticationProvider} using the provided parameters.
|
* Constructs an {@code OAuth2RefreshTokenAuthenticationProvider} using the provided parameters.
|
||||||
@ -89,6 +92,11 @@ public class OAuth2RefreshTokenAuthenticationProvider implements AuthenticationP
|
|||||||
this.jwtCustomizer = jwtCustomizer;
|
this.jwtCustomizer = jwtCustomizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
protected void setProviderSettings(ProviderSettings providerSettings) {
|
||||||
|
this.providerSettings = providerSettings;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
OAuth2RefreshTokenAuthenticationToken refreshTokenAuthentication =
|
OAuth2RefreshTokenAuthenticationToken refreshTokenAuthentication =
|
||||||
@ -137,13 +145,23 @@ public class OAuth2RefreshTokenAuthenticationProvider implements AuthenticationP
|
|||||||
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
|
throw new OAuth2AuthenticationException(new OAuth2Error(OAuth2ErrorCodes.INVALID_GRANT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String issuer = this.providerSettings != null ? this.providerSettings.issuer() : null;
|
||||||
|
|
||||||
|
JoseHeader.Builder headersBuilder = JwtUtils.headers();
|
||||||
|
JwtClaimsSet.Builder claimsBuilder = JwtUtils.accessTokenClaims(
|
||||||
|
registeredClient, issuer, authorization.getPrincipalName(), scopes);
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
JwtEncodingContext context = JwtEncodingContextUtils.accessTokenContext(registeredClient, authorization, scopes)
|
JwtEncodingContext context = JwtEncodingContext.with(headersBuilder, claimsBuilder)
|
||||||
|
.registeredClient(registeredClient)
|
||||||
.principal(authorization.getAttribute(Principal.class.getName()))
|
.principal(authorization.getAttribute(Principal.class.getName()))
|
||||||
|
.authorization(authorization)
|
||||||
|
.tokenType(OAuth2TokenType.ACCESS_TOKEN)
|
||||||
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
|
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
|
||||||
.authorizationGrant(refreshTokenAuthentication)
|
.authorizationGrant(refreshTokenAuthentication)
|
||||||
.build();
|
.build();
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
|
||||||
this.jwtCustomizer.customize(context);
|
this.jwtCustomizer.customize(context);
|
||||||
|
|
||||||
JoseHeader headers = context.getHeaders().build();
|
JoseHeader headers = context.getHeaders().build();
|
||||||
|
Loading…
Reference in New Issue
Block a user