diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ConfigurerUtils.java b/oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ConfigurerUtils.java index b6f57d08..c728249e 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ConfigurerUtils.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2ConfigurerUtils.java @@ -28,7 +28,7 @@ import org.springframework.core.ResolvableType; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; import org.springframework.security.oauth2.core.OAuth2Token; import org.springframework.security.oauth2.jwt.JwtEncoder; -import org.springframework.security.oauth2.jwt.NimbusJwsEncoder; +import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator; import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationConsentService; import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService; @@ -138,7 +138,7 @@ final class OAuth2ConfigurerUtils { if (jwtEncoder == null) { JWKSource jwkSource = getJwkSource(builder); if (jwkSource != null) { - jwtEncoder = new NimbusJwsEncoder(jwkSource); + jwtEncoder = new NimbusJwtEncoder(jwkSource); } } if (jwtEncoder != null) { diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JoseHeader.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JoseHeader.java deleted file mode 100644 index 1b7561e1..00000000 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JoseHeader.java +++ /dev/null @@ -1,396 +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 org.springframework.security.oauth2.jwt; - -import java.net.URL; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Consumer; - -import org.springframework.security.oauth2.core.converter.ClaimConversionService; -import org.springframework.security.oauth2.jose.JwaAlgorithm; -import org.springframework.util.Assert; - -/** - * The JOSE header is a JSON object representing the header parameters of a JSON Web Token, - * whether the JWT is a JWS or JWE, that describe the cryptographic operations applied to the JWT - * and optionally, additional properties of the JWT. - * - * @author Anoop Garlapati - * @author Joe Grandja - * @since 0.0.1 - * @see Jwt - * @see JWT JOSE Header - * @see JWS JOSE Header - * @see JWE JOSE Header - * @deprecated See gh-596 - */ -@Deprecated -public final class JoseHeader { - private final Map headers; - - private JoseHeader(Map headers) { - this.headers = Collections.unmodifiableMap(new HashMap<>(headers)); - } - - /** - * Returns the {@link JwaAlgorithm JWA algorithm} used to digitally sign the JWS or encrypt the JWE. - * - * @return the {@link JwaAlgorithm} - */ - @SuppressWarnings("unchecked") - public T getAlgorithm() { - return (T) getHeader(JoseHeaderNames.ALG); - } - - /** - * Returns the JWK Set URL that refers to the resource of a set of JSON-encoded public keys, - * one of which corresponds to the key used to digitally sign the JWS or encrypt the JWE. - * - * @return the JWK Set URL - */ - public URL getJwkSetUrl() { - return getHeader(JoseHeaderNames.JKU); - } - - /** - * Returns the JSON Web Key which is the public key that corresponds to the key - * used to digitally sign the JWS or encrypt the JWE. - * - * @return the JSON Web Key - */ - public Map getJwk() { - return getHeader(JoseHeaderNames.JWK); - } - - /** - * Returns the key ID that is a hint indicating which key was used to secure the JWS or JWE. - * - * @return the key ID - */ - public String getKeyId() { - return getHeader(JoseHeaderNames.KID); - } - - /** - * Returns the X.509 URL that refers to the resource for the X.509 public key certificate - * or certificate chain corresponding to the key used to digitally sign the JWS or encrypt the JWE. - * - * @return the X.509 URL - */ - public URL getX509Url() { - return getHeader(JoseHeaderNames.X5U); - } - - /** - * Returns the X.509 certificate chain that contains the X.509 public key certificate - * or certificate chain corresponding to the key used to digitally sign the JWS or - * encrypt the JWE. The certificate or certificate chain is represented as a - * {@code List} of certificate value {@code String}s. Each {@code String} in the - * {@code List} is a Base64-encoded DER PKIX certificate value. - * - * @return the X.509 certificate chain - */ - public List getX509CertificateChain() { - return getHeader(JoseHeaderNames.X5C); - } - - /** - * Returns the X.509 certificate SHA-1 thumbprint that is a base64url-encoded SHA-1 thumbprint (a.k.a. digest) - * of the DER encoding of the X.509 certificate corresponding to the key used to digitally sign the JWS or encrypt the JWE. - * - * @return the X.509 certificate SHA-1 thumbprint - */ - public String getX509SHA1Thumbprint() { - return getHeader(JoseHeaderNames.X5T); - } - - /** - * Returns the X.509 certificate SHA-256 thumbprint that is a base64url-encoded SHA-256 thumbprint (a.k.a. digest) - * of the DER encoding of the X.509 certificate corresponding to the key used to digitally sign the JWS or encrypt the JWE. - * - * @return the X.509 certificate SHA-256 thumbprint - */ - public String getX509SHA256Thumbprint() { - return getHeader(JoseHeaderNames.X5T_S256); - } - - /** - * Returns the type header that declares the media type of the JWS/JWE. - * - * @return the type header - */ - public String getType() { - return getHeader(JoseHeaderNames.TYP); - } - - /** - * Returns the content type header that declares the media type of the secured content (the payload). - * - * @return the content type header - */ - public String getContentType() { - return getHeader(JoseHeaderNames.CTY); - } - - /** - * Returns the critical headers that indicates which extensions to the JWS/JWE/JWA specifications - * are being used that MUST be understood and processed. - * - * @return the critical headers - */ - public Set getCritical() { - return getHeader(JoseHeaderNames.CRIT); - } - - /** - * Returns the headers. - * - * @return the headers - */ - public Map getHeaders() { - return this.headers; - } - - /** - * Returns the header value. - * - * @param name the header name - * @param the type of the header value - * @return the header value - */ - @SuppressWarnings("unchecked") - public T getHeader(String name) { - Assert.hasText(name, "name cannot be empty"); - return (T) getHeaders().get(name); - } - - /** - * Returns a new {@link Builder}. - * - * @return the {@link Builder} - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Returns a new {@link Builder}, initialized with the provided {@link JwaAlgorithm}. - * - * @param jwaAlgorithm the {@link JwaAlgorithm} - * @return the {@link Builder} - */ - public static Builder withAlgorithm(JwaAlgorithm jwaAlgorithm) { - return new Builder(jwaAlgorithm); - } - - /** - * Returns a new {@link Builder}, initialized with the provided {@code headers}. - * - * @param headers the headers - * @return the {@link Builder} - */ - public static Builder from(JoseHeader headers) { - return new Builder(headers); - } - - /** - * A builder for {@link JoseHeader}. - */ - public static final class Builder { - private final Map headers = new HashMap<>(); - - private Builder() { - } - - private Builder(JwaAlgorithm jwaAlgorithm) { - algorithm(jwaAlgorithm); - } - - private Builder(JoseHeader headers) { - Assert.notNull(headers, "headers cannot be null"); - this.headers.putAll(headers.getHeaders()); - } - - /** - * Sets the {@link JwaAlgorithm JWA algorithm} used to digitally sign the JWS or encrypt the JWE. - * - * @param jwaAlgorithm the {@link JwaAlgorithm} - * @return the {@link Builder} - */ - public Builder algorithm(JwaAlgorithm jwaAlgorithm) { - Assert.notNull(jwaAlgorithm, "jwaAlgorithm cannot be null"); - return header(JoseHeaderNames.ALG, jwaAlgorithm); - } - - /** - * Sets the JWK Set URL that refers to the resource of a set of JSON-encoded public keys, - * one of which corresponds to the key used to digitally sign the JWS or encrypt the JWE. - * - * @param jwkSetUrl the JWK Set URL - * @return the {@link Builder} - */ - public Builder jwkSetUrl(String jwkSetUrl) { - return header(JoseHeaderNames.JKU, convertAsURL(JoseHeaderNames.JKU, jwkSetUrl)); - } - - /** - * Sets the JSON Web Key which is the public key that corresponds to the key - * used to digitally sign the JWS or encrypt the JWE. - * - * @param jwk the JSON Web Key - * @return the {@link Builder} - */ - public Builder jwk(Map jwk) { - return header(JoseHeaderNames.JWK, jwk); - } - - /** - * Sets the key ID that is a hint indicating which key was used to secure the JWS or JWE. - * - * @param keyId the key ID - * @return the {@link Builder} - */ - public Builder keyId(String keyId) { - return header(JoseHeaderNames.KID, keyId); - } - - /** - * Sets the X.509 URL that refers to the resource for the X.509 public key certificate - * or certificate chain corresponding to the key used to digitally sign the JWS or encrypt the JWE. - * - * @param x509Url the X.509 URL - * @return the {@link Builder} - */ - public Builder x509Url(String x509Url) { - return header(JoseHeaderNames.X5U, convertAsURL(JoseHeaderNames.X5U, x509Url)); - } - - /** - * Sets the X.509 certificate chain that contains the X.509 public key certificate - * or certificate chain corresponding to the key used to digitally sign the JWS or - * encrypt the JWE. The certificate or certificate chain is represented as a - * {@code List} of certificate value {@code String}s. Each {@code String} in the - * {@code List} is a Base64-encoded DER PKIX certificate value. - * - * @param x509CertificateChain the X.509 certificate chain - * @return the {@link Builder} - */ - public Builder x509CertificateChain(List x509CertificateChain) { - return header(JoseHeaderNames.X5C, x509CertificateChain); - } - - /** - * Sets the X.509 certificate SHA-1 thumbprint that is a base64url-encoded SHA-1 thumbprint (a.k.a. digest) - * of the DER encoding of the X.509 certificate corresponding to the key used to digitally sign the JWS or encrypt the JWE. - * - * @param x509SHA1Thumbprint the X.509 certificate SHA-1 thumbprint - * @return the {@link Builder} - */ - public Builder x509SHA1Thumbprint(String x509SHA1Thumbprint) { - return header(JoseHeaderNames.X5T, x509SHA1Thumbprint); - } - - /** - * Sets the X.509 certificate SHA-256 thumbprint that is a base64url-encoded SHA-256 thumbprint (a.k.a. digest) - * of the DER encoding of the X.509 certificate corresponding to the key used to digitally sign the JWS or encrypt the JWE. - * - * @param x509SHA256Thumbprint the X.509 certificate SHA-256 thumbprint - * @return the {@link Builder} - */ - public Builder x509SHA256Thumbprint(String x509SHA256Thumbprint) { - return header(JoseHeaderNames.X5T_S256, x509SHA256Thumbprint); - } - - /** - * Sets the type header that declares the media type of the JWS/JWE. - * - * @param type the type header - * @return the {@link Builder} - */ - public Builder type(String type) { - return header(JoseHeaderNames.TYP, type); - } - - /** - * Sets the content type header that declares the media type of the secured content (the payload). - * - * @param contentType the content type header - * @return the {@link Builder} - */ - public Builder contentType(String contentType) { - return header(JoseHeaderNames.CTY, contentType); - } - - /** - * Sets the critical headers that indicates which extensions to the JWS/JWE/JWA specifications - * are being used that MUST be understood and processed. - * - * @param headerNames the critical header names - * @return the {@link Builder} - */ - public Builder critical(Set headerNames) { - return header(JoseHeaderNames.CRIT, headerNames); - } - - /** - * Sets the header. - * - * @param name the header name - * @param value the header value - * @return the {@link Builder} - */ - public Builder header(String name, Object value) { - Assert.hasText(name, "name cannot be empty"); - Assert.notNull(value, "value cannot be null"); - this.headers.put(name, value); - return this; - } - - /** - * A {@code Consumer} to be provided access to the headers - * allowing the ability to add, replace, or remove. - * - * @param headersConsumer a {@code Consumer} of the headers - * @return the {@link Builder} - */ - public Builder headers(Consumer> headersConsumer) { - headersConsumer.accept(this.headers); - return this; - } - - /** - * Builds a new {@link JoseHeader}. - * - * @return a {@link JoseHeader} - */ - public JoseHeader build() { - Assert.notEmpty(this.headers, "headers cannot be empty"); - return new JoseHeader(this.headers); - } - - private static URL convertAsURL(String header, String value) { - URL convertedValue = ClaimConversionService.getSharedInstance().convert(value, URL.class); - Assert.isTrue(convertedValue != null, - () -> "Unable to convert header '" + header + "' of type '" + value.getClass() + "' to URL."); - return convertedValue; - } - - } -} diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JoseHeaderNames.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JoseHeaderNames.java deleted file mode 100644 index 4f63229a..00000000 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JoseHeaderNames.java +++ /dev/null @@ -1,101 +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 org.springframework.security.oauth2.jwt; - -/** - * The Registered Header Parameter Names defined by the JSON Web Token (JWT), - * JSON Web Signature (JWS) and JSON Web Encryption (JWE) specifications - * that may be contained in the JOSE Header of a JWT. - * - * @author Anoop Garlapati - * @author Joe Grandja - * @since 0.0.1 - * @see JoseHeader - * @see JWT JOSE Header - * @see JWS JOSE Header - * @see JWE JOSE Header - * @deprecated See gh-596 - */ -@Deprecated -public final class JoseHeaderNames { - - /** - * {@code alg} - the algorithm header identifies the cryptographic algorithm used to secure a JWS or JWE - */ - public static final String ALG = "alg"; - - /** - * {@code jku} - the JWK Set URL header is a URI that refers to a resource for a set of JSON-encoded public keys, - * one of which corresponds to the key used to digitally sign a JWS or encrypt a JWE - */ - public static final String JKU = "jku"; - - /** - * {@code jwk} - the JSON Web Key header is the public key that corresponds to the key - * used to digitally sign a JWS or encrypt a JWE - */ - public static final String JWK = "jwk"; - - /** - * {@code kid} - the key ID header is a hint indicating which key was used to secure a JWS or JWE - */ - public static final String KID = "kid"; - - /** - * {@code x5u} - the X.509 URL header is a URI that refers to a resource for the X.509 public key certificate - * or certificate chain corresponding to the key used to digitally sign a JWS or encrypt a JWE - */ - public static final String X5U = "x5u"; - - /** - * {@code x5c} - the X.509 certificate chain header contains the X.509 public key certificate - * or certificate chain corresponding to the key used to digitally sign a JWS or encrypt a JWE - */ - public static final String X5C = "x5c"; - - /** - * {@code x5t} - the X.509 certificate SHA-1 thumbprint header is a base64url-encoded SHA-1 thumbprint (a.k.a. digest) - * of the DER encoding of the X.509 certificate corresponding to the key used to digitally sign a JWS or encrypt a JWE - */ - public static final String X5T = "x5t"; - - /** - * {@code x5t#S256} - the X.509 certificate SHA-256 thumbprint header is a base64url-encoded SHA-256 thumbprint (a.k.a. digest) - * of the DER encoding of the X.509 certificate corresponding to the key used to digitally sign a JWS or encrypt a JWE - */ - public static final String X5T_S256 = "x5t#S256"; - - /** - * {@code typ} - the type header is used by JWS/JWE applications to declare the media type of a JWS/JWE - */ - public static final String TYP = "typ"; - - /** - * {@code cty} - the content type header is used by JWS/JWE applications to declare the media type - * of the secured content (the payload) - */ - public static final String CTY = "cty"; - - /** - * {@code crit} - the critical header indicates that extensions to the JWS/JWE/JWA specifications - * are being used that MUST be understood and processed - */ - public static final String CRIT = "crit"; - - private JoseHeaderNames() { - } - -} diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JwtClaimsSet.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JwtClaimsSet.java deleted file mode 100644 index b5648b1f..00000000 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JwtClaimsSet.java +++ /dev/null @@ -1,204 +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 org.springframework.security.oauth2.jwt; - -import java.net.URL; -import java.time.Instant; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; - -import org.springframework.security.oauth2.core.converter.ClaimConversionService; -import org.springframework.util.Assert; - -/** - * The {@link Jwt JWT} Claims Set is a JSON object representing the claims conveyed by a JSON Web Token. - * - * @author Anoop Garlapati - * @author Joe Grandja - * @since 0.0.1 - * @see Jwt - * @see JwtClaimAccessor - * @see JWT Claims Set - * @deprecated See gh-596 - */ -@Deprecated -public final class JwtClaimsSet implements JwtClaimAccessor { - private final Map claims; - - private JwtClaimsSet(Map claims) { - this.claims = Collections.unmodifiableMap(new HashMap<>(claims)); - } - - @Override - public Map getClaims() { - return this.claims; - } - - /** - * Returns a new {@link Builder}. - * - * @return the {@link Builder} - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Returns a new {@link Builder}, initialized with the provided {@code claims}. - * - * @param claims a JWT claims set - * @return the {@link Builder} - */ - public static Builder from(JwtClaimsSet claims) { - return new Builder(claims); - } - - /** - * A builder for {@link JwtClaimsSet}. - */ - public static final class Builder { - private final Map claims = new HashMap<>(); - - private Builder() { - } - - private Builder(JwtClaimsSet claims) { - Assert.notNull(claims, "claims cannot be null"); - this.claims.putAll(claims.getClaims()); - } - - /** - * Sets the issuer {@code (iss)} claim, which identifies the principal that issued the JWT. - * - * @param issuer the issuer identifier - * @return the {@link Builder} - */ - public Builder issuer(String issuer) { - return claim(JwtClaimNames.ISS, issuer); - } - - /** - * Sets the subject {@code (sub)} claim, which identifies the principal that is the subject of the JWT. - * - * @param subject the subject identifier - * @return the {@link Builder} - */ - public Builder subject(String subject) { - return claim(JwtClaimNames.SUB, subject); - } - - /** - * Sets the audience {@code (aud)} claim, which identifies the recipient(s) that the JWT is intended for. - * - * @param audience the audience that this JWT is intended for - * @return the {@link Builder} - */ - public Builder audience(List audience) { - return claim(JwtClaimNames.AUD, audience); - } - - /** - * Sets the expiration time {@code (exp)} claim, which identifies the time - * on or after which the JWT MUST NOT be accepted for processing. - * - * @param expiresAt the time on or after which the JWT MUST NOT be accepted for processing - * @return the {@link Builder} - */ - public Builder expiresAt(Instant expiresAt) { - return claim(JwtClaimNames.EXP, expiresAt); - } - - /** - * Sets the not before {@code (nbf)} claim, which identifies the time - * before which the JWT MUST NOT be accepted for processing. - * - * @param notBefore the time before which the JWT MUST NOT be accepted for processing - * @return the {@link Builder} - */ - public Builder notBefore(Instant notBefore) { - return claim(JwtClaimNames.NBF, notBefore); - } - - /** - * Sets the issued at {@code (iat)} claim, which identifies the time at which the JWT was issued. - * - * @param issuedAt the time at which the JWT was issued - * @return the {@link Builder} - */ - public Builder issuedAt(Instant issuedAt) { - return claim(JwtClaimNames.IAT, issuedAt); - } - - /** - * Sets the JWT ID {@code (jti)} claim, which provides a unique identifier for the JWT. - * - * @param jti the unique identifier for the JWT - * @return the {@link Builder} - */ - public Builder id(String jti) { - return claim(JwtClaimNames.JTI, jti); - } - - /** - * Sets the claim. - * - * @param name the claim name - * @param value the claim value - * @return the {@link Builder} - */ - public Builder claim(String name, Object value) { - Assert.hasText(name, "name cannot be empty"); - Assert.notNull(value, "value cannot be null"); - this.claims.put(name, value); - return this; - } - - /** - * A {@code Consumer} to be provided access to the claims - * allowing the ability to add, replace, or remove. - * - * @param claimsConsumer a {@code Consumer} of the claims - */ - public Builder claims(Consumer> claimsConsumer) { - claimsConsumer.accept(this.claims); - return this; - } - - /** - * Builds a new {@link JwtClaimsSet}. - * - * @return a {@link JwtClaimsSet} - */ - public JwtClaimsSet build() { - Assert.notEmpty(this.claims, "claims cannot be empty"); - - // The value of the 'iss' claim is a String or URL (StringOrURI). - // Attempt to convert to URL. - Object issuer = this.claims.get(JwtClaimNames.ISS); - if (issuer != null) { - URL convertedValue = ClaimConversionService.getSharedInstance().convert(issuer, URL.class); - if (convertedValue != null) { - this.claims.put(JwtClaimNames.ISS, convertedValue); - } - } - - return new JwtClaimsSet(this.claims); - } - } -} diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JwtEncoder.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JwtEncoder.java deleted file mode 100644 index 4fa6d5f0..00000000 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JwtEncoder.java +++ /dev/null @@ -1,56 +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 org.springframework.security.oauth2.jwt; - -/** - * Implementations of this interface are responsible for encoding - * a JSON Web Token (JWT) to it's compact claims representation format. - * - *

- * JWTs may be represented using the JWS Compact Serialization format for a - * JSON Web Signature (JWS) structure or JWE Compact Serialization format for a - * JSON Web Encryption (JWE) structure. Therefore, implementors are responsible - * for signing a JWS and/or encrypting a JWE. - * - * @author Anoop Garlapati - * @author Joe Grandja - * @since 0.0.1 - * @see Jwt - * @see JoseHeader - * @see JwtClaimsSet - * @see JwtDecoder - * @see JSON Web Token (JWT) - * @see JSON Web Signature (JWS) - * @see JSON Web Encryption (JWE) - * @see JWS Compact Serialization - * @see JWE Compact Serialization - * @deprecated See gh-596 - */ -@Deprecated -@FunctionalInterface -public interface JwtEncoder { - - /** - * Encode the JWT to it's compact claims representation format. - * - * @param headers the JOSE header - * @param claims the JWT Claims Set - * @return a {@link Jwt} - * @throws JwtEncodingException if an error occurs while attempting to encode the JWT - */ - Jwt encode(JoseHeader headers, JwtClaimsSet claims) throws JwtEncodingException; - -} diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JwtEncodingException.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JwtEncodingException.java deleted file mode 100644 index 6ea866d0..00000000 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/JwtEncodingException.java +++ /dev/null @@ -1,48 +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 org.springframework.security.oauth2.jwt; - -/** - * This exception is thrown when an error occurs - * while attempting to encode a JSON Web Token (JWT). - * - * @author Joe Grandja - * @since 0.0.1 - * @deprecated See gh-596 - */ -@Deprecated -public class JwtEncodingException extends JwtException { - - /** - * Constructs a {@code JwtEncodingException} using the provided parameters. - * - * @param message the detail message - */ - public JwtEncodingException(String message) { - super(message); - } - - /** - * Constructs a {@code JwtEncodingException} using the provided parameters. - * - * @param message the detail message - * @param cause the root cause - */ - public JwtEncodingException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwsEncoder.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwsEncoder.java deleted file mode 100644 index ec052dec..00000000 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/jwt/NimbusJwsEncoder.java +++ /dev/null @@ -1,344 +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 org.springframework.security.oauth2.jwt; - -import java.net.URI; -import java.net.URL; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import com.nimbusds.jose.JOSEException; -import com.nimbusds.jose.JOSEObjectType; -import com.nimbusds.jose.JWSAlgorithm; -import com.nimbusds.jose.JWSHeader; -import com.nimbusds.jose.JWSSigner; -import com.nimbusds.jose.crypto.factories.DefaultJWSSignerFactory; -import com.nimbusds.jose.jwk.JWK; -import com.nimbusds.jose.jwk.JWKMatcher; -import com.nimbusds.jose.jwk.JWKSelector; -import com.nimbusds.jose.jwk.KeyType; -import com.nimbusds.jose.jwk.KeyUse; -import com.nimbusds.jose.jwk.source.JWKSource; -import com.nimbusds.jose.proc.SecurityContext; -import com.nimbusds.jose.produce.JWSSignerFactory; -import com.nimbusds.jose.util.Base64; -import com.nimbusds.jose.util.Base64URL; -import com.nimbusds.jwt.JWTClaimsSet; -import com.nimbusds.jwt.SignedJWT; - -import org.springframework.core.convert.converter.Converter; -import org.springframework.util.Assert; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -/** - * An implementation of a {@link JwtEncoder} that encodes a JSON Web Token (JWT) using the - * JSON Web Signature (JWS) Compact Serialization format. The private/secret key used for - * signing the JWS is supplied by the {@code com.nimbusds.jose.jwk.source.JWKSource} - * provided via the constructor. - * - *

- * NOTE: This implementation uses the Nimbus JOSE + JWT SDK. - * - * @author Joe Grandja - * @since 0.0.1 - * @see JwtEncoder - * @see com.nimbusds.jose.jwk.source.JWKSource - * @see com.nimbusds.jose.jwk.JWK - * @see JSON Web Token (JWT) - * @see JSON Web Signature (JWS) - * @see JWS Compact Serialization - * @see Nimbus JOSE + JWT SDK - * @deprecated See gh-596 - */ -@Deprecated -public final class NimbusJwsEncoder implements JwtEncoder { - private static final String ENCODING_ERROR_MESSAGE_TEMPLATE = "An error occurred while attempting to encode the Jwt: %s"; - private static final Converter JWS_HEADER_CONVERTER = new JwsHeaderConverter(); - private static final Converter JWT_CLAIMS_SET_CONVERTER = new JwtClaimsSetConverter(); - private static final JWSSignerFactory JWS_SIGNER_FACTORY = new DefaultJWSSignerFactory(); - private final Map jwsSigners = new ConcurrentHashMap<>(); - private final JWKSource jwkSource; - - /** - * Constructs a {@code NimbusJwsEncoder} using the provided parameters. - * @param jwkSource the {@code com.nimbusds.jose.jwk.source.JWKSource} - */ - public NimbusJwsEncoder(JWKSource jwkSource) { - Assert.notNull(jwkSource, "jwkSource cannot be null"); - this.jwkSource = jwkSource; - } - - @Override - public Jwt encode(JoseHeader headers, JwtClaimsSet claims) throws JwtEncodingException { - Assert.notNull(headers, "headers cannot be null"); - Assert.notNull(claims, "claims cannot be null"); - - JWK jwk = selectJwk(headers); - headers = addKeyIdentifierHeadersIfNecessary(headers, jwk); - - String jws = serialize(headers, claims, jwk); - - return new Jwt(jws, claims.getIssuedAt(), claims.getExpiresAt(), headers.getHeaders(), claims.getClaims()); - } - - private JWK selectJwk(JoseHeader headers) { - List jwks; - try { - JWKSelector jwkSelector = new JWKSelector(createJwkMatcher(headers)); - jwks = this.jwkSource.get(jwkSelector, null); - } catch (Exception ex) { - throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, - "Failed to select a JWK signing key -> " + ex.getMessage()), ex); - } - - if (jwks.size() > 1) { - throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, - "Found multiple JWK signing keys for algorithm '" + headers.getAlgorithm().getName() + "'")); - } - - if (jwks.isEmpty()) { - throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, - "Failed to select a JWK signing key")); - } - - return jwks.get(0); - } - - private String serialize(JoseHeader headers, JwtClaimsSet claims, JWK jwk) { - JWSHeader jwsHeader = JWS_HEADER_CONVERTER.convert(headers); - JWTClaimsSet jwtClaimsSet = JWT_CLAIMS_SET_CONVERTER.convert(claims); - - JWSSigner jwsSigner = this.jwsSigners.computeIfAbsent(jwk, NimbusJwsEncoder::createSigner); - - SignedJWT signedJwt = new SignedJWT(jwsHeader, jwtClaimsSet); - try { - signedJwt.sign(jwsSigner); - } catch (JOSEException ex) { - throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, - "Failed to sign the JWT -> " + ex.getMessage()), ex); - } - return signedJwt.serialize(); - } - - private static JWKMatcher createJwkMatcher(JoseHeader headers) { - JWSAlgorithm jwsAlgorithm = JWSAlgorithm.parse(headers.getAlgorithm().getName()); - - if (JWSAlgorithm.Family.RSA.contains(jwsAlgorithm) || JWSAlgorithm.Family.EC.contains(jwsAlgorithm)) { - // @formatter:off - return new JWKMatcher.Builder() - .keyType(KeyType.forAlgorithm(jwsAlgorithm)) - .keyID(headers.getKeyId()) - .keyUses(KeyUse.SIGNATURE, null) - .algorithms(jwsAlgorithm, null) - .x509CertSHA256Thumbprint(Base64URL.from(headers.getX509SHA256Thumbprint())) - .build(); - // @formatter:on - } else if (JWSAlgorithm.Family.HMAC_SHA.contains(jwsAlgorithm)) { - // @formatter:off - return new JWKMatcher.Builder() - .keyType(KeyType.forAlgorithm(jwsAlgorithm)) - .keyID(headers.getKeyId()) - .privateOnly(true) - .algorithms(jwsAlgorithm, null) - .build(); - // @formatter:on - } - - return null; - } - - private static JoseHeader addKeyIdentifierHeadersIfNecessary(JoseHeader headers, JWK jwk) { - // Check if headers have already been added - if (StringUtils.hasText(headers.getKeyId()) && StringUtils.hasText(headers.getX509SHA256Thumbprint())) { - return headers; - } - // Check if headers can be added from JWK - if (!StringUtils.hasText(jwk.getKeyID()) && jwk.getX509CertSHA256Thumbprint() == null) { - return headers; - } - - JoseHeader.Builder headersBuilder = JoseHeader.from(headers); - if (!StringUtils.hasText(headers.getKeyId()) && StringUtils.hasText(jwk.getKeyID())) { - headersBuilder.keyId(jwk.getKeyID()); - } - if (!StringUtils.hasText(headers.getX509SHA256Thumbprint()) && jwk.getX509CertSHA256Thumbprint() != null) { - headersBuilder.x509SHA256Thumbprint(jwk.getX509CertSHA256Thumbprint().toString()); - } - - return headersBuilder.build(); - } - - private static JWSSigner createSigner(JWK jwk) { - try { - return JWS_SIGNER_FACTORY.createJWSSigner(jwk); - } catch (JOSEException ex) { - throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, - "Failed to create a JWS Signer -> " + ex.getMessage()), ex); - } - } - - private static class JwsHeaderConverter implements Converter { - - @Override - public JWSHeader convert(JoseHeader headers) { - JWSHeader.Builder builder = new JWSHeader.Builder(JWSAlgorithm.parse(headers.getAlgorithm().getName())); - - if (headers.getJwkSetUrl() != null) { - builder.jwkURL(convertAsURI(JoseHeaderNames.JKU, headers.getJwkSetUrl())); - } - - Map jwk = headers.getJwk(); - if (!CollectionUtils.isEmpty(jwk)) { - try { - builder.jwk(JWK.parse(jwk)); - } catch (Exception ex) { - throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, - "Unable to convert '" + JoseHeaderNames.JWK + "' JOSE header"), ex); - } - } - - String keyId = headers.getKeyId(); - if (StringUtils.hasText(keyId)) { - builder.keyID(keyId); - } - - if (headers.getX509Url() != null) { - builder.x509CertURL(convertAsURI(JoseHeaderNames.X5U, headers.getX509Url())); - } - - List x509CertificateChain = headers.getX509CertificateChain(); - if (!CollectionUtils.isEmpty(x509CertificateChain)) { - List x5cList = new ArrayList<>(); - x509CertificateChain.forEach((x5c) -> x5cList.add(new Base64(x5c))); - if (!x5cList.isEmpty()) { - builder.x509CertChain(x5cList); - } - } - - String x509SHA1Thumbprint = headers.getX509SHA1Thumbprint(); - if (StringUtils.hasText(x509SHA1Thumbprint)) { - builder.x509CertThumbprint(new Base64URL(x509SHA1Thumbprint)); - } - - String x509SHA256Thumbprint = headers.getX509SHA256Thumbprint(); - if (StringUtils.hasText(x509SHA256Thumbprint)) { - builder.x509CertSHA256Thumbprint(new Base64URL(x509SHA256Thumbprint)); - } - - String type = headers.getType(); - if (StringUtils.hasText(type)) { - builder.type(new JOSEObjectType(type)); - } - - String contentType = headers.getContentType(); - if (StringUtils.hasText(contentType)) { - builder.contentType(contentType); - } - - Set critical = headers.getCritical(); - if (!CollectionUtils.isEmpty(critical)) { - builder.criticalParams(critical); - } - - Map customHeaders = new HashMap<>(); - headers.getHeaders().forEach((name, value) -> { - if (!JWSHeader.getRegisteredParameterNames().contains(name)) { - customHeaders.put(name, value); - } - }); - if (!customHeaders.isEmpty()) { - builder.customParams(customHeaders); - } - - return builder.build(); - } - - private static URI convertAsURI(String header, URL url) { - try { - return url.toURI(); - } catch (Exception ex) { - throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, - "Unable to convert '" + header + "' JOSE header to a URI"), ex); - } - } - - } - - private static class JwtClaimsSetConverter implements Converter { - - @Override - public JWTClaimsSet convert(JwtClaimsSet claims) { - JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder(); - - // NOTE: The value of the 'iss' claim is a String or URL (StringOrURI). - Object issuer = claims.getClaim(JwtClaimNames.ISS); - if (issuer != null) { - builder.issuer(issuer.toString()); - } - - String subject = claims.getSubject(); - if (StringUtils.hasText(subject)) { - builder.subject(subject); - } - - List audience = claims.getAudience(); - if (!CollectionUtils.isEmpty(audience)) { - builder.audience(audience); - } - - Instant expiresAt = claims.getExpiresAt(); - if (expiresAt != null) { - builder.expirationTime(Date.from(expiresAt)); - } - - Instant notBefore = claims.getNotBefore(); - if (notBefore != null) { - builder.notBeforeTime(Date.from(notBefore)); - } - - Instant issuedAt = claims.getIssuedAt(); - if (issuedAt != null) { - builder.issueTime(Date.from(issuedAt)); - } - - String jwtId = claims.getId(); - if (StringUtils.hasText(jwtId)) { - builder.jwtID(jwtId); - } - - Map customClaims = new HashMap<>(); - claims.getClaims().forEach((name, value) -> { - if (!JWTClaimsSet.getRegisteredNames().contains(name)) { - customClaims.put(name, value); - } - }); - if (!customClaims.isEmpty()) { - customClaims.forEach(builder::claim); - } - - return builder.build(); - } - - } - -} diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/JwtEncodingContext.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/JwtEncodingContext.java index 41ff40d9..cfd5cbce 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/JwtEncodingContext.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/JwtEncodingContext.java @@ -21,10 +21,11 @@ import java.util.Map; import java.util.function.Consumer; import org.springframework.lang.Nullable; -import org.springframework.security.oauth2.jwt.JoseHeader; +import org.springframework.security.oauth2.jwt.JwsHeader; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtClaimsSet; import org.springframework.security.oauth2.jwt.JwtEncoder; +import org.springframework.security.oauth2.jwt.JwtEncoderParameters; import org.springframework.util.Assert; /** @@ -33,9 +34,9 @@ import org.springframework.util.Assert; * @author Joe Grandja * @since 0.1.0 * @see OAuth2TokenContext - * @see JoseHeader.Builder + * @see JwsHeader.Builder * @see JwtClaimsSet.Builder - * @see JwtEncoder#encode(JoseHeader, JwtClaimsSet) + * @see JwtEncoder#encode(JwtEncoderParameters) */ public final class JwtEncodingContext implements OAuth2TokenContext { private final Map context; @@ -58,13 +59,13 @@ public final class JwtEncodingContext implements OAuth2TokenContext { } /** - * Returns the {@link JoseHeader.Builder headers} + * Returns the {@link JwsHeader.Builder headers} * allowing the ability to add, replace, or remove. * - * @return the {@link JoseHeader.Builder} + * @return the {@link JwsHeader.Builder} */ - public JoseHeader.Builder getHeaders() { - return get(JoseHeader.Builder.class); + public JwsHeader.Builder getHeaders() { + return get(JwsHeader.Builder.class); } /** @@ -84,7 +85,7 @@ public final class JwtEncodingContext implements OAuth2TokenContext { * @param claimsBuilder the claims to initialize the builder * @return the {@link Builder} */ - public static Builder with(JoseHeader.Builder headersBuilder, JwtClaimsSet.Builder claimsBuilder) { + public static Builder with(JwsHeader.Builder headersBuilder, JwtClaimsSet.Builder claimsBuilder) { return new Builder(headersBuilder, claimsBuilder); } @@ -93,24 +94,24 @@ public final class JwtEncodingContext implements OAuth2TokenContext { */ public static final class Builder extends AbstractBuilder { - private Builder(JoseHeader.Builder headersBuilder, JwtClaimsSet.Builder claimsBuilder) { + private Builder(JwsHeader.Builder headersBuilder, JwtClaimsSet.Builder claimsBuilder) { Assert.notNull(headersBuilder, "headersBuilder cannot be null"); Assert.notNull(claimsBuilder, "claimsBuilder cannot be null"); - put(JoseHeader.Builder.class, headersBuilder); + put(JwsHeader.Builder.class, headersBuilder); put(JwtClaimsSet.Builder.class, claimsBuilder); } /** - * A {@code Consumer} of the {@link JoseHeader.Builder headers} + * A {@code Consumer} of the {@link JwsHeader.Builder headers} * allowing the ability to add, replace, or remove. * * @deprecated Use {@link #getHeaders()} instead - * @param headersConsumer a {@code Consumer} of the {@link JoseHeader.Builder headers} + * @param headersConsumer a {@code Consumer} of the {@link JwsHeader.Builder headers} * @return the {@link Builder} for further configuration */ @Deprecated - public Builder headers(Consumer headersConsumer) { - headersConsumer.accept(get(JoseHeader.Builder.class)); + public Builder headers(Consumer headersConsumer) { + headersConsumer.accept(get(JwsHeader.Builder.class)); return this; } diff --git a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/JwtGenerator.java b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/JwtGenerator.java index a66281e1..00be7daf 100644 --- a/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/JwtGenerator.java +++ b/oauth2-authorization-server/src/main/java/org/springframework/security/oauth2/server/authorization/token/JwtGenerator.java @@ -30,10 +30,11 @@ import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; import org.springframework.security.oauth2.core.oidc.OidcIdToken; 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.JwsHeader; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtClaimsSet; import org.springframework.security.oauth2.jwt.JwtEncoder; +import org.springframework.security.oauth2.jwt.JwtEncoderParameters; import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; import org.springframework.security.oauth2.server.authorization.OAuth2TokenContext; import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; @@ -127,7 +128,7 @@ public final class JwtGenerator implements OAuth2TokenGenerator { } // @formatter:on - JoseHeader.Builder headersBuilder = JoseHeader.withAlgorithm(SignatureAlgorithm.RS256); + JwsHeader.Builder headersBuilder = JwsHeader.with(SignatureAlgorithm.RS256); if (this.jwtCustomizer != null) { // @formatter:off @@ -150,10 +151,10 @@ public final class JwtGenerator implements OAuth2TokenGenerator { this.jwtCustomizer.customize(jwtContext); } - JoseHeader headers = headersBuilder.build(); + JwsHeader headers = headersBuilder.build(); JwtClaimsSet claims = claimsBuilder.build(); - Jwt jwt = this.jwtEncoder.encode(headers, claims); + Jwt jwt = this.jwtEncoder.encode(JwtEncoderParameters.from(headers, claims)); return jwt; } diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java index 3faebcea..3f982daf 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OAuth2AuthorizationCodeGrantTests.java @@ -81,7 +81,7 @@ import org.springframework.security.oauth2.jose.TestJwks; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtEncoder; -import org.springframework.security.oauth2.jwt.NimbusJwsEncoder; +import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator; import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationConsentService; import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService; @@ -161,7 +161,7 @@ public class OAuth2AuthorizationCodeGrantTests { private static EmbeddedDatabase db; private static JWKSource jwkSource; - private static NimbusJwsEncoder jwtEncoder; + private static NimbusJwtEncoder jwtEncoder; private static ProviderSettings providerSettings; private static HttpMessageConverter accessTokenHttpResponseConverter = new OAuth2AccessTokenResponseHttpMessageConverter(); @@ -197,7 +197,7 @@ public class OAuth2AuthorizationCodeGrantTests { public static void init() { JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK); jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); - jwtEncoder = new NimbusJwsEncoder(jwkSource); + jwtEncoder = new NimbusJwtEncoder(jwkSource); providerSettings = ProviderSettings.builder() .authorizationEndpoint("/test/authorize") .tokenEndpoint("/test/token") diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcClientRegistrationTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcClientRegistrationTests.java index 55063fa3..00dfc13f 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcClientRegistrationTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcClientRegistrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * 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. @@ -64,12 +64,13 @@ import org.springframework.security.oauth2.core.oidc.OidcClientRegistration; import org.springframework.security.oauth2.core.oidc.http.converter.OidcClientRegistrationHttpMessageConverter; import org.springframework.security.oauth2.jose.TestJwks; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; -import org.springframework.security.oauth2.jwt.JoseHeader; +import org.springframework.security.oauth2.jwt.JwsHeader; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtClaimsSet; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtEncoder; -import org.springframework.security.oauth2.jwt.NimbusJwsEncoder; +import org.springframework.security.oauth2.jwt.JwtEncoderParameters; +import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository; @@ -135,7 +136,7 @@ public class OidcClientRegistrationTests { JWKSet jwkSet = new JWKSet(TestJwks.DEFAULT_RSA_JWK); jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(jwkSet); clientJwkSet = new JWKSet(TestJwks.generateRsaJwk().build()); - jwtClientAssertionEncoder = new NimbusJwsEncoder((jwkSelector, securityContext) -> jwkSelector.select(clientJwkSet)); + jwtClientAssertionEncoder = new NimbusJwtEncoder((jwkSelector, securityContext) -> jwkSelector.select(clientJwkSet)); db = new EmbeddedDatabaseBuilder() .generateUniqueName(true) .setType(EmbeddedDatabaseType.HSQL) @@ -280,12 +281,12 @@ public class OidcClientRegistrationTests { this.registeredClientRepository.save(clientRegistrar); // @formatter:off - JoseHeader joseHeader = JoseHeader.withAlgorithm(SignatureAlgorithm.RS256) + JwsHeader jwsHeader = JwsHeader.with(SignatureAlgorithm.RS256) .build(); JwtClaimsSet jwtClaimsSet = jwtClientAssertionClaims(clientRegistrar) .build(); // @formatter:on - Jwt jwtAssertion = jwtClientAssertionEncoder.encode(joseHeader, jwtClaimsSet); + Jwt jwtAssertion = jwtClientAssertionEncoder.encode(JwtEncoderParameters.from(jwsHeader, jwtClaimsSet)); MvcResult mvcResult = this.mvc.perform(post(DEFAULT_TOKEN_ENDPOINT_URI) .param(OAuth2ParameterNames.GRANT_TYPE, AuthorizationGrantType.CLIENT_CREDENTIALS.getValue()) diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java index 809f8f93..c49744bd 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcTests.java @@ -69,17 +69,13 @@ import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames import org.springframework.security.oauth2.jose.TestJwks; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.jwt.NimbusJwsEncoder; -import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator; +import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; -import org.springframework.security.oauth2.server.authorization.token.JwtGenerator; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; -import org.springframework.security.oauth2.server.authorization.token.OAuth2RefreshTokenGenerator; import org.springframework.security.oauth2.server.authorization.OAuth2TokenContext; import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository; import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository.RegisteredClientParametersMapper; @@ -88,6 +84,10 @@ import org.springframework.security.oauth2.server.authorization.client.Registere import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; import org.springframework.security.oauth2.server.authorization.config.ProviderSettings; import org.springframework.security.oauth2.server.authorization.jackson2.TestingAuthenticationTokenMixin; +import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator; +import org.springframework.security.oauth2.server.authorization.token.JwtGenerator; +import org.springframework.security.oauth2.server.authorization.token.OAuth2RefreshTokenGenerator; +import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.test.web.servlet.MockMvc; @@ -415,7 +415,7 @@ public class OidcTests { @Bean OAuth2TokenGenerator tokenGenerator() { - JwtGenerator jwtGenerator = new JwtGenerator(new NimbusJwsEncoder(jwkSource())); + JwtGenerator jwtGenerator = new JwtGenerator(new NimbusJwtEncoder(jwkSource())); jwtGenerator.setJwtCustomizer(jwtCustomizer()); OAuth2RefreshTokenGenerator refreshTokenGenerator = new OAuth2RefreshTokenGenerator(); OAuth2TokenGenerator delegatingTokenGenerator = diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcUserInfoTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcUserInfoTests.java index d5336832..9c520bcd 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcUserInfoTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/authorization/OidcUserInfoTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * 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. @@ -45,12 +45,13 @@ import org.springframework.security.oauth2.core.oidc.OidcScopes; import org.springframework.security.oauth2.core.oidc.OidcUserInfo; import org.springframework.security.oauth2.jose.TestJwks; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; -import org.springframework.security.oauth2.jwt.JoseHeader; +import org.springframework.security.oauth2.jwt.JwsHeader; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtClaimsSet; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtEncoder; -import org.springframework.security.oauth2.jwt.NimbusJwsEncoder; +import org.springframework.security.oauth2.jwt.JwtEncoderParameters; +import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; import org.springframework.security.oauth2.server.authorization.InMemoryOAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; @@ -207,13 +208,13 @@ public class OidcUserInfoTests { } private OAuth2Authorization createAuthorization() { - JoseHeader headers = JoseHeader.withAlgorithm(SignatureAlgorithm.RS256).build(); + JwsHeader headers = JwsHeader.with(SignatureAlgorithm.RS256).build(); // @formatter:off JwtClaimsSet claimSet = JwtClaimsSet.builder() .claims(claims -> claims.putAll(createUserInfo().getClaims())) .build(); // @formatter:on - Jwt jwt = this.jwtEncoder.encode(headers, claimSet); + Jwt jwt = this.jwtEncoder.encode(JwtEncoderParameters.from(headers, claimSet)); Instant now = Instant.now(); Set scopes = new HashSet<>(Arrays.asList( @@ -371,7 +372,7 @@ public class OidcUserInfoTests { @Bean JwtEncoder jwtEncoder(JWKSource jwkSource) { - return new NimbusJwsEncoder(jwkSource); + return new NimbusJwtEncoder(jwkSource); } @Bean diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/JoseHeaderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/JoseHeaderTests.java deleted file mode 100644 index d4c85b4b..00000000 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/JoseHeaderTests.java +++ /dev/null @@ -1,108 +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.jwt; - -import org.junit.Test; - -import org.springframework.security.oauth2.jose.JwaAlgorithm; -import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -/** - * Tests for {@link JoseHeader}. - * - * @author Joe Grandja - */ -public class JoseHeaderTests { - - @Test - public void withAlgorithmWhenNullThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> JoseHeader.withAlgorithm(null)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("jwaAlgorithm cannot be null"); - } - - @Test - public void buildWhenAllHeadersProvidedThenAllHeadersAreSet() { - JoseHeader expectedJoseHeader = TestJoseHeaders.joseHeader().build(); - - JoseHeader joseHeader = JoseHeader.withAlgorithm(expectedJoseHeader.getAlgorithm()) - .jwkSetUrl(expectedJoseHeader.getJwkSetUrl().toExternalForm()) - .jwk(expectedJoseHeader.getJwk()) - .keyId(expectedJoseHeader.getKeyId()) - .x509Url(expectedJoseHeader.getX509Url().toExternalForm()) - .x509CertificateChain(expectedJoseHeader.getX509CertificateChain()) - .x509SHA1Thumbprint(expectedJoseHeader.getX509SHA1Thumbprint()) - .x509SHA256Thumbprint(expectedJoseHeader.getX509SHA256Thumbprint()) - .type(expectedJoseHeader.getType()) - .contentType(expectedJoseHeader.getContentType()) - .headers(headers -> headers.put("custom-header-name", "custom-header-value")) - .build(); - - assertThat(joseHeader.getAlgorithm()).isEqualTo(expectedJoseHeader.getAlgorithm()); - assertThat(joseHeader.getJwkSetUrl()).isEqualTo(expectedJoseHeader.getJwkSetUrl()); - assertThat(joseHeader.getJwk()).isEqualTo(expectedJoseHeader.getJwk()); - assertThat(joseHeader.getKeyId()).isEqualTo(expectedJoseHeader.getKeyId()); - assertThat(joseHeader.getX509Url()).isEqualTo(expectedJoseHeader.getX509Url()); - assertThat(joseHeader.getX509CertificateChain()).isEqualTo(expectedJoseHeader.getX509CertificateChain()); - assertThat(joseHeader.getX509SHA1Thumbprint()).isEqualTo(expectedJoseHeader.getX509SHA1Thumbprint()); - assertThat(joseHeader.getX509SHA256Thumbprint()).isEqualTo(expectedJoseHeader.getX509SHA256Thumbprint()); - assertThat(joseHeader.getCritical()).isEqualTo(expectedJoseHeader.getCritical()); - assertThat(joseHeader.getType()).isEqualTo(expectedJoseHeader.getType()); - assertThat(joseHeader.getContentType()).isEqualTo(expectedJoseHeader.getContentType()); - assertThat(joseHeader.getHeader("custom-header-name")).isEqualTo("custom-header-value"); - assertThat(joseHeader.getHeaders()).isEqualTo(expectedJoseHeader.getHeaders()); - } - - @Test - public void fromWhenNullThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> JoseHeader.from(null)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("headers cannot be null"); - } - - @Test - public void fromWhenHeadersProvidedThenCopied() { - JoseHeader expectedJoseHeader = TestJoseHeaders.joseHeader().build(); - JoseHeader joseHeader = JoseHeader.from(expectedJoseHeader).build(); - assertThat(joseHeader.getHeaders()).isEqualTo(expectedJoseHeader.getHeaders()); - } - - @Test - public void headerWhenNameNullThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> JoseHeader.withAlgorithm(SignatureAlgorithm.RS256).header(null, "value")) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("name cannot be empty"); - } - - @Test - public void headerWhenValueNullThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> JoseHeader.withAlgorithm(SignatureAlgorithm.RS256).header("name", null)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("value cannot be null"); - } - - @Test - public void getHeaderWhenNullThenThrowIllegalArgumentException() { - JoseHeader joseHeader = TestJoseHeaders.joseHeader().build(); - - assertThatThrownBy(() -> joseHeader.getHeader(null)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("name cannot be empty"); - } -} diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/JwtClaimsSetTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/JwtClaimsSetTests.java deleted file mode 100644 index 4319ac16..00000000 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/JwtClaimsSetTests.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2020 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.jwt; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -/** - * Tests for {@link JwtClaimsSet}. - * - * @author Joe Grandja - */ -public class JwtClaimsSetTests { - - @Test - public void buildWhenClaimsEmptyThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> JwtClaimsSet.builder().build()) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("claims cannot be empty"); - } - - @Test - public void buildWhenAllClaimsProvidedThenAllClaimsAreSet() { - JwtClaimsSet expectedJwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build(); - - JwtClaimsSet jwtClaimsSet = JwtClaimsSet.builder() - .issuer(expectedJwtClaimsSet.getIssuer().toExternalForm()) - .subject(expectedJwtClaimsSet.getSubject()) - .audience(expectedJwtClaimsSet.getAudience()) - .issuedAt(expectedJwtClaimsSet.getIssuedAt()) - .notBefore(expectedJwtClaimsSet.getNotBefore()) - .expiresAt(expectedJwtClaimsSet.getExpiresAt()) - .id(expectedJwtClaimsSet.getId()) - .claims(claims -> claims.put("custom-claim-name", "custom-claim-value")) - .build(); - - assertThat(jwtClaimsSet.getIssuer()).isEqualTo(expectedJwtClaimsSet.getIssuer()); - assertThat(jwtClaimsSet.getSubject()).isEqualTo(expectedJwtClaimsSet.getSubject()); - assertThat(jwtClaimsSet.getAudience()).isEqualTo(expectedJwtClaimsSet.getAudience()); - assertThat(jwtClaimsSet.getIssuedAt()).isEqualTo(expectedJwtClaimsSet.getIssuedAt()); - assertThat(jwtClaimsSet.getNotBefore()).isEqualTo(expectedJwtClaimsSet.getNotBefore()); - assertThat(jwtClaimsSet.getExpiresAt()).isEqualTo(expectedJwtClaimsSet.getExpiresAt()); - assertThat(jwtClaimsSet.getId()).isEqualTo(expectedJwtClaimsSet.getId()); - assertThat(jwtClaimsSet.getClaim("custom-claim-name")).isEqualTo("custom-claim-value"); - assertThat(jwtClaimsSet.getClaims()).isEqualTo(expectedJwtClaimsSet.getClaims()); - } - - @Test - public void fromWhenNullThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> JwtClaimsSet.from(null)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("claims cannot be null"); - } - - @Test - public void fromWhenClaimsProvidedThenCopied() { - JwtClaimsSet expectedJwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build(); - JwtClaimsSet jwtClaimsSet = JwtClaimsSet.from(expectedJwtClaimsSet).build(); - assertThat(jwtClaimsSet.getClaims()).isEqualTo(expectedJwtClaimsSet.getClaims()); - } - - @Test - public void claimWhenNameNullThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> JwtClaimsSet.builder().claim(null, "value")) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("name cannot be empty"); - } - - @Test - public void claimWhenValueNullThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> JwtClaimsSet.builder().claim("name", null)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("value cannot be null"); - } -} diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwsEncoderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwsEncoderTests.java deleted file mode 100644 index 574cc75f..00000000 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/NimbusJwsEncoderTests.java +++ /dev/null @@ -1,275 +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.jwt; - -import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import com.nimbusds.jose.KeySourceException; -import com.nimbusds.jose.jwk.ECKey; -import com.nimbusds.jose.jwk.JWK; -import com.nimbusds.jose.jwk.JWKSelector; -import com.nimbusds.jose.jwk.JWKSet; -import com.nimbusds.jose.jwk.KeyUse; -import com.nimbusds.jose.jwk.OctetSequenceKey; -import com.nimbusds.jose.jwk.RSAKey; -import com.nimbusds.jose.jwk.source.JWKSource; -import com.nimbusds.jose.proc.SecurityContext; -import org.junit.Before; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import org.springframework.security.oauth2.jose.TestJwks; -import org.springframework.security.oauth2.jose.TestKeys; -import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.willAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; - -/** - * Tests for {@link NimbusJwsEncoder}. - * - * @author Joe Grandja - */ -public class NimbusJwsEncoderTests { - - private List jwkList; - - private JWKSource jwkSource; - - private NimbusJwsEncoder jwsEncoder; - - @Before - public void setUp() { - this.jwkList = new ArrayList<>(); - this.jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(new JWKSet(this.jwkList)); - this.jwsEncoder = new NimbusJwsEncoder(this.jwkSource); - } - - @Test - public void constructorWhenJwkSourceNullThenThrowIllegalArgumentException() { - assertThatIllegalArgumentException().isThrownBy(() -> new NimbusJwsEncoder(null)) - .withMessage("jwkSource cannot be null"); - } - - @Test - public void encodeWhenHeadersNullThenThrowIllegalArgumentException() { - JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build(); - - assertThatIllegalArgumentException().isThrownBy(() -> this.jwsEncoder.encode(null, jwtClaimsSet)) - .withMessage("headers cannot be null"); - } - - @Test - public void encodeWhenClaimsNullThenThrowIllegalArgumentException() { - JoseHeader joseHeader = TestJoseHeaders.joseHeader().build(); - - assertThatIllegalArgumentException().isThrownBy(() -> this.jwsEncoder.encode(joseHeader, null)) - .withMessage("claims cannot be null"); - } - - @Test - public void encodeWhenJwkSelectFailedThenThrowJwtEncodingException() throws Exception { - this.jwkSource = mock(JWKSource.class); - this.jwsEncoder = new NimbusJwsEncoder(this.jwkSource); - given(this.jwkSource.get(any(), any())).willThrow(new KeySourceException("key source error")); - - JoseHeader joseHeader = TestJoseHeaders.joseHeader().build(); - JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build(); - - assertThatExceptionOfType(JwtEncodingException.class) - .isThrownBy(() -> this.jwsEncoder.encode(joseHeader, jwtClaimsSet)) - .withMessageContaining("Failed to select a JWK signing key -> key source error"); - } - - @Test - public void encodeWhenJwkMultipleSelectedThenThrowJwtEncodingException() throws Exception { - RSAKey rsaJwk = TestJwks.DEFAULT_RSA_JWK; - this.jwkList.add(rsaJwk); - this.jwkList.add(rsaJwk); - - JoseHeader joseHeader = JoseHeader.withAlgorithm(SignatureAlgorithm.RS256).build(); - JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build(); - - assertThatExceptionOfType(JwtEncodingException.class) - .isThrownBy(() -> this.jwsEncoder.encode(joseHeader, jwtClaimsSet)) - .withMessageContaining("Found multiple JWK signing keys for algorithm 'RS256'"); - } - - @Test - public void encodeWhenJwkSelectEmptyThenThrowJwtEncodingException() { - JoseHeader joseHeader = TestJoseHeaders.joseHeader().build(); - JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build(); - - assertThatExceptionOfType(JwtEncodingException.class) - .isThrownBy(() -> this.jwsEncoder.encode(joseHeader, jwtClaimsSet)) - .withMessageContaining("Failed to select a JWK signing key"); - } - - @Test - public void encodeWhenJwkUseEncryptionThenThrowJwtEncodingException() throws Exception { - // @formatter:off - RSAKey rsaJwk = TestJwks.jwk(TestKeys.DEFAULT_PUBLIC_KEY, TestKeys.DEFAULT_PRIVATE_KEY) - .keyUse(KeyUse.ENCRYPTION) - .build(); - // @formatter:on - - this.jwkSource = mock(JWKSource.class); - this.jwsEncoder = new NimbusJwsEncoder(this.jwkSource); - given(this.jwkSource.get(any(), any())).willReturn(Collections.singletonList(rsaJwk)); - - JoseHeader joseHeader = TestJoseHeaders.joseHeader().build(); - JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build(); - - assertThatExceptionOfType(JwtEncodingException.class) - .isThrownBy(() -> this.jwsEncoder.encode(joseHeader, jwtClaimsSet)).withMessageContaining( - "Failed to create a JWS Signer -> The JWK use must be sig (signature) or unspecified"); - } - - @Test - public void encodeWhenSuccessThenDecodes() throws Exception { - RSAKey rsaJwk = TestJwks.DEFAULT_RSA_JWK; - this.jwkList.add(rsaJwk); - - JoseHeader joseHeader = JoseHeader.withAlgorithm(SignatureAlgorithm.RS256).build(); - JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build(); - - Jwt encodedJws = this.jwsEncoder.encode(joseHeader, jwtClaimsSet); - - assertThat(encodedJws.getHeaders().get(JoseHeaderNames.ALG)).isEqualTo(joseHeader.getAlgorithm()); - assertThat(encodedJws.getHeaders().get(JoseHeaderNames.JKU)).isNull(); - assertThat(encodedJws.getHeaders().get(JoseHeaderNames.JWK)).isNull(); - assertThat(encodedJws.getHeaders().get(JoseHeaderNames.KID)).isEqualTo(rsaJwk.getKeyID()); - assertThat(encodedJws.getHeaders().get(JoseHeaderNames.X5U)).isNull(); - assertThat(encodedJws.getHeaders().get(JoseHeaderNames.X5C)).isNull(); - assertThat(encodedJws.getHeaders().get(JoseHeaderNames.X5T)).isNull(); - assertThat(encodedJws.getHeaders().get(JoseHeaderNames.X5T_S256)).isNull(); - assertThat(encodedJws.getHeaders().get(JoseHeaderNames.TYP)).isNull(); - assertThat(encodedJws.getHeaders().get(JoseHeaderNames.CTY)).isNull(); - assertThat(encodedJws.getHeaders().get(JoseHeaderNames.CRIT)).isNull(); - - assertThat(encodedJws.getIssuer()).isEqualTo(jwtClaimsSet.getIssuer()); - assertThat(encodedJws.getSubject()).isEqualTo(jwtClaimsSet.getSubject()); - assertThat(encodedJws.getAudience()).isEqualTo(jwtClaimsSet.getAudience()); - assertThat(encodedJws.getExpiresAt()).isEqualTo(jwtClaimsSet.getExpiresAt()); - assertThat(encodedJws.getNotBefore()).isEqualTo(jwtClaimsSet.getNotBefore()); - assertThat(encodedJws.getIssuedAt()).isEqualTo(jwtClaimsSet.getIssuedAt()); - assertThat(encodedJws.getId()).isEqualTo(jwtClaimsSet.getId()); - assertThat(encodedJws.getClaim("custom-claim-name")).isEqualTo("custom-claim-value"); - - NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withPublicKey(rsaJwk.toRSAPublicKey()).build(); - jwtDecoder.decode(encodedJws.getTokenValue()); - } - - @Test - public void encodeWhenKeysRotatedThenNewKeyUsed() throws Exception { - TestJWKSource jwkSource = new TestJWKSource(); - JWKSource jwkSourceDelegate = spy(new JWKSource() { - @Override - public List get(JWKSelector jwkSelector, SecurityContext context) { - return jwkSource.get(jwkSelector, context); - } - }); - NimbusJwsEncoder jwsEncoder = new NimbusJwsEncoder(jwkSourceDelegate); - - JwkListResultCaptor jwkListResultCaptor = new JwkListResultCaptor(); - willAnswer(jwkListResultCaptor).given(jwkSourceDelegate).get(any(), any()); - - JoseHeader joseHeader = JoseHeader.withAlgorithm(SignatureAlgorithm.RS256).build(); - JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet().build(); - - Jwt encodedJws = jwsEncoder.encode(joseHeader, jwtClaimsSet); - - JWK jwk1 = jwkListResultCaptor.getResult().get(0); - NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withPublicKey(((RSAKey) jwk1).toRSAPublicKey()).build(); - jwtDecoder.decode(encodedJws.getTokenValue()); - - jwkSource.rotate(); // Trigger key rotation - - encodedJws = jwsEncoder.encode(joseHeader, jwtClaimsSet); - - JWK jwk2 = jwkListResultCaptor.getResult().get(0); - jwtDecoder = NimbusJwtDecoder.withPublicKey(((RSAKey) jwk2).toRSAPublicKey()).build(); - jwtDecoder.decode(encodedJws.getTokenValue()); - - assertThat(jwk1.getKeyID()).isNotEqualTo(jwk2.getKeyID()); - } - - private static final class JwkListResultCaptor implements Answer> { - - private List result; - - private List getResult() { - return this.result; - } - - @SuppressWarnings("unchecked") - @Override - public List answer(InvocationOnMock invocationOnMock) throws Throwable { - this.result = (List) invocationOnMock.callRealMethod(); - return this.result; - } - - } - - private static final class TestJWKSource implements JWKSource { - - private int keyId = 1000; - - private JWKSet jwkSet; - - private TestJWKSource() { - init(); - } - - @Override - public List get(JWKSelector jwkSelector, SecurityContext context) { - return jwkSelector.select(this.jwkSet); - } - - private void init() { - // @formatter:off - RSAKey rsaJwk = TestJwks.jwk(TestKeys.DEFAULT_PUBLIC_KEY, TestKeys.DEFAULT_PRIVATE_KEY) - .keyID("rsa-jwk-" + this.keyId++) - .build(); - ECKey ecJwk = TestJwks.jwk((ECPublicKey) TestKeys.DEFAULT_EC_KEY_PAIR.getPublic(), (ECPrivateKey) TestKeys.DEFAULT_EC_KEY_PAIR.getPrivate()) - .keyID("ec-jwk-" + this.keyId++) - .build(); - OctetSequenceKey secretJwk = TestJwks.jwk(TestKeys.DEFAULT_SECRET_KEY) - .keyID("secret-jwk-" + this.keyId++) - .build(); - // @formatter:on - this.jwkSet = new JWKSet(Arrays.asList(rsaJwk, ecJwk, secretJwk)); - } - - private void rotate() { - init(); - } - - } - -} diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/TestJoseHeaders.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/TestJwsHeaders.java similarity index 80% rename from oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/TestJoseHeaders.java rename to oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/TestJwsHeaders.java index 6db49a54..da0939b6 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/TestJoseHeaders.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/jwt/TestJwsHeaders.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * 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. @@ -24,18 +24,18 @@ import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; /** * @author Joe Grandja */ -public final class TestJoseHeaders { +public final class TestJwsHeaders { - private TestJoseHeaders() { + private TestJwsHeaders() { } - public static JoseHeader.Builder joseHeader() { - return joseHeader(SignatureAlgorithm.RS256); + public static JwsHeader.Builder jwsHeader() { + return jwsHeader(SignatureAlgorithm.RS256); } - public static JoseHeader.Builder joseHeader(SignatureAlgorithm signatureAlgorithm) { + public static JwsHeader.Builder jwsHeader(SignatureAlgorithm signatureAlgorithm) { // @formatter:off - return JoseHeader.withAlgorithm(signatureAlgorithm) + return JwsHeader.with(signatureAlgorithm) .jwkSetUrl("https://provider.com/oauth2/jwks") .jwk(rsaJwk()) .keyId("keyId") diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/JwtEncodingContextTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/JwtEncodingContextTests.java index f6eefdef..ea2696ee 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/JwtEncodingContextTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/JwtEncodingContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * 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. @@ -23,9 +23,9 @@ import org.springframework.security.oauth2.core.AuthorizationGrantType; import org.springframework.security.oauth2.core.ClientAuthenticationMethod; import org.springframework.security.oauth2.core.OAuth2TokenType; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; -import org.springframework.security.oauth2.jwt.JoseHeader; +import org.springframework.security.oauth2.jwt.JwsHeader; import org.springframework.security.oauth2.jwt.JwtClaimsSet; -import org.springframework.security.oauth2.jwt.TestJoseHeaders; +import org.springframework.security.oauth2.jwt.TestJwsHeaders; import org.springframework.security.oauth2.jwt.TestJwtClaimsSets; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationToken; import org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationGrantAuthenticationToken; @@ -52,7 +52,7 @@ public class JwtEncodingContextTests { @Test public void withWhenClaimsNullThenThrowIllegalArgumentException() { - assertThatThrownBy(() -> JwtEncodingContext.with(TestJoseHeaders.joseHeader(), null)) + assertThatThrownBy(() -> JwtEncodingContext.with(TestJwsHeaders.jwsHeader(), null)) .isInstanceOf(IllegalArgumentException.class) .hasMessage("claimsBuilder cannot be null"); } @@ -60,7 +60,7 @@ public class JwtEncodingContextTests { @Test public void setWhenValueNullThenThrowIllegalArgumentException() { JwtEncodingContext.Builder builder = JwtEncodingContext - .with(TestJoseHeaders.joseHeader(), TestJwtClaimsSets.jwtClaimsSet()); + .with(TestJwsHeaders.jwsHeader(), TestJwtClaimsSets.jwtClaimsSet()); assertThatThrownBy(() -> builder.registeredClient(null)) .isInstanceOf(IllegalArgumentException.class); assertThatThrownBy(() -> builder.principal(null)) @@ -79,7 +79,7 @@ public class JwtEncodingContextTests { @Test public void buildWhenAllValuesProvidedThenAllValuesAreSet() { - JoseHeader.Builder headers = TestJoseHeaders.joseHeader(); + JwsHeader.Builder headers = TestJwsHeaders.jwsHeader(); JwtClaimsSet.Builder claims = TestJwtClaimsSets.jwtClaimsSet(); RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); TestingAuthenticationToken principal = new TestingAuthenticationToken("principal", "password"); diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/JwtClientAssertionAuthenticationProviderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/JwtClientAssertionAuthenticationProviderTests.java index 1e7c966d..7d55fa1c 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/JwtClientAssertionAuthenticationProviderTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/JwtClientAssertionAuthenticationProviderTests.java @@ -44,12 +44,13 @@ import org.springframework.security.oauth2.jose.TestKeys; import org.springframework.security.oauth2.jose.jws.MacAlgorithm; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import org.springframework.security.oauth2.jwt.BadJwtException; -import org.springframework.security.oauth2.jwt.JoseHeader; +import org.springframework.security.oauth2.jwt.JwsHeader; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtClaimsSet; import org.springframework.security.oauth2.jwt.JwtEncoder; +import org.springframework.security.oauth2.jwt.JwtEncoderParameters; import org.springframework.security.oauth2.jwt.JwtValidationException; -import org.springframework.security.oauth2.jwt.NimbusJwsEncoder; +import org.springframework.security.oauth2.jwt.NimbusJwtEncoder; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; @@ -303,7 +304,7 @@ public class JwtClientAssertionAuthenticationProviderTests { .thenReturn(registeredClient); // @formatter:off - JoseHeader joseHeader = JoseHeader.withAlgorithm(MacAlgorithm.HS256) + JwsHeader jwsHeader = JwsHeader.with(MacAlgorithm.HS256) .build(); JwtClaimsSet jwtClaimsSet = JwtClaimsSet.builder() .issuer("invalid-iss") @@ -313,7 +314,7 @@ public class JwtClientAssertionAuthenticationProviderTests { // @formatter:on JwtEncoder jwsEncoder = createEncoder(TestKeys.DEFAULT_ENCODED_SECRET_KEY, "HmacSHA256"); - Jwt jwtAssertion = jwsEncoder.encode(joseHeader, jwtClaimsSet); + Jwt jwtAssertion = jwsEncoder.encode(JwtEncoderParameters.from(jwsHeader, jwtClaimsSet)); OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken( registeredClient.getClientId(), JWT_CLIENT_ASSERTION_AUTHENTICATION_METHOD, jwtAssertion.getTokenValue(), null); @@ -346,14 +347,14 @@ public class JwtClientAssertionAuthenticationProviderTests { .thenReturn(registeredClient); // @formatter:off - JoseHeader joseHeader = JoseHeader.withAlgorithm(MacAlgorithm.HS256) + JwsHeader jwsHeader = JwsHeader.with(MacAlgorithm.HS256) .build(); JwtClaimsSet jwtClaimsSet = jwtClientAssertionClaims(registeredClient) .build(); // @formatter:on JwtEncoder jwsEncoder = createEncoder(TestKeys.DEFAULT_ENCODED_SECRET_KEY, "HmacSHA256"); - Jwt jwtAssertion = jwsEncoder.encode(joseHeader, jwtClaimsSet); + Jwt jwtAssertion = jwsEncoder.encode(JwtEncoderParameters.from(jwsHeader, jwtClaimsSet)); OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken( registeredClient.getClientId(), JWT_CLIENT_ASSERTION_AUTHENTICATION_METHOD, jwtAssertion.getTokenValue(), null); @@ -392,14 +393,14 @@ public class JwtClientAssertionAuthenticationProviderTests { Map parameters = createPkceTokenParameters(S256_CODE_VERIFIER); // @formatter:off - JoseHeader joseHeader = JoseHeader.withAlgorithm(MacAlgorithm.HS256) + JwsHeader jwsHeader = JwsHeader.with(MacAlgorithm.HS256) .build(); JwtClaimsSet jwtClaimsSet = jwtClientAssertionClaims(registeredClient) .build(); // @formatter:on JwtEncoder jwsEncoder = createEncoder(TestKeys.DEFAULT_ENCODED_SECRET_KEY, "HmacSHA256"); - Jwt jwtAssertion = jwsEncoder.encode(joseHeader, jwtClaimsSet); + Jwt jwtAssertion = jwsEncoder.encode(JwtEncoderParameters.from(jwsHeader, jwtClaimsSet)); OAuth2ClientAuthenticationToken authentication = new OAuth2ClientAuthenticationToken( registeredClient.getClientId(), JWT_CLIENT_ASSERTION_AUTHENTICATION_METHOD, jwtAssertion.getTokenValue(), parameters); @@ -430,7 +431,7 @@ public class JwtClientAssertionAuthenticationProviderTests { OctetSequenceKey secretKeyJwk = TestJwks.jwk(secretKey).build(); JWKSource jwkSource = (jwkSelector, securityContext) -> jwkSelector.select(new JWKSet(secretKeyJwk)); - return new NimbusJwsEncoder(jwkSource); + return new NimbusJwtEncoder(jwkSource); } private static String asUrl(String uri, String path) { diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java index 6923d522..5176ac2c 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2AuthorizationCodeAuthenticationProviderTests.java @@ -50,17 +50,12 @@ import org.springframework.security.oauth2.jwt.JoseHeaderNames; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtClaimsSet; import org.springframework.security.oauth2.jwt.JwtEncoder; -import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator; +import org.springframework.security.oauth2.jwt.JwtEncoderParameters; import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; -import org.springframework.security.oauth2.server.authorization.token.JwtGenerator; -import org.springframework.security.oauth2.server.authorization.token.OAuth2AccessTokenGenerator; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; -import org.springframework.security.oauth2.server.authorization.token.OAuth2RefreshTokenGenerator; -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext; import org.springframework.security.oauth2.server.authorization.OAuth2TokenContext; import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; @@ -68,6 +63,12 @@ import org.springframework.security.oauth2.server.authorization.config.ProviderS import org.springframework.security.oauth2.server.authorization.config.TokenSettings; import org.springframework.security.oauth2.server.authorization.context.ProviderContext; import org.springframework.security.oauth2.server.authorization.context.ProviderContextHolder; +import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator; +import org.springframework.security.oauth2.server.authorization.token.JwtGenerator; +import org.springframework.security.oauth2.server.authorization.token.OAuth2AccessTokenGenerator; +import org.springframework.security.oauth2.server.authorization.token.OAuth2RefreshTokenGenerator; +import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext; +import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -351,7 +352,7 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { OAuth2AuthorizationCodeAuthenticationToken authentication = new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null); - when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt()); + when(this.jwtEncoder.encode(any())).thenReturn(createJwt()); doAnswer(answer -> { OAuth2TokenContext context = answer.getArgument(0); @@ -385,7 +386,7 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { OAuth2AuthorizationCodeAuthenticationToken authentication = new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null); - when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt()); + when(this.jwtEncoder.encode(any())).thenReturn(createJwt()); doAnswer(answer -> { OAuth2TokenContext context = answer.getArgument(0); @@ -419,7 +420,7 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { OAuth2AuthorizationCodeAuthenticationToken authentication = new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null); - when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt()); + when(this.jwtEncoder.encode(any())).thenReturn(createJwt()); OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) this.authenticationProvider.authenticate(authentication); @@ -438,9 +439,9 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { assertThat(jwtEncodingContext.getHeaders()).isNotNull(); assertThat(jwtEncodingContext.getClaims()).isNotNull(); - ArgumentCaptor jwtClaimsSetCaptor = ArgumentCaptor.forClass(JwtClaimsSet.class); - verify(this.jwtEncoder).encode(any(), jwtClaimsSetCaptor.capture()); - JwtClaimsSet jwtClaimsSet = jwtClaimsSetCaptor.getValue(); + ArgumentCaptor jwtEncoderParametersCaptor = ArgumentCaptor.forClass(JwtEncoderParameters.class); + verify(this.jwtEncoder).encode(jwtEncoderParametersCaptor.capture()); + JwtClaimsSet jwtClaimsSet = jwtEncoderParametersCaptor.getValue().getClaims(); Set scopes = jwtClaimsSet.getClaim(OAuth2ParameterNames.SCOPE); assertThat(scopes).isEqualTo(authorization.getAttribute(OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME)); @@ -475,7 +476,7 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { OAuth2AuthorizationCodeAuthenticationToken authentication = new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null); - when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt()); + when(this.jwtEncoder.encode(any())).thenReturn(createJwt()); OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) this.authenticationProvider.authenticate(authentication); @@ -511,7 +512,7 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { assertThat(idTokenContext.getHeaders()).isNotNull(); assertThat(idTokenContext.getClaims()).isNotNull(); - verify(this.jwtEncoder, times(2)).encode(any(), any()); // Access token and ID Token + verify(this.jwtEncoder, times(2)).encode(any()); // Access token and ID Token ArgumentCaptor authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class); verify(this.authorizationService).save(authorizationCaptor.capture()); @@ -549,7 +550,7 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { OAuth2AuthorizationCodeAuthenticationToken authentication = new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null); - when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt()); + when(this.jwtEncoder.encode(any())).thenReturn(createJwt()); OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) this.authenticationProvider.authenticate(authentication); @@ -568,9 +569,9 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { assertThat(jwtEncodingContext.getHeaders()).isNotNull(); assertThat(jwtEncodingContext.getClaims()).isNotNull(); - ArgumentCaptor jwtClaimsSetCaptor = ArgumentCaptor.forClass(JwtClaimsSet.class); - verify(this.jwtEncoder).encode(any(), jwtClaimsSetCaptor.capture()); - JwtClaimsSet jwtClaimsSet = jwtClaimsSetCaptor.getValue(); + ArgumentCaptor jwtEncoderParametersCaptor = ArgumentCaptor.forClass(JwtEncoderParameters.class); + verify(this.jwtEncoder).encode(jwtEncoderParametersCaptor.capture()); + JwtClaimsSet jwtClaimsSet = jwtEncoderParametersCaptor.getValue().getClaims(); Set scopes = jwtClaimsSet.getClaim(OAuth2ParameterNames.SCOPE); assertThat(scopes).isEqualTo(authorization.getAttribute(OAuth2Authorization.AUTHORIZED_SCOPE_ATTRIBUTE_NAME)); @@ -614,7 +615,7 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { Instant accessTokenIssuedAt = Instant.now(); Instant accessTokenExpiresAt = accessTokenIssuedAt.plus(accessTokenTTL); - when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt(accessTokenIssuedAt, accessTokenExpiresAt)); + when(this.jwtEncoder.encode(any())).thenReturn(createJwt(accessTokenIssuedAt, accessTokenExpiresAt)); OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) this.authenticationProvider.authenticate(authentication); @@ -651,7 +652,7 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { OAuth2AuthorizationCodeAuthenticationToken authentication = new OAuth2AuthorizationCodeAuthenticationToken(AUTHORIZATION_CODE, clientPrincipal, authorizationRequest.getRedirectUri(), null); - when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt()); + when(this.jwtEncoder.encode(any())).thenReturn(createJwt()); OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) this.authenticationProvider.authenticate(authentication); @@ -666,7 +667,7 @@ public class OAuth2AuthorizationCodeAuthenticationProviderTests { when(this.authorizationService.findByToken(eq(AUTHORIZATION_CODE), eq(AUTHORIZATION_CODE_TOKEN_TYPE))) .thenReturn(authorization); - when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt()); + when(this.jwtEncoder.encode(any())).thenReturn(createJwt()); @SuppressWarnings("unchecked") Supplier refreshTokenGenerator = spy(new Supplier() { diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProviderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProviderTests.java index 8261ac1e..96e06e57 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProviderTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2ClientCredentialsAuthenticationProviderTests.java @@ -39,22 +39,22 @@ import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import org.springframework.security.oauth2.jwt.JoseHeaderNames; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtEncoder; -import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator; import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; -import org.springframework.security.oauth2.server.authorization.token.JwtGenerator; -import org.springframework.security.oauth2.server.authorization.token.OAuth2AccessTokenGenerator; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext; import org.springframework.security.oauth2.server.authorization.OAuth2TokenContext; import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; 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.context.ProviderContext; import org.springframework.security.oauth2.server.authorization.context.ProviderContextHolder; +import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator; +import org.springframework.security.oauth2.server.authorization.token.JwtGenerator; +import org.springframework.security.oauth2.server.authorization.token.OAuth2AccessTokenGenerator; +import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext; +import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -217,7 +217,7 @@ public class OAuth2ClientCredentialsAuthenticationProviderTests { OAuth2ClientCredentialsAuthenticationToken authentication = new OAuth2ClientCredentialsAuthenticationToken(clientPrincipal, requestedScope, null); - when(this.jwtEncoder.encode(any(), any())) + when(this.jwtEncoder.encode(any())) .thenReturn(createJwt(Collections.singleton("mapped-scoped"))); OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = @@ -252,7 +252,7 @@ public class OAuth2ClientCredentialsAuthenticationProviderTests { OAuth2ClientCredentialsAuthenticationToken authentication = new OAuth2ClientCredentialsAuthenticationToken(clientPrincipal, null, null); - when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt(registeredClient.getScopes())); + when(this.jwtEncoder.encode(any())).thenReturn(createJwt(registeredClient.getScopes())); OAuth2AccessTokenAuthenticationToken accessTokenAuthentication = (OAuth2AccessTokenAuthenticationToken) this.authenticationProvider.authenticate(authentication); diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProviderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProviderTests.java index b7953a7d..2eb8a2f1 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProviderTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/authentication/OAuth2RefreshTokenAuthenticationProviderTests.java @@ -48,17 +48,11 @@ import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import org.springframework.security.oauth2.jwt.JoseHeaderNames; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtEncoder; -import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator; import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; -import org.springframework.security.oauth2.server.authorization.token.JwtGenerator; -import org.springframework.security.oauth2.server.authorization.token.OAuth2AccessTokenGenerator; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; -import org.springframework.security.oauth2.server.authorization.token.OAuth2RefreshTokenGenerator; -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext; import org.springframework.security.oauth2.server.authorization.OAuth2TokenContext; import org.springframework.security.oauth2.server.authorization.OAuth2TokenCustomizer; -import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; import org.springframework.security.oauth2.server.authorization.TestOAuth2Authorizations; import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; @@ -66,6 +60,12 @@ import org.springframework.security.oauth2.server.authorization.config.ProviderS import org.springframework.security.oauth2.server.authorization.config.TokenSettings; import org.springframework.security.oauth2.server.authorization.context.ProviderContext; import org.springframework.security.oauth2.server.authorization.context.ProviderContextHolder; +import org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator; +import org.springframework.security.oauth2.server.authorization.token.JwtGenerator; +import org.springframework.security.oauth2.server.authorization.token.OAuth2AccessTokenGenerator; +import org.springframework.security.oauth2.server.authorization.token.OAuth2RefreshTokenGenerator; +import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenClaimsContext; +import org.springframework.security.oauth2.server.authorization.token.OAuth2TokenGenerator; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -99,7 +99,7 @@ public class OAuth2RefreshTokenAuthenticationProviderTests { public void setUp() { this.authorizationService = mock(OAuth2AuthorizationService.class); this.jwtEncoder = mock(JwtEncoder.class); - when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwt(Collections.singleton("scope1"))); + when(this.jwtEncoder.encode(any())).thenReturn(createJwt(Collections.singleton("scope1"))); this.jwtCustomizer = mock(OAuth2TokenCustomizer.class); JwtGenerator jwtGenerator = new JwtGenerator(this.jwtEncoder); jwtGenerator.setJwtCustomizer(this.jwtCustomizer); @@ -265,7 +265,7 @@ public class OAuth2RefreshTokenAuthenticationProviderTests { assertThat(idTokenContext.getHeaders()).isNotNull(); assertThat(idTokenContext.getClaims()).isNotNull(); - verify(this.jwtEncoder, times(2)).encode(any(), any()); // Access token and ID Token + verify(this.jwtEncoder, times(2)).encode(any()); // Access token and ID Token ArgumentCaptor authorizationCaptor = ArgumentCaptor.forClass(OAuth2Authorization.class); verify(this.authorizationService).save(authorizationCaptor.capture()); diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java index 6bc70cf2..a0a403b7 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/authentication/OidcClientRegistrationAuthenticationProviderTests.java @@ -42,11 +42,11 @@ import org.springframework.security.oauth2.core.oidc.OidcClientMetadataClaimName import org.springframework.security.oauth2.core.oidc.OidcClientRegistration; import org.springframework.security.oauth2.jose.jws.MacAlgorithm; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; -import org.springframework.security.oauth2.jwt.JoseHeader; +import org.springframework.security.oauth2.jwt.JwsHeader; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtClaimsSet; import org.springframework.security.oauth2.jwt.JwtEncoder; -import org.springframework.security.oauth2.jwt.TestJoseHeaders; +import org.springframework.security.oauth2.jwt.TestJwsHeaders; import org.springframework.security.oauth2.jwt.TestJwtClaimsSets; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2AuthorizationService; @@ -451,7 +451,7 @@ public class OidcClientRegistrationAuthenticationProviderTests { when(this.authorizationService.findByToken( eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN))) .thenReturn(authorization); - when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwtClientConfiguration()); + when(this.jwtEncoder.encode(any())).thenReturn(createJwtClientConfiguration()); JwtAuthenticationToken principal = new JwtAuthenticationToken( jwt, AuthorityUtils.createAuthorityList("SCOPE_client.create")); @@ -538,7 +538,7 @@ public class OidcClientRegistrationAuthenticationProviderTests { when(this.authorizationService.findByToken( eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN))) .thenReturn(authorization); - when(this.jwtEncoder.encode(any(), any())).thenReturn(createJwtClientConfiguration()); + when(this.jwtEncoder.encode(any())).thenReturn(createJwtClientConfiguration()); JwtAuthenticationToken principal = new JwtAuthenticationToken( jwt, AuthorityUtils.createAuthorityList("SCOPE_client.create")); @@ -565,7 +565,7 @@ public class OidcClientRegistrationAuthenticationProviderTests { eq(jwtAccessToken.getTokenValue()), eq(OAuth2TokenType.ACCESS_TOKEN)); verify(this.registeredClientRepository).save(registeredClientCaptor.capture()); verify(this.authorizationService, times(2)).save(authorizationCaptor.capture()); - verify(this.jwtEncoder).encode(any(), any()); + verify(this.jwtEncoder).encode(any()); // assert "registration" access token, which should be used for subsequent calls to client configuration endpoint OAuth2Authorization authorizationResult = authorizationCaptor.getAllValues().get(0); @@ -834,13 +834,13 @@ public class OidcClientRegistrationAuthenticationProviderTests { private static Jwt createJwt(Set scopes) { // @formatter:off - JoseHeader joseHeader = TestJoseHeaders.joseHeader() + JwsHeader jwsHeader = TestJwsHeaders.jwsHeader() .build(); JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet() .claim(OAuth2ParameterNames.SCOPE, scopes) .build(); Jwt jwt = Jwt.withTokenValue("jwt-access-token") - .headers(headers -> headers.putAll(joseHeader.getHeaders())) + .headers(headers -> headers.putAll(jwsHeader.getHeaders())) .claims(claims -> claims.putAll(jwtClaimsSet.getClaims())) .build(); // @formatter:on diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcClientRegistrationEndpointFilterTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcClientRegistrationEndpointFilterTests.java index 9bb78136..4a96fd62 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcClientRegistrationEndpointFilterTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/oidc/web/OidcClientRegistrationEndpointFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2020-2021 the original author or authors. + * 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. @@ -47,10 +47,10 @@ import org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMe import org.springframework.security.oauth2.core.oidc.OidcClientRegistration; import org.springframework.security.oauth2.core.oidc.http.converter.OidcClientRegistrationHttpMessageConverter; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; -import org.springframework.security.oauth2.jwt.JoseHeader; +import org.springframework.security.oauth2.jwt.JwsHeader; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtClaimsSet; -import org.springframework.security.oauth2.jwt.TestJoseHeaders; +import org.springframework.security.oauth2.jwt.TestJwsHeaders; import org.springframework.security.oauth2.jwt.TestJwtClaimsSets; import org.springframework.security.oauth2.server.authorization.oidc.authentication.OidcClientRegistrationAuthenticationToken; import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; @@ -473,13 +473,13 @@ public class OidcClientRegistrationEndpointFilterTests { private static Jwt createJwt(String scope) { // @formatter:off - JoseHeader joseHeader = TestJoseHeaders.joseHeader() + JwsHeader jwsHeader = TestJwsHeaders.jwsHeader() .build(); JwtClaimsSet jwtClaimsSet = TestJwtClaimsSets.jwtClaimsSet() .claim(OAuth2ParameterNames.SCOPE, Collections.singleton(scope)) .build(); Jwt jwt = Jwt.withTokenValue("jwt-access-token") - .headers(headers -> headers.putAll(joseHeader.getHeaders())) + .headers(headers -> headers.putAll(jwsHeader.getHeaders())) .claims(claims -> claims.putAll(jwtClaimsSet.getClaims())) .build(); // @formatter:on diff --git a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/token/JwtGeneratorTests.java b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/token/JwtGeneratorTests.java index 1d8afdad..130bc721 100644 --- a/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/token/JwtGeneratorTests.java +++ b/oauth2-authorization-server/src/test/java/org/springframework/security/oauth2/server/authorization/token/JwtGeneratorTests.java @@ -36,11 +36,11 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames; import org.springframework.security.oauth2.core.oidc.IdTokenClaimNames; import org.springframework.security.oauth2.core.oidc.OidcScopes; import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames; -import org.springframework.security.oauth2.jose.jws.JwsAlgorithm; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; -import org.springframework.security.oauth2.jwt.JoseHeader; +import org.springframework.security.oauth2.jwt.JwsHeader; import org.springframework.security.oauth2.jwt.JwtClaimsSet; import org.springframework.security.oauth2.jwt.JwtEncoder; +import org.springframework.security.oauth2.jwt.JwtEncoderParameters; import org.springframework.security.oauth2.server.authorization.JwtEncodingContext; import org.springframework.security.oauth2.server.authorization.OAuth2Authorization; import org.springframework.security.oauth2.server.authorization.OAuth2TokenContext; @@ -200,14 +200,13 @@ public class JwtGeneratorTests { assertThat(jwtEncodingContext.getAuthorizationGrantType()).isEqualTo(tokenContext.getAuthorizationGrantType()); assertThat(jwtEncodingContext.getAuthorizationGrant()).isEqualTo(tokenContext.getAuthorizationGrant()); - ArgumentCaptor joseHeaderCaptor = ArgumentCaptor.forClass(JoseHeader.class); - ArgumentCaptor jwtClaimsSetCaptor = ArgumentCaptor.forClass(JwtClaimsSet.class); - verify(this.jwtEncoder).encode(joseHeaderCaptor.capture(), jwtClaimsSetCaptor.capture()); + ArgumentCaptor jwtEncoderParametersCaptor = ArgumentCaptor.forClass(JwtEncoderParameters.class); + verify(this.jwtEncoder).encode(jwtEncoderParametersCaptor.capture()); - JoseHeader joseHeader = joseHeaderCaptor.getValue(); - assertThat(joseHeader.getAlgorithm()).isEqualTo(SignatureAlgorithm.RS256); + JwsHeader jwsHeader = jwtEncoderParametersCaptor.getValue().getJwsHeader(); + assertThat(jwsHeader.getAlgorithm()).isEqualTo(SignatureAlgorithm.RS256); - JwtClaimsSet jwtClaimsSet = jwtClaimsSetCaptor.getValue(); + JwtClaimsSet jwtClaimsSet = jwtEncoderParametersCaptor.getValue().getClaims(); assertThat(jwtClaimsSet.getIssuer().toExternalForm()).isEqualTo(tokenContext.getProviderContext().getIssuer()); assertThat(jwtClaimsSet.getSubject()).isEqualTo(tokenContext.getAuthorization().getPrincipalName()); assertThat(jwtClaimsSet.getAudience()).containsExactly(tokenContext.getRegisteredClient().getClientId());