فهرست منبع

Add DelegatingJwtGrantedAuthoritiesConverter

Closes gh-7596
Ropi 5 سال پیش
والد
کامیت
97cc119d86

+ 80 - 0
oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/DelegatingJwtGrantedAuthoritiesConverter.java

@@ -0,0 +1,80 @@
+/*
+ * Copyright 2002-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.oauth2.server.resource.authentication;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.oauth2.jwt.Jwt;
+
+/**
+ * Implementation of {@link Converter} that wraps multiple {@link Converter} instances into one.
+ *
+ * @author Laszlo Stahorszki
+ * @since 5.5
+ */
+public class DelegatingJwtGrantedAuthoritiesConverter implements Converter<Jwt, Collection<GrantedAuthority>> {
+
+	private final Collection<Converter<Jwt, Collection<GrantedAuthority>>> converters = new HashSet<>();
+
+	/**
+	 * Constructs a {@link DelegatingJwtGrantedAuthoritiesConverter} using the provided {@link Collection} of
+	 * {@link Converter}s
+	 *
+	 * @param converters the {@link Collection} of {@link Converter}s to use
+	 */
+	public DelegatingJwtGrantedAuthoritiesConverter(Collection<Converter<Jwt, Collection<GrantedAuthority>>> converters) {
+		this.converters.addAll(converters);
+	}
+
+	/**
+	 * Constructs a {@link DelegatingJwtGrantedAuthoritiesConverter} using the provided array of
+	 * {@link Converter}s
+	 *
+	 * @param converters the array of {@link Converter}s to use
+	 */
+	@SafeVarargs
+	public DelegatingJwtGrantedAuthoritiesConverter(Converter<Jwt, Collection<GrantedAuthority>>... converters) {
+		this(Arrays.asList(converters));
+	}
+
+	/**
+	 * Collects the {@link Collection} of authorities from the provided {@link Jwt} token. The method iterates through
+	 * all the {@link Converter}s provided during construction and returns the union of {@link GrantedAuthority}s
+	 * they extract.
+	 * @param source the source object to convert, which must be an instance of {@code S} (never {@code null})
+	 * @return the converted object, which must be an instance of {@code T} (potentially {@code null})
+	 * @throws IllegalArgumentException if the source cannot be converted to the desired target type
+	 */
+	@Override
+	public Collection<GrantedAuthority> convert(Jwt source) {
+		Collection<GrantedAuthority> result = new LinkedHashSet<>();
+
+		for (Converter<Jwt, Collection<GrantedAuthority>> converter: this.converters) {
+			Collection<GrantedAuthority> authorities = converter.convert(source);
+			if (authorities != null) {
+				result.addAll(authorities);
+			}
+		}
+
+		return result;
+	}
+}

+ 79 - 0
oauth2/oauth2-resource-server/src/test/java/org/springframework/security/oauth2/server/resource/authentication/DelegatingJwtGrantedAuthoritiesConverterTest.java

@@ -0,0 +1,79 @@
+/*
+ * Copyright 2002-2020 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.oauth2.server.resource.authentication;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.junit.Test;
+
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.oauth2.jwt.Jwt;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for verifying {@link DelegatingJwtGrantedAuthoritiesConverter}
+ *
+ * @author Laszlo Stahorszki
+ */
+public class DelegatingJwtGrantedAuthoritiesConverterTest {
+
+	@Test
+	public void convertNoConverters() {
+		DelegatingJwtGrantedAuthoritiesConverter subject = new DelegatingJwtGrantedAuthoritiesConverter();
+
+		assertThat(subject.convert(Jwt.withTokenValue("some-token-value")
+				.header("header", "value")
+				.claim("claim", "value")
+				.build())).isEmpty();
+	}
+
+	@Test
+	public void convert() {
+		DelegatingJwtGrantedAuthoritiesConverter subject = new DelegatingJwtGrantedAuthoritiesConverter(((source) ->
+				Collections.singletonList(new SimpleGrantedAuthority(source.getClaim("claim")))));
+
+		assertThat(subject.convert(Jwt.withTokenValue("some-token-value")
+				.header("header", "value")
+				.claim("claim", "value")
+				.build())).containsExactlyInAnyOrder(new SimpleGrantedAuthority("value"));
+	}
+
+	@Test
+	public void convertMultipleConverters() {
+		DelegatingJwtGrantedAuthoritiesConverter subject = new DelegatingJwtGrantedAuthoritiesConverter(
+				(source) -> Collections.singletonList(new SimpleGrantedAuthority(source.getClaim("claim"))),
+				(source) -> Arrays.stream(source.getHeaders().entrySet().toArray(new Map.Entry[]{}))
+						.map(Map.Entry::getValue)
+						.map(Object::toString)
+						.map(SimpleGrantedAuthority::new)
+						.collect(Collectors.toList()));
+
+		assertThat(subject.convert(Jwt.withTokenValue("some-token-value")
+				.header("header", "value")
+				.header("header2", "value2")
+				.claim("claim", "value3")
+				.build())).containsExactlyInAnyOrder(
+						new SimpleGrantedAuthority("value"),
+						new SimpleGrantedAuthority("value2"),
+						new SimpleGrantedAuthority("value3")
+		);
+	}
+}