Introduce ReactiveJwtAuthenticationConverter

Some changes based on PR comments

Fixes gh-6273
This commit is contained in:
Eric Deandrea 2018-12-12 08:11:12 -05:00 committed by Josh Cummings
parent cb0ea0241b
commit 0f7dff3774
8 changed files with 511 additions and 88 deletions

View File

@ -16,17 +16,13 @@
package org.springframework.security.oauth2.server.resource.authentication;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.util.StringUtils;
import org.springframework.util.Assert;
/**
* @author Rob Winch
@ -34,39 +30,39 @@ import org.springframework.util.StringUtils;
* @since 5.1
*/
public class JwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken> {
private static final String SCOPE_AUTHORITY_PREFIX = "SCOPE_";
private static final Collection<String> WELL_KNOWN_SCOPE_ATTRIBUTE_NAMES =
Arrays.asList("scope", "scp");
private Converter<Jwt, Collection<GrantedAuthority>> jwtGrantedAuthoritiesConverter
= new JwtGrantedAuthoritiesConverter();
@Override
public final AbstractAuthenticationToken convert(Jwt jwt) {
Collection<GrantedAuthority> authorities = extractAuthorities(jwt);
return new JwtAuthenticationToken(jwt, authorities);
}
/**
* Extracts the {@link GrantedAuthority}s from scope attributes typically found in a {@link Jwt}
*
* @param jwt The token
* @return The collection of {@link GrantedAuthority}s found on the token
* @deprecated Since 5.2. Use your own custom converter instead
* @see JwtGrantedAuthoritiesConverter
* @see #setJwtGrantedAuthoritiesConverter(Converter)
*/
@Deprecated
protected Collection<GrantedAuthority> extractAuthorities(Jwt jwt) {
return this.getScopes(jwt)
.stream()
.map(authority -> SCOPE_AUTHORITY_PREFIX + authority)
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
return this.jwtGrantedAuthoritiesConverter.convert(jwt);
}
private Collection<String> getScopes(Jwt jwt) {
for ( String attributeName : WELL_KNOWN_SCOPE_ATTRIBUTE_NAMES ) {
Object scopes = jwt.getClaims().get(attributeName);
if (scopes instanceof String) {
if (StringUtils.hasText((String) scopes)) {
return Arrays.asList(((String) scopes).split(" "));
} else {
return Collections.emptyList();
}
} else if (scopes instanceof Collection) {
return (Collection<String>) scopes;
}
}
return Collections.emptyList();
/**
* Sets the {@link Converter Converter&lt;Jwt, Collection&lt;GrantedAuthority&gt;&gt;} to use.
* Defaults to {@link JwtGrantedAuthoritiesConverter}.
*
* @param jwtGrantedAuthoritiesConverter The converter
* @since 5.2
* @see JwtGrantedAuthoritiesConverter
*/
public void setJwtGrantedAuthoritiesConverter(Converter<Jwt, Collection<GrantedAuthority>> jwtGrantedAuthoritiesConverter) {
Assert.notNull(jwtGrantedAuthoritiesConverter, "jwtGrantedAuthoritiesConverter cannot be null");
this.jwtGrantedAuthoritiesConverter = jwtGrantedAuthoritiesConverter;
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright 2002-2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.server.resource.authentication;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.stream.Collectors;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.util.StringUtils;
/**
* Extracts the {@link GrantedAuthority}s from scope attributes typically found in a
* {@link Jwt}.
*
* @author Eric Deandrea
* @since 5.2
*/
public final class JwtGrantedAuthoritiesConverter implements Converter<Jwt, Collection<GrantedAuthority>> {
private static final String SCOPE_AUTHORITY_PREFIX = "SCOPE_";
private static final Collection<String> WELL_KNOWN_SCOPE_ATTRIBUTE_NAMES =
Arrays.asList("scope", "scp");
/**
* Extracts the authorities
* @param jwt The {@link Jwt} token
* @return The {@link GrantedAuthority authorities} read from the token scopes
*/
@Override
public Collection<GrantedAuthority> convert(Jwt jwt) {
return getScopes(jwt)
.stream()
.map(authority -> SCOPE_AUTHORITY_PREFIX + authority)
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
/**
* Gets the scopes from a {@link Jwt} token
* @param jwt The {@link Jwt} token
* @return The scopes from the token
*/
private Collection<String> getScopes(Jwt jwt) {
for ( String attributeName : WELL_KNOWN_SCOPE_ATTRIBUTE_NAMES ) {
Object scopes = jwt.getClaims().get(attributeName);
if (scopes instanceof String) {
if (StringUtils.hasText((String) scopes)) {
return Arrays.asList(((String) scopes).split(" "));
} else {
return Collections.emptyList();
}
} else if (scopes instanceof Collection) {
return (Collection<String>) scopes;
}
}
return Collections.emptyList();
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 2002-2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.server.resource.authentication;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.util.Assert;
/**
* Reactive version of {@link JwtAuthenticationConverter} for converting a {@link Jwt}
* to a {@link AbstractAuthenticationToken Mono&lt;AbstractAuthenticationToken&gt;}.
*
* @author Eric Deandrea
* @since 5.2
*/
public final class ReactiveJwtAuthenticationConverter implements Converter<Jwt, Mono<AbstractAuthenticationToken>> {
private Converter<Jwt, Flux<GrantedAuthority>> jwtGrantedAuthoritiesConverter
= new ReactiveJwtGrantedAuthoritiesConverterAdapter(new JwtGrantedAuthoritiesConverter());
@Override
public Mono<AbstractAuthenticationToken> convert(Jwt jwt) {
return this.jwtGrantedAuthoritiesConverter.convert(jwt)
.collectList()
.map(authorities -> new JwtAuthenticationToken(jwt, authorities));
}
/**
* Sets the {@link Converter Converter&lt;Jwt, Flux&lt;GrantedAuthority&gt;&gt;} to use.
* Defaults to a reactive {@link JwtGrantedAuthoritiesConverter}.
*
* @param jwtGrantedAuthoritiesConverter The converter
* @see JwtGrantedAuthoritiesConverter
*/
public void setJwtGrantedAuthoritiesConverter(Converter<Jwt, Flux<GrantedAuthority>> jwtGrantedAuthoritiesConverter) {
Assert.notNull(jwtGrantedAuthoritiesConverter, "jwtGrantedAuthoritiesConverter cannot be null");
this.jwtGrantedAuthoritiesConverter = jwtGrantedAuthoritiesConverter;
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright 2002-2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.server.resource.authentication;
import java.util.Collection;
import reactor.core.publisher.Flux;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.util.Assert;
/**
* Adapts a {@link Converter Converter&lt;Jwt, Collection&lt;GrantedAuthority&gt;&gt;} to a
* {@link Converter Converter&lt;Jwt, Flux&lt;GrantedAuthority&gt;&gt;}.
* <p>
* Make sure the {@link Converter Converter&lt;Jwt, Collection&lt;GrantedAuthority&gt;&gt;}
* being adapted is non-blocking.
* </p>
*
* @author Eric Deandrea
* @since 5.2
* @see JwtGrantedAuthoritiesConverter
*/
public final class ReactiveJwtGrantedAuthoritiesConverterAdapter implements Converter<Jwt, Flux<GrantedAuthority>> {
private final Converter<Jwt, Collection<GrantedAuthority>> grantedAuthoritiesConverter;
public ReactiveJwtGrantedAuthoritiesConverterAdapter(Converter<Jwt, Collection<GrantedAuthority>> grantedAuthoritiesConverter) {
Assert.notNull(grantedAuthoritiesConverter, "grantedAuthoritiesConverter cannot be null");
this.grantedAuthoritiesConverter = grantedAuthoritiesConverter;
}
@Override
public Flux<GrantedAuthority> convert(Jwt jwt) {
return Flux.fromIterable(this.grantedAuthoritiesConverter.convert(jwt));
}
}

View File

@ -16,6 +16,9 @@
package org.springframework.security.oauth2.server.resource.authentication;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
@ -23,17 +26,15 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.assertj.core.util.Maps;
import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
import org.springframework.security.oauth2.jwt.Jwt;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link JwtAuthenticationConverter}
*
@ -43,7 +44,7 @@ public class JwtAuthenticationConverterTests {
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
@Test
public void convertWhenTokenHasScopeAttributeThenTranslatedToAuthorities() {
public void convertWhenDefaultGrantedAuthoritiesConverterSet() {
Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write"));
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt);
@ -55,68 +56,26 @@ public class JwtAuthenticationConverterTests {
}
@Test
public void convertWhenTokenHasEmptyScopeAttributeThenTranslatedToNoAuthorities() {
Jwt jwt = this.jwt(Collections.singletonMap("scope", ""));
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt);
Collection<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly();
public void whenSettingNullGrantedAuthoritiesConverter() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(null))
.withMessage("jwtGrantedAuthoritiesConverter cannot be null");
}
@Test
public void convertWhenTokenHasScpAttributeThenTranslatedToAuthorities() {
Jwt jwt = this.jwt(Collections.singletonMap("scp", Arrays.asList("message:read", "message:write")));
public void convertWithOverriddenGrantedAuthoritiesConverter() {
Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write"));
Converter<Jwt, Collection<GrantedAuthority>> grantedAuthoritiesConverter =
token -> Arrays.asList(new SimpleGrantedAuthority("blah"));
this.jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt);
Collection<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("SCOPE_message:read"),
new SimpleGrantedAuthority("SCOPE_message:write"));
}
@Test
public void convertWhenTokenHasEmptyScpAttributeThenTranslatedToNoAuthorities() {
Jwt jwt = this.jwt(Maps.newHashMap("scp", Arrays.asList()));
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt);
Collection<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly();
}
@Test
public void convertWhenTokenHasBothScopeAndScpThenScopeAttributeIsTranslatedToAuthorities() {
Map<String, Object> claims = new HashMap<>();
claims.put("scp", Arrays.asList("message:read", "message:write"));
claims.put("scope", "missive:read missive:write");
Jwt jwt = this.jwt(claims);
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt);
Collection<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("SCOPE_missive:read"),
new SimpleGrantedAuthority("SCOPE_missive:write"));
}
@Test
public void convertWhenTokenHasEmptyScopeAndNonEmptyScpThenScopeAttributeIsTranslatedToNoAuthorities() {
Map<String, Object> claims = new HashMap<>();
claims.put("scp", Arrays.asList("message:read", "message:write"));
claims.put("scope", "");
Jwt jwt = this.jwt(claims);
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt);
Collection<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly();
new SimpleGrantedAuthority("blah"));
}
private Jwt jwt(Map<String, Object> claims) {

View File

@ -0,0 +1,117 @@
/*
* Copyright 2002-2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.server.resource.authentication;
import static org.assertj.core.api.Assertions.assertThat;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.assertj.core.util.Maps;
import org.junit.Test;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
import org.springframework.security.oauth2.jwt.Jwt;
/**
* Tests for {@link JwtGrantedAuthoritiesConverter}
*
* @author Eric Deandrea
* @since 5.2
*/
public class JwtGrantedAuthoritiesConverterTests {
private JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
@Test
public void convertWhenTokenHasScopeAttributeThenTranslatedToAuthorities() {
Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write"));
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("SCOPE_message:read"),
new SimpleGrantedAuthority("SCOPE_message:write"));
}
@Test
public void convertWhenTokenHasEmptyScopeAttributeThenTranslatedToNoAuthorities() {
Jwt jwt = this.jwt(Collections.singletonMap("scope", ""));
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly();
}
@Test
public void convertWhenTokenHasScpAttributeThenTranslatedToAuthorities() {
Jwt jwt = this.jwt(Collections.singletonMap("scp", Arrays.asList("message:read", "message:write")));
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("SCOPE_message:read"),
new SimpleGrantedAuthority("SCOPE_message:write"));
}
@Test
public void convertWhenTokenHasEmptyScpAttributeThenTranslatedToNoAuthorities() {
Jwt jwt = this.jwt(Maps.newHashMap("scp", Arrays.asList()));
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly();
}
@Test
public void convertWhenTokenHasBothScopeAndScpThenScopeAttributeIsTranslatedToAuthorities() {
Map<String, Object> claims = new HashMap<>();
claims.put("scp", Arrays.asList("message:read", "message:write"));
claims.put("scope", "missive:read missive:write");
Jwt jwt = this.jwt(claims);
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("SCOPE_missive:read"),
new SimpleGrantedAuthority("SCOPE_missive:write"));
}
@Test
public void convertWhenTokenHasEmptyScopeAndNonEmptyScpThenScopeAttributeIsTranslatedToNoAuthorities() {
Map<String, Object> claims = new HashMap<>();
claims.put("scp", Arrays.asList("message:read", "message:write"));
claims.put("scope", "");
Jwt jwt = this.jwt(claims);
Collection<GrantedAuthority> authorities = this.jwtGrantedAuthoritiesConverter.convert(jwt);
assertThat(authorities).containsExactly();
}
private Jwt jwt(Map<String, Object> claims) {
Map<String, Object> headers = new HashMap<>();
headers.put("alg", JwsAlgorithms.RS256);
return new Jwt("token", Instant.now(), Instant.now().plusSeconds(3600), headers, claims);
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright 2002-2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.server.resource.authentication;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import reactor.core.publisher.Flux;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
import org.springframework.security.oauth2.jwt.Jwt;
/**
* Tests for {@link ReactiveJwtAuthenticationConverter}
*
* @author Eric Deandrea
* @since 5.2
*/
public class ReactiveJwtAuthenticationConverterTests {
ReactiveJwtAuthenticationConverter jwtAuthenticationConverter = new ReactiveJwtAuthenticationConverter();
@Test
public void convertWhenDefaultGrantedAuthoritiesConverterSet() {
Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write"));
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block();
Collection<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("SCOPE_message:read"),
new SimpleGrantedAuthority("SCOPE_message:write"));
}
@Test
public void whenSettingNullGrantedAuthoritiesConverter() {
assertThatIllegalArgumentException()
.isThrownBy(() -> this.jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(null))
.withMessage("jwtGrantedAuthoritiesConverter cannot be null");
}
@Test
public void convertWithOverriddenGrantedAuthoritiesConverter() {
Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write"));
Converter<Jwt, Flux<GrantedAuthority>> grantedAuthoritiesConverter =
token -> Flux.just(new SimpleGrantedAuthority("blah"));
this.jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(grantedAuthoritiesConverter);
AbstractAuthenticationToken authentication = this.jwtAuthenticationConverter.convert(jwt).block();
Collection<GrantedAuthority> authorities = authentication.getAuthorities();
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("blah"));
}
private Jwt jwt(Map<String, Object> claims) {
Map<String, Object> headers = new HashMap<>();
headers.put("alg", JwsAlgorithms.RS256);
return new Jwt("token", Instant.now(), Instant.now().plusSeconds(3600), headers, claims);
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright 2002-2018 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.server.resource.authentication;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import org.junit.Test;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
import org.springframework.security.oauth2.jwt.Jwt;
/**
* Tests for {@link ReactiveJwtGrantedAuthoritiesConverterAdapter}
*
* @author Eric Deandrea
* @since 5.2
*/
public class ReactiveJwtGrantedAuthoritiesConverterAdapterTests {
@Test
public void convertWithGrantedAuthoritiesConverter() {
Jwt jwt = this.jwt(Collections.singletonMap("scope", "message:read message:write"));
Converter<Jwt, Collection<GrantedAuthority>> grantedAuthoritiesConverter =
token -> Arrays.asList(new SimpleGrantedAuthority("blah"));
Collection<GrantedAuthority> authorities =
new ReactiveJwtGrantedAuthoritiesConverterAdapter(grantedAuthoritiesConverter)
.convert(jwt)
.toStream()
.collect(Collectors.toList());
assertThat(authorities).containsExactly(
new SimpleGrantedAuthority("blah"));
}
@Test
public void whenConstructingWithInvalidConverter() {
assertThatIllegalArgumentException()
.isThrownBy(() -> new ReactiveJwtGrantedAuthoritiesConverterAdapter(null))
.withMessage("grantedAuthoritiesConverter cannot be null");
}
private Jwt jwt(Map<String, Object> claims) {
Map<String, Object> headers = new HashMap<>();
headers.put("alg", JwsAlgorithms.RS256);
return new Jwt("token", Instant.now(), Instant.now().plusSeconds(3600), headers, claims);
}
}