|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * Copyright 2020 the original author or authors.
|
|
|
+ * 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.
|
|
@@ -13,54 +13,49 @@
|
|
|
* See the License for the specific language governing permissions and
|
|
|
* limitations under the License.
|
|
|
*/
|
|
|
-package org.springframework.security.oauth2.jose.jws;
|
|
|
+package org.springframework.security.oauth2.jwt;
|
|
|
+
|
|
|
+import java.net.URL;
|
|
|
+import java.time.Instant;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
+import java.util.UUID;
|
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
|
+import java.util.concurrent.atomic.AtomicReference;
|
|
|
+import java.util.function.BiConsumer;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
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.KeyLengthException;
|
|
|
-import com.nimbusds.jose.crypto.MACSigner;
|
|
|
-import com.nimbusds.jose.crypto.RSASSASigner;
|
|
|
+import com.nimbusds.jose.KeySourceException;
|
|
|
+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.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.security.crypto.key.AsymmetricKey;
|
|
|
-import org.springframework.security.crypto.key.CryptoKey;
|
|
|
-import org.springframework.security.crypto.key.CryptoKeySource;
|
|
|
-import org.springframework.security.oauth2.jose.JoseHeader;
|
|
|
-import org.springframework.security.oauth2.jose.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.jwt.JwtEncodingException;
|
|
|
+import org.springframework.security.oauth2.jose.jws.JwsAlgorithm;
|
|
|
import org.springframework.util.Assert;
|
|
|
import org.springframework.util.CollectionUtils;
|
|
|
import org.springframework.util.StringUtils;
|
|
|
|
|
|
-import javax.crypto.SecretKey;
|
|
|
-import java.net.URI;
|
|
|
-import java.net.URL;
|
|
|
-import java.security.PrivateKey;
|
|
|
-import java.time.Instant;
|
|
|
-import java.util.Date;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Map;
|
|
|
-import java.util.Set;
|
|
|
-import java.util.UUID;
|
|
|
-import java.util.function.BiConsumer;
|
|
|
-import java.util.stream.Collectors;
|
|
|
-
|
|
|
/**
|
|
|
- * 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 obtained
|
|
|
- * from the {@link CryptoKeySource} supplied via the constructor.
|
|
|
+ * 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.
|
|
|
*
|
|
|
* <p>
|
|
|
* <b>NOTE:</b> This implementation uses the Nimbus JOSE + JWT SDK.
|
|
@@ -68,50 +63,46 @@ import java.util.stream.Collectors;
|
|
|
* @author Joe Grandja
|
|
|
* @since 0.0.1
|
|
|
* @see JwtEncoder
|
|
|
- * @see CryptoKeySource
|
|
|
- * @see <a target="_blank" href="https://tools.ietf.org/html/rfc7519">JSON Web Token (JWT)</a>
|
|
|
- * @see <a target="_blank" href="https://tools.ietf.org/html/rfc7515">JSON Web Signature (JWS)</a>
|
|
|
- * @see <a target="_blank" href="https://tools.ietf.org/html/rfc7515#section-3.1">JWS Compact Serialization</a>
|
|
|
- * @see <a target="_blank" href="https://connect2id.com/products/nimbus-jose-jwt">Nimbus JOSE + JWT SDK</a>
|
|
|
+ * @see com.nimbusds.jose.jwk.source.JWKSource
|
|
|
+ * @see com.nimbusds.jose.jwk.JWK
|
|
|
+ * @see <a target="_blank" href="https://tools.ietf.org/html/rfc7519">JSON Web Token
|
|
|
+ * (JWT)</a>
|
|
|
+ * @see <a target="_blank" href="https://tools.ietf.org/html/rfc7515">JSON Web Signature
|
|
|
+ * (JWS)</a>
|
|
|
+ * @see <a target="_blank" href="https://tools.ietf.org/html/rfc7515#section-3.1">JWS
|
|
|
+ * Compact Serialization</a>
|
|
|
+ * @see <a target="_blank" href="https://connect2id.com/products/nimbus-jose-jwt">Nimbus
|
|
|
+ * JOSE + JWT SDK</a>
|
|
|
*/
|
|
|
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 String RSA_KEY_TYPE = "RSA";
|
|
|
- private static final String EC_KEY_TYPE = "EC";
|
|
|
- private static final Map<JwsAlgorithm, String> jcaKeyAlgorithmMappings = new HashMap<JwsAlgorithm, String>() {
|
|
|
- {
|
|
|
- put(MacAlgorithm.HS256, "HmacSHA256");
|
|
|
- put(MacAlgorithm.HS384, "HmacSHA384");
|
|
|
- put(MacAlgorithm.HS512, "HmacSHA512");
|
|
|
- put(SignatureAlgorithm.RS256, RSA_KEY_TYPE);
|
|
|
- put(SignatureAlgorithm.RS384, RSA_KEY_TYPE);
|
|
|
- put(SignatureAlgorithm.RS512, RSA_KEY_TYPE);
|
|
|
- put(SignatureAlgorithm.ES256, EC_KEY_TYPE);
|
|
|
- put(SignatureAlgorithm.ES384, EC_KEY_TYPE);
|
|
|
- put(SignatureAlgorithm.ES512, EC_KEY_TYPE);
|
|
|
- }
|
|
|
+
|
|
|
+ private static final String ENCODING_ERROR_MESSAGE_TEMPLATE = "An error occurred while attempting to encode the Jwt: %s";
|
|
|
+
|
|
|
+ private static final Converter<JoseHeader, JWSHeader> JWS_HEADER_CONVERTER = new JwsHeaderConverter();
|
|
|
+
|
|
|
+ private static final Converter<JwtClaimsSet, JWTClaimsSet> JWT_CLAIMS_SET_CONVERTER = new JwtClaimsSetConverter();
|
|
|
+
|
|
|
+ private static final JWSSignerFactory JWS_SIGNER_FACTORY = new DefaultJWSSignerFactory();
|
|
|
+
|
|
|
+ private final Map<JWK, JWSSigner> jwsSigners = new ConcurrentHashMap<>();
|
|
|
+
|
|
|
+ private final JWKSource<SecurityContext> jwkSource;
|
|
|
+
|
|
|
+ private BiConsumer<JoseHeader.Builder, JwtClaimsSet.Builder> jwtCustomizer = (headers, claims) -> {
|
|
|
};
|
|
|
- private static final Converter<JoseHeader, JWSHeader> jwsHeaderConverter = new JwsHeaderConverter();
|
|
|
- private static final Converter<JwtClaimsSet, JWTClaimsSet> jwtClaimsSetConverter = new JwtClaimsSetConverter();
|
|
|
- private final CryptoKeySource keySource;
|
|
|
- private BiConsumer<JoseHeader.Builder, JwtClaimsSet.Builder> jwtCustomizer = (headers, claims) -> {};
|
|
|
|
|
|
/**
|
|
|
* Constructs a {@code NimbusJwsEncoder} using the provided parameters.
|
|
|
- *
|
|
|
- * @param keySource the source for cryptographic keys
|
|
|
+ * @param jwkSource the {@code com.nimbusds.jose.jwk.source.JWKSource}
|
|
|
*/
|
|
|
- public NimbusJwsEncoder(CryptoKeySource keySource) {
|
|
|
- Assert.notNull(keySource, "keySource cannot be null");
|
|
|
- this.keySource = keySource;
|
|
|
+ public NimbusJwsEncoder(JWKSource<SecurityContext> jwkSource) {
|
|
|
+ Assert.notNull(jwkSource, "jwkSource cannot be null");
|
|
|
+ this.jwkSource = jwkSource;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * Sets the {@link Jwt} customizer to be provided the
|
|
|
- * {@link JoseHeader.Builder} and {@link JwtClaimsSet.Builder}
|
|
|
- * allowing for further customizations.
|
|
|
- *
|
|
|
+ * Sets the {@link Jwt} customizer to be provided the {@link JoseHeader.Builder} and
|
|
|
+ * {@link JwtClaimsSet.Builder} allowing for further customizations.
|
|
|
* @param jwtCustomizer the {@link Jwt} customizer to be provided the
|
|
|
* {@link JoseHeader.Builder} and {@link JwtClaimsSet.Builder}
|
|
|
*/
|
|
@@ -125,78 +116,85 @@ public final class NimbusJwsEncoder implements JwtEncoder {
|
|
|
Assert.notNull(headers, "headers cannot be null");
|
|
|
Assert.notNull(claims, "claims cannot be null");
|
|
|
|
|
|
- CryptoKey<?> cryptoKey = selectKey(headers);
|
|
|
- if (cryptoKey == null) {
|
|
|
- throw new JwtEncodingException(String.format(
|
|
|
- ENCODING_ERROR_MESSAGE_TEMPLATE,
|
|
|
- "Unsupported key for algorithm '" + headers.getJwsAlgorithm().getName() + "'"));
|
|
|
- }
|
|
|
-
|
|
|
- JWSSigner jwsSigner;
|
|
|
- if (AsymmetricKey.class.isAssignableFrom(cryptoKey.getClass())) {
|
|
|
- if (!cryptoKey.getAlgorithm().equals(RSA_KEY_TYPE)) {
|
|
|
- throw new JwtEncodingException(String.format(
|
|
|
- ENCODING_ERROR_MESSAGE_TEMPLATE,
|
|
|
- "Unsupported key type '" + cryptoKey.getAlgorithm() + "'"));
|
|
|
- }
|
|
|
- PrivateKey privateKey = (PrivateKey) cryptoKey.getKey();
|
|
|
- jwsSigner = new RSASSASigner(privateKey);
|
|
|
- } else {
|
|
|
- SecretKey secretKey = (SecretKey) cryptoKey.getKey();
|
|
|
- try {
|
|
|
- jwsSigner = new MACSigner(secretKey);
|
|
|
- } catch (KeyLengthException ex) {
|
|
|
- throw new JwtEncodingException(String.format(
|
|
|
- ENCODING_ERROR_MESSAGE_TEMPLATE, ex.getMessage()), ex);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
+ // @formatter:off
|
|
|
JoseHeader.Builder headersBuilder = JoseHeader.from(headers)
|
|
|
- .type(JOSEObjectType.JWT.getType())
|
|
|
- .keyId(cryptoKey.getId());
|
|
|
+ .type(JOSEObjectType.JWT.getType());
|
|
|
JwtClaimsSet.Builder claimsBuilder = JwtClaimsSet.from(claims)
|
|
|
.id(UUID.randomUUID().toString());
|
|
|
+ // @formatter:on
|
|
|
|
|
|
this.jwtCustomizer.accept(headersBuilder, claimsBuilder);
|
|
|
|
|
|
- headers = headersBuilder.build();
|
|
|
+ JWK jwk = selectJwk(headersBuilder);
|
|
|
+ if (jwk == null) {
|
|
|
+ throw new JwtEncodingException(
|
|
|
+ String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, "Failed to select a JWK signing key"));
|
|
|
+ }
|
|
|
+ else if (!StringUtils.hasText(jwk.getKeyID())) {
|
|
|
+ throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE,
|
|
|
+ "The \"kid\" (key ID) from the selected JWK cannot be empty"));
|
|
|
+ }
|
|
|
+
|
|
|
+ headers = headersBuilder.keyId(jwk.getKeyID()).build();
|
|
|
claims = claimsBuilder.build();
|
|
|
|
|
|
- JWSHeader jwsHeader = jwsHeaderConverter.convert(headers);
|
|
|
- JWTClaimsSet jwtClaimsSet = jwtClaimsSetConverter.convert(claims);
|
|
|
+ JWSHeader jwsHeader = JWS_HEADER_CONVERTER.convert(headers);
|
|
|
+ JWTClaimsSet jwtClaimsSet = JWT_CLAIMS_SET_CONVERTER.convert(claims);
|
|
|
+
|
|
|
+ JWSSigner jwsSigner = this.jwsSigners.computeIfAbsent(jwk, (key) -> {
|
|
|
+ try {
|
|
|
+ return JWS_SIGNER_FACTORY.createJWSSigner(key);
|
|
|
+ }
|
|
|
+ catch (JOSEException ex) {
|
|
|
+ throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE,
|
|
|
+ "Failed to create a JWS Signer -> " + ex.getMessage()), ex);
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
- SignedJWT signedJWT = new SignedJWT(jwsHeader, jwtClaimsSet);
|
|
|
+ SignedJWT signedJwt = new SignedJWT(jwsHeader, jwtClaimsSet);
|
|
|
try {
|
|
|
- signedJWT.sign(jwsSigner);
|
|
|
- } catch (JOSEException ex) {
|
|
|
- throw new JwtEncodingException(String.format(
|
|
|
- ENCODING_ERROR_MESSAGE_TEMPLATE, ex.getMessage()), ex);
|
|
|
+ signedJwt.sign(jwsSigner);
|
|
|
}
|
|
|
- String jws = signedJWT.serialize();
|
|
|
+ catch (JOSEException ex) {
|
|
|
+ throw new JwtEncodingException(
|
|
|
+ String.format(ENCODING_ERROR_MESSAGE_TEMPLATE, "Failed to sign the JWT -> " + ex.getMessage()), ex);
|
|
|
+ }
|
|
|
+ String jws = signedJwt.serialize();
|
|
|
|
|
|
- return new Jwt(jws, claims.getIssuedAt(), claims.getExpiresAt(),
|
|
|
- headers.getHeaders(), claims.getClaims());
|
|
|
+ return new Jwt(jws, claims.getIssuedAt(), claims.getExpiresAt(), headers.getHeaders(), claims.getClaims());
|
|
|
}
|
|
|
|
|
|
- private CryptoKey<?> selectKey(JoseHeader headers) {
|
|
|
- JwsAlgorithm jwsAlgorithm = headers.getJwsAlgorithm();
|
|
|
- String keyAlgorithm = jcaKeyAlgorithmMappings.get(jwsAlgorithm);
|
|
|
- if (!StringUtils.hasText(keyAlgorithm)) {
|
|
|
- return null;
|
|
|
+ private JWK selectJwk(JoseHeader.Builder headersBuilder) {
|
|
|
+ final AtomicReference<JWSAlgorithm> jwsAlgorithm = new AtomicReference<>();
|
|
|
+ headersBuilder.headers((h) -> {
|
|
|
+ JwsAlgorithm jwsAlg = (JwsAlgorithm) h.get(JoseHeaderNames.ALG);
|
|
|
+ jwsAlgorithm.set(JWSAlgorithm.parse(jwsAlg.getName()));
|
|
|
+ });
|
|
|
+ JWSHeader jwsHeader = new JWSHeader(jwsAlgorithm.get());
|
|
|
+ JWKSelector jwkSelector = new JWKSelector(JWKMatcher.forJWSHeader(jwsHeader));
|
|
|
+
|
|
|
+ List<JWK> jwks;
|
|
|
+ try {
|
|
|
+ jwks = this.jwkSource.get(jwkSelector, null);
|
|
|
+ }
|
|
|
+ catch (KeySourceException 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 '" + jwsAlgorithm.get().getName() + "'"));
|
|
|
}
|
|
|
|
|
|
- return this.keySource.getKeys().stream()
|
|
|
- .filter(key -> key.getAlgorithm().equals(keyAlgorithm))
|
|
|
- .findFirst()
|
|
|
- .orElse(null);
|
|
|
+ return !jwks.isEmpty() ? jwks.get(0) : null;
|
|
|
}
|
|
|
|
|
|
private static class JwsHeaderConverter implements Converter<JoseHeader, JWSHeader> {
|
|
|
|
|
|
@Override
|
|
|
public JWSHeader convert(JoseHeader headers) {
|
|
|
- JWSHeader.Builder builder = new JWSHeader.Builder(
|
|
|
- JWSAlgorithm.parse(headers.getJwsAlgorithm().getName()));
|
|
|
+ JWSHeader.Builder builder = new JWSHeader.Builder(JWSAlgorithm.parse(headers.getJwsAlgorithm().getName()));
|
|
|
|
|
|
Set<String> critical = headers.getCritical();
|
|
|
if (!CollectionUtils.isEmpty(critical)) {
|
|
@@ -208,14 +206,14 @@ public final class NimbusJwsEncoder implements JwtEncoder {
|
|
|
builder.contentType(contentType);
|
|
|
}
|
|
|
|
|
|
- String jwkSetUri = headers.getJwkSetUri();
|
|
|
- if (StringUtils.hasText(jwkSetUri)) {
|
|
|
+ URL jwkSetUri = headers.getJwkSetUri();
|
|
|
+ if (jwkSetUri != null) {
|
|
|
try {
|
|
|
- builder.jwkURL(new URI(jwkSetUri));
|
|
|
- } catch (Exception ex) {
|
|
|
- throw new JwtEncodingException(String.format(
|
|
|
- ENCODING_ERROR_MESSAGE_TEMPLATE,
|
|
|
- "Failed to convert '" + JoseHeaderNames.JKU + "' JOSE header"), ex);
|
|
|
+ builder.jwkURL(jwkSetUri.toURI());
|
|
|
+ }
|
|
|
+ catch (Exception ex) {
|
|
|
+ throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE,
|
|
|
+ "Failed to convert '" + JoseHeaderNames.JKU + "' JOSE header to a URI"), ex);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -223,9 +221,9 @@ public final class NimbusJwsEncoder implements JwtEncoder {
|
|
|
if (!CollectionUtils.isEmpty(jwk)) {
|
|
|
try {
|
|
|
builder.jwk(JWK.parse(jwk));
|
|
|
- } catch (Exception ex) {
|
|
|
- throw new JwtEncodingException(String.format(
|
|
|
- ENCODING_ERROR_MESSAGE_TEMPLATE,
|
|
|
+ }
|
|
|
+ catch (Exception ex) {
|
|
|
+ throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE,
|
|
|
"Failed to convert '" + JoseHeaderNames.JWK + "' JOSE header"), ex);
|
|
|
}
|
|
|
}
|
|
@@ -242,10 +240,7 @@ public final class NimbusJwsEncoder implements JwtEncoder {
|
|
|
|
|
|
List<String> x509CertificateChain = headers.getX509CertificateChain();
|
|
|
if (!CollectionUtils.isEmpty(x509CertificateChain)) {
|
|
|
- builder.x509CertChain(
|
|
|
- x509CertificateChain.stream()
|
|
|
- .map(Base64::new)
|
|
|
- .collect(Collectors.toList()));
|
|
|
+ builder.x509CertChain(x509CertificateChain.stream().map(Base64::new).collect(Collectors.toList()));
|
|
|
}
|
|
|
|
|
|
String x509SHA1Thumbprint = headers.getX509SHA1Thumbprint();
|
|
@@ -258,19 +253,19 @@ public final class NimbusJwsEncoder implements JwtEncoder {
|
|
|
builder.x509CertSHA256Thumbprint(new Base64URL(x509SHA256Thumbprint));
|
|
|
}
|
|
|
|
|
|
- String x509Uri = headers.getX509Uri();
|
|
|
- if (StringUtils.hasText(x509Uri)) {
|
|
|
+ URL x509Uri = headers.getX509Uri();
|
|
|
+ if (x509Uri != null) {
|
|
|
try {
|
|
|
- builder.x509CertURL(new URI(x509Uri));
|
|
|
- } catch (Exception ex) {
|
|
|
- throw new JwtEncodingException(String.format(
|
|
|
- ENCODING_ERROR_MESSAGE_TEMPLATE,
|
|
|
- "Failed to convert '" + JoseHeaderNames.X5U + "' JOSE header"), ex);
|
|
|
+ builder.x509CertURL(x509Uri.toURI());
|
|
|
+ }
|
|
|
+ catch (Exception ex) {
|
|
|
+ throw new JwtEncodingException(String.format(ENCODING_ERROR_MESSAGE_TEMPLATE,
|
|
|
+ "Failed to convert '" + JoseHeaderNames.X5U + "' JOSE header to a URI"), ex);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Map<String, Object> customHeaders = headers.getHeaders().entrySet().stream()
|
|
|
- .filter(header -> !JWSHeader.getRegisteredParameterNames().contains(header.getKey()))
|
|
|
+ .filter((header) -> !JWSHeader.getRegisteredParameterNames().contains(header.getKey()))
|
|
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
|
|
if (!CollectionUtils.isEmpty(customHeaders)) {
|
|
|
builder.customParams(customHeaders);
|
|
@@ -278,6 +273,7 @@ public final class NimbusJwsEncoder implements JwtEncoder {
|
|
|
|
|
|
return builder.build();
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
|
|
|
private static class JwtClaimsSetConverter implements Converter<JwtClaimsSet, JWTClaimsSet> {
|
|
@@ -322,7 +318,7 @@ public final class NimbusJwsEncoder implements JwtEncoder {
|
|
|
}
|
|
|
|
|
|
Map<String, Object> customClaims = claims.getClaims().entrySet().stream()
|
|
|
- .filter(claim -> !JWTClaimsSet.getRegisteredNames().contains(claim.getKey()))
|
|
|
+ .filter((claim) -> !JWTClaimsSet.getRegisteredNames().contains(claim.getKey()))
|
|
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
|
|
if (!CollectionUtils.isEmpty(customClaims)) {
|
|
|
customClaims.forEach(builder::claim);
|
|
@@ -330,5 +326,7 @@ public final class NimbusJwsEncoder implements JwtEncoder {
|
|
|
|
|
|
return builder.build();
|
|
|
}
|
|
|
+
|
|
|
}
|
|
|
+
|
|
|
}
|