mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
ACS-4895 Restore support for providing IDS public key (#1856)
This commit is contained in:
@@ -58,6 +58,7 @@ public class IdentityServiceConfig implements InitializingBean
|
|||||||
private String clientKeystore;
|
private String clientKeystore;
|
||||||
private String clientKeystorePassword;
|
private String clientKeystorePassword;
|
||||||
private String clientKeyPassword;
|
private String clientKeyPassword;
|
||||||
|
private String realmKey;
|
||||||
|
|
||||||
public void setGlobalProperties(Properties globalProperties)
|
public void setGlobalProperties(Properties globalProperties)
|
||||||
{
|
{
|
||||||
@@ -229,4 +230,14 @@ public class IdentityServiceConfig implements InitializingBean
|
|||||||
{
|
{
|
||||||
return clientKeyPassword;
|
return clientKeyPassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRealmKey(String realmKey)
|
||||||
|
{
|
||||||
|
this.realmKey = realmKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRealmKey()
|
||||||
|
{
|
||||||
|
return realmKey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,8 +29,12 @@ import static java.util.Objects.requireNonNull;
|
|||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
import static java.util.function.Predicate.not;
|
import static java.util.function.Predicate.not;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.interfaces.RSAPublicKey;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -63,10 +67,12 @@ import org.springframework.http.ResponseEntity;
|
|||||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||||
import org.springframework.http.converter.FormHttpMessageConverter;
|
import org.springframework.http.converter.FormHttpMessageConverter;
|
||||||
|
import org.springframework.security.converter.RsaKeyConverters;
|
||||||
import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
|
import org.springframework.security.oauth2.client.http.OAuth2ErrorResponseErrorHandler;
|
||||||
import org.springframework.security.oauth2.client.oidc.authentication.OidcIdTokenDecoderFactory;
|
import org.springframework.security.oauth2.client.oidc.authentication.OidcIdTokenDecoderFactory;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
||||||
import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder;
|
import org.springframework.security.oauth2.client.registration.ClientRegistration.Builder;
|
||||||
|
import org.springframework.security.oauth2.client.registration.ClientRegistration.ProviderDetails;
|
||||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||||
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
|
||||||
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
|
import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator;
|
||||||
@@ -109,7 +115,7 @@ public class IdentityServiceFacadeFactoryBean implements FactoryBean<IdentitySer
|
|||||||
factory = new SpringBasedIdentityServiceFacadeFactory(
|
factory = new SpringBasedIdentityServiceFacadeFactory(
|
||||||
new HttpClientProvider(identityServiceConfig)::createHttpClient,
|
new HttpClientProvider(identityServiceConfig)::createHttpClient,
|
||||||
new ClientRegistrationProvider(identityServiceConfig)::createClientRegistration,
|
new ClientRegistrationProvider(identityServiceConfig)::createClientRegistration,
|
||||||
new JwtDecoderProvider()::createJwtDecoder
|
new JwtDecoderProvider(identityServiceConfig)::createJwtDecoder
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,12 +202,12 @@ public class IdentityServiceFacadeFactoryBean implements FactoryBean<IdentitySer
|
|||||||
{
|
{
|
||||||
private final Supplier<HttpClient> httpClientProvider;
|
private final Supplier<HttpClient> httpClientProvider;
|
||||||
private final Function<RestOperations, ClientRegistration> clientRegistrationProvider;
|
private final Function<RestOperations, ClientRegistration> clientRegistrationProvider;
|
||||||
private final BiFunction<RestOperations, ClientRegistration, JwtDecoder> jwtDecoderProvider;
|
private final BiFunction<RestOperations, ProviderDetails, JwtDecoder> jwtDecoderProvider;
|
||||||
|
|
||||||
SpringBasedIdentityServiceFacadeFactory(
|
SpringBasedIdentityServiceFacadeFactory(
|
||||||
Supplier<HttpClient> httpClientProvider,
|
Supplier<HttpClient> httpClientProvider,
|
||||||
Function<RestOperations, ClientRegistration> clientRegistrationProvider,
|
Function<RestOperations, ClientRegistration> clientRegistrationProvider,
|
||||||
BiFunction<RestOperations, ClientRegistration, JwtDecoder> jwtDecoderProvider)
|
BiFunction<RestOperations, ProviderDetails, JwtDecoder> jwtDecoderProvider)
|
||||||
{
|
{
|
||||||
this.httpClientProvider = Objects.requireNonNull(httpClientProvider);
|
this.httpClientProvider = Objects.requireNonNull(httpClientProvider);
|
||||||
this.clientRegistrationProvider = Objects.requireNonNull(clientRegistrationProvider);
|
this.clientRegistrationProvider = Objects.requireNonNull(clientRegistrationProvider);
|
||||||
@@ -217,7 +223,7 @@ public class IdentityServiceFacadeFactoryBean implements FactoryBean<IdentitySer
|
|||||||
final ClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClientProvider.get());
|
final ClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClientProvider.get());
|
||||||
final RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
|
final RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
|
||||||
final ClientRegistration clientRegistration = clientRegistrationProvider.apply(restTemplate);
|
final ClientRegistration clientRegistration = clientRegistrationProvider.apply(restTemplate);
|
||||||
final JwtDecoder jwtDecoder = jwtDecoderProvider.apply(restTemplate, clientRegistration);
|
final JwtDecoder jwtDecoder = jwtDecoderProvider.apply(restTemplate, clientRegistration.getProviderDetails());
|
||||||
|
|
||||||
return new SpringBasedIdentityServiceFacade(createOAuth2RestTemplate(httpRequestFactory), clientRegistration, jwtDecoder);
|
return new SpringBasedIdentityServiceFacade(createOAuth2RestTemplate(httpRequestFactory), clientRegistration, jwtDecoder);
|
||||||
}
|
}
|
||||||
@@ -246,6 +252,7 @@ public class IdentityServiceFacadeFactoryBean implements FactoryBean<IdentitySer
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
HttpClientBuilder clientBuilder = HttpClients.custom();
|
HttpClientBuilder clientBuilder = HttpClients.custom();
|
||||||
|
|
||||||
clientBuilder = applyConnectionConfiguration(clientBuilder);
|
clientBuilder = applyConnectionConfiguration(clientBuilder);
|
||||||
clientBuilder = applySSLConfiguration(clientBuilder);
|
clientBuilder = applySSLConfiguration(clientBuilder);
|
||||||
|
|
||||||
@@ -389,54 +396,100 @@ public class IdentityServiceFacadeFactoryBean implements FactoryBean<IdentitySer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class JwtDecoderProvider
|
static class JwtDecoderProvider
|
||||||
{
|
{
|
||||||
private static final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.RS256;
|
private static final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.RS256;
|
||||||
|
private final IdentityServiceConfig config;
|
||||||
|
|
||||||
public JwtDecoder createJwtDecoder(RestOperations rest, ClientRegistration clientRegistration)
|
JwtDecoderProvider(IdentityServiceConfig config)
|
||||||
|
{
|
||||||
|
this.config = Objects.requireNonNull(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JwtDecoder createJwtDecoder(RestOperations rest, ProviderDetails providerDetails)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
final String jwkSetUri = requireValidJwkSetUri(clientRegistration);
|
final NimbusJwtDecoder decoder = buildJwtDecoder(rest, providerDetails);
|
||||||
final NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
|
|
||||||
.jwsAlgorithm(SIGNATURE_ALGORITHM)
|
|
||||||
.restOperations(rest)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
decoder.setJwtValidator(createJwtTokenValidator(clientRegistration));
|
decoder.setJwtValidator(createJwtTokenValidator(providerDetails));
|
||||||
decoder.setClaimSetConverter(new ClaimTypeConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverters()));
|
decoder.setClaimSetConverter(new ClaimTypeConverter(OidcIdTokenDecoderFactory.createDefaultClaimTypeConverters()));
|
||||||
|
|
||||||
return decoder;
|
return decoder;
|
||||||
}
|
} catch (RuntimeException e)
|
||||||
catch (RuntimeException e)
|
|
||||||
{
|
{
|
||||||
LOGGER.warn("Failed to create JwtDecoder.", e);
|
LOGGER.warn("Failed to create JwtDecoder.", e);
|
||||||
throw authorizationServerCantBeUsedException(e);
|
throw authorizationServerCantBeUsedException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String requireValidJwkSetUri(ClientRegistration clientRegistration)
|
private NimbusJwtDecoder buildJwtDecoder(RestOperations rest, ProviderDetails providerDetails)
|
||||||
{
|
{
|
||||||
final String uri = clientRegistration.getProviderDetails().getJwkSetUri();
|
if (isDefined(config.getRealmKey()))
|
||||||
|
{
|
||||||
|
final RSAPublicKey publicKey = parsePublicKey(config.getRealmKey());
|
||||||
|
return NimbusJwtDecoder.withPublicKey(publicKey)
|
||||||
|
.signatureAlgorithm(SIGNATURE_ALGORITHM)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
final String jwkSetUri = requireValidJwkSetUri(providerDetails);
|
||||||
|
return NimbusJwtDecoder.withJwkSetUri(jwkSetUri)
|
||||||
|
.jwsAlgorithm(SIGNATURE_ALGORITHM)
|
||||||
|
.restOperations(rest)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private OAuth2TokenValidator<Jwt> createJwtTokenValidator(ProviderDetails providerDetails)
|
||||||
|
{
|
||||||
|
return new DelegatingOAuth2TokenValidator<>(
|
||||||
|
new JwtTimestampValidator(Duration.of(0, ChronoUnit.MILLIS)),
|
||||||
|
new JwtIssuerValidator(providerDetails.getIssuerUri()),
|
||||||
|
new JwtClaimValidator<String>("typ", "Bearer"::equals),
|
||||||
|
new JwtClaimValidator<String>(JwtClaimNames.SUB, Objects::nonNull));
|
||||||
|
}
|
||||||
|
|
||||||
|
private RSAPublicKey parsePublicKey(String pem)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return tryToParsePublicKey(pem);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (isPemFormatException(e))
|
||||||
|
{
|
||||||
|
//For backward compatibility with Keycloak adapter
|
||||||
|
return tryToParsePublicKey("-----BEGIN PUBLIC KEY-----\n" + pem + "\n-----END PUBLIC KEY-----");
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RSAPublicKey tryToParsePublicKey(String pem)
|
||||||
|
{
|
||||||
|
final InputStream pemStream = new ByteArrayInputStream(pem.getBytes(StandardCharsets.UTF_8));
|
||||||
|
return RsaKeyConverters.x509().convert(pemStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isPemFormatException(Exception e)
|
||||||
|
{
|
||||||
|
return e.getMessage() != null && e.getMessage().contains("-----BEGIN PUBLIC KEY-----");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String requireValidJwkSetUri(ProviderDetails providerDetails)
|
||||||
|
{
|
||||||
|
final String uri = providerDetails.getJwkSetUri();
|
||||||
if (!isDefined(uri)) {
|
if (!isDefined(uri)) {
|
||||||
OAuth2Error oauth2Error = new OAuth2Error("missing_signature_verifier",
|
OAuth2Error oauth2Error = new OAuth2Error("missing_signature_verifier",
|
||||||
"Failed to find a Signature Verifier for Client Registration: '"
|
"Failed to find a Signature Verifier for: '"
|
||||||
+ clientRegistration.getRegistrationId()
|
+ providerDetails.getIssuerUri()
|
||||||
+ "'. Check to ensure you have configured the JwkSet URI.",
|
+ "'. Check to ensure you have configured the JwkSet URI.",
|
||||||
null);
|
null);
|
||||||
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
|
||||||
}
|
}
|
||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OAuth2TokenValidator<Jwt> createJwtTokenValidator(ClientRegistration clientRegistration)
|
|
||||||
{
|
|
||||||
return new DelegatingOAuth2TokenValidator<>(
|
|
||||||
new JwtTimestampValidator(Duration.of(0, ChronoUnit.MILLIS)),
|
|
||||||
new JwtIssuerValidator(clientRegistration.getProviderDetails().getIssuerUri()),
|
|
||||||
new JwtClaimValidator<String>("typ", "Bearer"::equals),
|
|
||||||
new JwtClaimValidator<String>(JwtClaimNames.SUB, Objects::nonNull));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isDefined(String value)
|
private static boolean isDefined(String value)
|
||||||
|
@@ -128,6 +128,9 @@
|
|||||||
<property name="clientSocketTimeout">
|
<property name="clientSocketTimeout">
|
||||||
<value>${identity-service.client-socket-timeout:2000}</value>
|
<value>${identity-service.client-socket-timeout:2000}</value>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="realmKey">
|
||||||
|
<value>${identity-service.realm-public-key:#{null}}</value>
|
||||||
|
</property>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
<!-- Enable control over mapping between request and user ID -->
|
<!-- Enable control over mapping between request and user ID -->
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
* #%L
|
* #%L
|
||||||
* Alfresco Repository
|
* Alfresco Repository
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
* Copyright (C) 2005 - 2023 Alfresco Software Limited
|
||||||
* %%
|
* %%
|
||||||
* This file is part of the Alfresco software.
|
* This file is part of the Alfresco software.
|
||||||
* If the software was purchased under a paid Alfresco license, the terms of
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco;
|
package org.alfresco;
|
||||||
|
|
||||||
|
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacadeFactoryBeanTest;
|
||||||
import org.alfresco.repo.security.authentication.identityservice.LazyInstantiatingIdentityServiceFacadeUnitTest;
|
import org.alfresco.repo.security.authentication.identityservice.LazyInstantiatingIdentityServiceFacadeUnitTest;
|
||||||
import org.alfresco.repo.security.authentication.identityservice.SpringBasedIdentityServiceFacadeUnitTest;
|
import org.alfresco.repo.security.authentication.identityservice.SpringBasedIdentityServiceFacadeUnitTest;
|
||||||
import org.alfresco.util.testing.category.DBTests;
|
import org.alfresco.util.testing.category.DBTests;
|
||||||
@@ -138,6 +139,7 @@ import org.junit.runners.Suite;
|
|||||||
org.alfresco.repo.search.impl.solr.facet.FacetQNameUtilsTest.class,
|
org.alfresco.repo.search.impl.solr.facet.FacetQNameUtilsTest.class,
|
||||||
org.alfresco.util.BeanExtenderUnitTest.class,
|
org.alfresco.util.BeanExtenderUnitTest.class,
|
||||||
org.alfresco.repo.solr.SOLRTrackingComponentUnitTest.class,
|
org.alfresco.repo.solr.SOLRTrackingComponentUnitTest.class,
|
||||||
|
IdentityServiceFacadeFactoryBeanTest.class,
|
||||||
LazyInstantiatingIdentityServiceFacadeUnitTest.class,
|
LazyInstantiatingIdentityServiceFacadeUnitTest.class,
|
||||||
SpringBasedIdentityServiceFacadeUnitTest.class,
|
SpringBasedIdentityServiceFacadeUnitTest.class,
|
||||||
org.alfresco.repo.security.authentication.CompositePasswordEncoderTest.class,
|
org.alfresco.repo.security.authentication.CompositePasswordEncoderTest.class,
|
||||||
|
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* Alfresco Repository
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2005 - 2023 Alfresco Software Limited
|
||||||
|
* %%
|
||||||
|
* This file is part of the Alfresco software.
|
||||||
|
* If the software was purchased under a paid Alfresco license, the terms of
|
||||||
|
* the paid license agreement will prevail. Otherwise, the software is
|
||||||
|
* provided under the following open source license terms:
|
||||||
|
*
|
||||||
|
* Alfresco is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Alfresco is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
package org.alfresco.repo.security.authentication.identityservice;
|
||||||
|
|
||||||
|
import static org.alfresco.repo.security.authentication.identityservice.IdentityServiceRemoteUserMapper.USERNAME_CLAIM;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.repo.security.authentication.identityservice.IdentityServiceFacadeFactoryBean.JwtDecoderProvider;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.security.oauth2.client.registration.ClientRegistration.ProviderDetails;
|
||||||
|
import org.springframework.security.oauth2.jwt.Jwt;
|
||||||
|
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||||
|
|
||||||
|
public class IdentityServiceFacadeFactoryBeanTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void shouldCreateJwtDecoderWithoutIDSWhenPublicKeyIsProvided()
|
||||||
|
{
|
||||||
|
final IdentityServiceConfig config = mock(IdentityServiceConfig.class);
|
||||||
|
when(config.getRealmKey()).thenReturn("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAve3MabX/rp3LbE7/zNqKxuid8WT7y4qSXsNaiPvl/OVbNWW/cu5td1VndItYhH6/gL7Z5W/r4MOeTlz/fOdXfjrRJou2f3UiPQwLV9RdOH3oS4/BUe+sviD8Q3eRfWBWWz3yw8f2YNtD4bMztIMMjqthvwdEEb9S9jbxxD0o71Bsrz/FwPi7HhSDA+Z/p01Hct8m4wx13ZlKRd4YjyC12FBmi9MSgsrFuWzyQHhHTeBDoALpfuiut3rhVxUtFmVTpy6p9vil7C5J5pok4MXPH0dJCyDNQz05ww5+fD+tfksIEpFeokRpN226F+P21oQVFUWwYIaXaFlG/hfvwmnlfQIDAQAB");
|
||||||
|
|
||||||
|
final ProviderDetails providerDetails = mock(ProviderDetails.class);
|
||||||
|
when(providerDetails.getIssuerUri()).thenReturn("https://my.issuer");
|
||||||
|
|
||||||
|
final JwtDecoderProvider provider = new JwtDecoderProvider(config);
|
||||||
|
|
||||||
|
final JwtDecoder decoder = provider.createJwtDecoder(null, providerDetails);
|
||||||
|
|
||||||
|
final Jwt decodedToken = decoder.decode("eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjIxNDc0ODM2NDcsImp0aSI6IjEyMzQiLCJpc3MiOiJodHRwczovL215Lmlzc3VlciIsInN1YiI6ImFiYzEyMyIsInR5cCI6IkJlYXJlciIsInByZWZlcnJlZF91c2VybmFtZSI6InBpb3RyZWsifQ.k_KaOrLLh3QsT8mKphkcz2vKpulgxp92UoEDccpHJ1mxE3Pa3gFXPKTj4goUBKXieGPZRMvBDhfWNxMvRYZPiQr2NXJKapkh0bTd0qoaSWz9ICe9Nu3eg7_VA_nwUVPz_35wwmrxgVk0_kpUYQN_VtaO7ZgFE2sJzFjbkVls5aqfAMnEjEgQl837hqZvmlW2ZRWebtxXfQxAjtp0gcTg-xtAHKIINYo_1_uAtt_H9L8KqFaioxrVAEDDIlcKnb-Ks3Y62CrZauaGUJeN_aNj2gdOpdkhvCw79yJyZSGZ7okjGbidCNSAf7Bo2Y6h3dP1Gga7kRmD648ftZESrNvbyg");
|
||||||
|
assertThat(decodedToken).isNotNull();
|
||||||
|
|
||||||
|
final Map<String, Object> claims = decodedToken.getClaims();
|
||||||
|
assertThat(claims).isNotNull()
|
||||||
|
.isNotEmpty()
|
||||||
|
.containsEntry(USERNAME_CLAIM, "piotrek");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user