Introduce ReactiveJwtAuthenticationConverter
Some changes based on PR comments Fixes gh-6273
This commit is contained in:
parent
cb0ea0241b
commit
0f7dff3774
|
@ -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<Jwt, Collection<GrantedAuthority>>} 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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<AbstractAuthenticationToken>}.
|
||||
*
|
||||
* @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<Jwt, Flux<GrantedAuthority>>} 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;
|
||||
}
|
||||
}
|
|
@ -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<Jwt, Collection<GrantedAuthority>>} to a
|
||||
* {@link Converter Converter<Jwt, Flux<GrantedAuthority>>}.
|
||||
* <p>
|
||||
* Make sure the {@link Converter Converter<Jwt, Collection<GrantedAuthority>>}
|
||||
* 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));
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue