Selaa lähdekoodia

Add InMemoryReactiveClientRegistrationRepository

Issue: gh-4807
Rob Winch 7 vuotta sitten
vanhempi
commit
a02b0c17f8

+ 82 - 0
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/InMemoryReactiveClientRegistrationRepository.java

@@ -0,0 +1,82 @@
+/*
+ * 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.client.registration;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.springframework.util.Assert;
+import org.springframework.util.ConcurrentReferenceHashMap;
+
+import reactor.core.publisher.Mono;
+
+/**
+ * A Reactive {@link ClientRegistrationRepository} that stores {@link ClientRegistration}(s) in-memory.
+ *
+ * @author Rob Winch
+ * @since 5.1
+ * @see ClientRegistrationRepository
+ * @see ClientRegistration
+ */
+public final class InMemoryReactiveClientRegistrationRepository
+		implements ReactiveClientRegistrationRepository, Iterable<ClientRegistration> {
+
+	private final Map<String, ClientRegistration> clientIdToClientRegistration;
+
+	/**
+	 * Constructs an {@code InMemoryReactiveClientRegistrationRepository} using the provided parameters.
+	 *
+	 * @param registrations the client registration(s)
+	 */
+	public InMemoryReactiveClientRegistrationRepository(ClientRegistration... registrations) {
+		Assert.notEmpty(registrations, "registrations cannot be empty");
+		this.clientIdToClientRegistration = new ConcurrentReferenceHashMap<>();
+		for (ClientRegistration registration : registrations) {
+			Assert.notNull(registration, "registrations cannot contain null values");
+			this.clientIdToClientRegistration.put(registration.getRegistrationId(), registration);
+		}
+	}
+
+	/**
+	 * Constructs an {@code InMemoryReactiveClientRegistrationRepository} using the provided parameters.
+	 *
+	 * @param registrations the client registration(s)
+	 */
+	public InMemoryReactiveClientRegistrationRepository(List<ClientRegistration> registrations) {
+		Assert.notEmpty(registrations, "registrations cannot be null or empty");
+		this.clientIdToClientRegistration = registrations.stream()
+				.collect(Collectors.toConcurrentMap(ClientRegistration::getRegistrationId, Function.identity()));
+	}
+
+
+	@Override
+	public Mono<ClientRegistration> findByRegistrationId(String registrationId) {
+		return Mono.justOrEmpty(this.clientIdToClientRegistration.get(registrationId));
+	}
+
+	/**
+	 * Returns an {@code Iterator} of {@link ClientRegistration}.
+	 *
+	 * @return an {@code Iterator<ClientRegistration>}
+	 */
+	@Override
+	public Iterator<ClientRegistration> iterator() {
+		return this.clientIdToClientRegistration.values().iterator();
+	}
+}

+ 45 - 0
oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ReactiveClientRegistrationRepository.java

@@ -0,0 +1,45 @@
+/*
+ * 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.client.registration;
+
+import reactor.core.publisher.Mono;
+
+/**
+ * A reactive repository for OAuth 2.0 / OpenID Connect 1.0 {@link ClientRegistration}(s).
+ *
+ * <p>
+ * <b>NOTE:</b> Client registration information is ultimately stored and owned
+ * by the associated Authorization Server.
+ * Therefore, this repository provides the capability to store a sub-set copy
+ * of the <i>primary</i> client registration information
+ * externally from the Authorization Server.
+ *
+ * @author Rob Winch
+ * @since 5.1
+ * @see ClientRegistration
+ */
+public interface ReactiveClientRegistrationRepository {
+
+	/**
+	 * Returns the client registration identified by the provided {@code registrationId}, or {@code null} if not found.
+	 *
+	 * @param registrationId the registration identifier
+	 * @return the {@link ClientRegistration} if found, otherwise {@code null}
+	 */
+	Mono<ClientRegistration> findByRegistrationId(String registrationId);
+
+}

+ 103 - 0
oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/InMemoryReactiveClientRegistrationRepositoryTests.java

@@ -0,0 +1,103 @@
+/*
+ * 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.client.registration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.security.oauth2.core.AuthorizationGrantType;
+import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
+
+import reactor.test.StepVerifier;
+
+/**
+ * @author Rob Winch
+ * @since 5.1
+ */
+public class InMemoryReactiveClientRegistrationRepositoryTests {
+
+	private ClientRegistration github = ClientRegistration.withRegistrationId("github")
+			.redirectUriTemplate("{baseUrl}/{action}/oauth2/code/{registrationId}")
+			.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
+			.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
+			.scope("read:user")
+			.authorizationUri("https://github.com/login/oauth/authorize")
+			.tokenUri("https://github.com/login/oauth/access_token")
+			.userInfoUri("https://api.github.com/user")
+			.userNameAttributeName("id")
+			.clientName("GitHub")
+			.clientId("clientId")
+			.clientSecret("clientSecret")
+			.build();
+
+	private InMemoryReactiveClientRegistrationRepository repository;
+
+	@Before
+	public void setup() {
+		this.repository = new InMemoryReactiveClientRegistrationRepository(this.github);
+	}
+
+	@Test
+	public void constructorWhenZeroVarArgsThenIllegalArgumentException() {
+		assertThatThrownBy(() -> new InMemoryReactiveClientRegistrationRepository())
+			.isInstanceOf(IllegalArgumentException.class);
+	}
+
+	@Test
+	public void constructorWhenClientRegistrationArrayThenIllegalArgumentException() {
+		ClientRegistration[] registrations = null;
+		assertThatThrownBy(() -> new InMemoryReactiveClientRegistrationRepository(registrations))
+				.isInstanceOf(IllegalArgumentException.class);
+	}
+
+	@Test
+	public void constructorWhenClientRegistrationListThenIllegalArgumentException() {
+		List<ClientRegistration> registrations = null;
+		assertThatThrownBy(() -> new InMemoryReactiveClientRegistrationRepository(registrations))
+				.isInstanceOf(IllegalArgumentException.class);
+	}
+
+	@Test
+	public void constructorWhenClientRegistrationIsNullThenIllegalArgumentException() {
+		ClientRegistration registration = null;
+		assertThatThrownBy(() -> new InMemoryReactiveClientRegistrationRepository(registration))
+				.isInstanceOf(IllegalArgumentException.class);
+	}
+
+	@Test
+	public void findByRegistrationIdWhenValidIdThenFound() {
+		StepVerifier.create(this.repository.findByRegistrationId(this.github.getRegistrationId()))
+				.expectNext(this.github)
+				.verifyComplete();
+	}
+
+	@Test
+	public void findByRegistrationIdWhenNotValidIdThenEmpty() {
+		StepVerifier.create(this.repository.findByRegistrationId(this.github.getRegistrationId() + "invalid"))
+				.verifyComplete();
+	}
+
+	@Test
+	public void iteratorWhenContainsGithubThenContains() {
+		assertThat(this.repository.iterator())
+			.containsOnly(this.github);
+	}
+}