From 9f56928407ff75a0736a3b7a632c65aae8d34d6d Mon Sep 17 00:00:00 2001 From: Justin Tay <49700559+justin-tay@users.noreply.github.com> Date: Fri, 7 Apr 2023 01:11:42 +0800 Subject: [PATCH] Add SupplierClientRegistrationRepository Closes gh-12967 --- .../SupplierClientRegistrationRepository.java | 65 +++++++++++ ...lierClientRegistrationRepositoryTests.java | 103 ++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/SupplierClientRegistrationRepository.java create mode 100644 oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/SupplierClientRegistrationRepositoryTests.java diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/SupplierClientRegistrationRepository.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/SupplierClientRegistrationRepository.java new file mode 100644 index 00000000000..d044eb33a2e --- /dev/null +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/SupplierClientRegistrationRepository.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2023 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.client.registration; + +import java.util.Iterator; +import java.util.function.Supplier; + +import org.springframework.util.Assert; +import org.springframework.util.function.SingletonSupplier; + +/** + * A {@link ClientRegistrationRepository} that lazily calls to retrieve + * {@link ClientRegistration}(s) when requested. + * + * @author Justin Tay + * @since 6.2 + * @see ClientRegistrationRepository + * @see ClientRegistration + */ +public final class SupplierClientRegistrationRepository + implements ClientRegistrationRepository, Iterable { + + private final Supplier repositorySupplier; + + /** + * Constructs an {@code SupplierClientRegistrationRepository} using the provided + * parameters. + * @param repositorySupplier the client registration repository supplier + */ + public > SupplierClientRegistrationRepository( + Supplier repositorySupplier) { + Assert.notNull(repositorySupplier, "repositorySupplier cannot be null"); + this.repositorySupplier = SingletonSupplier.of(repositorySupplier); + } + + @Override + public ClientRegistration findByRegistrationId(String registrationId) { + Assert.hasText(registrationId, "registrationId cannot be empty"); + return this.repositorySupplier.get().findByRegistrationId(registrationId); + } + + /** + * Returns an {@code Iterator} of {@link ClientRegistration}. + * @return an {@code Iterator} + */ + @Override + public Iterator iterator() { + return ((Iterable) this.repositorySupplier.get()).iterator(); + } + +} diff --git a/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/SupplierClientRegistrationRepositoryTests.java b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/SupplierClientRegistrationRepositoryTests.java new file mode 100644 index 00000000000..c9ebb65af06 --- /dev/null +++ b/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/registration/SupplierClientRegistrationRepositoryTests.java @@ -0,0 +1,103 @@ +/* + * Copyright 2002-2023 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.client.registration; + +import java.util.Collections; +import java.util.function.Supplier; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link SupplierClientRegistrationRepository}. + * + * @author Justin Tay + * @since 6.2 + */ +@ExtendWith(MockitoExtension.class) +public class SupplierClientRegistrationRepositoryTests { + + private ClientRegistration registration = TestClientRegistrations.clientRegistration().build(); + + private SupplierClientRegistrationRepository clients = new SupplierClientRegistrationRepository( + () -> new InMemoryClientRegistrationRepository(this.registration)); + + @Mock + Supplier clientRegistrationRepositorySupplier; + + @Test + public void constructorMapClientRegistrationWhenNullThenIllegalArgumentException() { + assertThatIllegalArgumentException().isThrownBy(() -> new SupplierClientRegistrationRepository(null)); + } + + @Test + public void constructorMapClientRegistrationWhenEmptyMapThenRepositoryIsEmpty() { + SupplierClientRegistrationRepository clients = new SupplierClientRegistrationRepository( + () -> new InMemoryClientRegistrationRepository(Collections.emptyMap())); + assertThat(clients).isEmpty(); + } + + @Test + public void findByRegistrationIdWhenFoundThenFound() { + String id = this.registration.getRegistrationId(); + assertThat(this.clients.findByRegistrationId(id)).isEqualTo(this.registration); + } + + @Test + public void findByRegistrationIdWhenNotFoundThenNull() { + String id = this.registration.getRegistrationId() + "MISSING"; + assertThat(this.clients.findByRegistrationId(id)).isNull(); + } + + @Test + public void findByRegistrationIdWhenNullIdThenIllegalArgumentException() { + assertThatIllegalArgumentException().isThrownBy(() -> this.clients.findByRegistrationId(null)); + } + + @Test + public void findByRegistrationIdThenSingletonSupplierCached() { + SupplierClientRegistrationRepository test = new SupplierClientRegistrationRepository( + this.clientRegistrationRepositorySupplier); + given(this.clientRegistrationRepositorySupplier.get()) + .willReturn(new InMemoryClientRegistrationRepository(this.registration)); + String id = this.registration.getRegistrationId(); + assertThat(test.findByRegistrationId(id)).isEqualTo(this.registration); + id = this.registration.getRegistrationId(); + assertThat(test.findByRegistrationId(id)).isEqualTo(this.registration); + verify(this.clientRegistrationRepositorySupplier, times(1)).get(); + } + + @Test + public void iteratorWhenRemoveThenThrowsUnsupportedOperationException() { + assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(this.clients.iterator()::remove); + } + + @Test + public void iteratorWhenGetThenContainsAll() { + assertThat(this.clients).containsOnly(this.registration); + } + +}