Add InMemoryReactiveClientRegistrationRepository

Issue: gh-4807
This commit is contained in:
Rob Winch 2018-04-23 22:07:16 -05:00
parent ca9cd20832
commit a02b0c17f8
3 changed files with 230 additions and 0 deletions

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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);
}
}