11 changed files with 451 additions and 49 deletions
@ -0,0 +1,78 @@
@@ -0,0 +1,78 @@
|
||||
/* |
||||
* Copyright 2020-2022 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.authorization; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import org.springframework.lang.Nullable; |
||||
import org.springframework.security.oauth2.core.OAuth2Token; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* An {@link OAuth2TokenGenerator} that simply delegates to it's |
||||
* internal {@code List} of {@link OAuth2TokenGenerator}(s). |
||||
* <p> |
||||
* Each {@link OAuth2TokenGenerator} is given a chance to |
||||
* {@link OAuth2TokenGenerator#generate(OAuth2TokenContext)} |
||||
* with the first {@code non-null} {@link OAuth2Token} being returned. |
||||
* |
||||
* @author Joe Grandja |
||||
* @since 0.2.3 |
||||
* @see OAuth2TokenGenerator |
||||
* @see JwtGenerator |
||||
* @see OAuth2RefreshTokenGenerator |
||||
*/ |
||||
public final class DelegatingOAuth2TokenGenerator implements OAuth2TokenGenerator<OAuth2Token> { |
||||
private final List<OAuth2TokenGenerator<OAuth2Token>> tokenGenerators; |
||||
|
||||
/** |
||||
* Constructs a {@code DelegatingOAuth2TokenGenerator} using the provided parameters. |
||||
* |
||||
* @param tokenGenerators an array of {@link OAuth2TokenGenerator}(s) |
||||
*/ |
||||
@SafeVarargs |
||||
public DelegatingOAuth2TokenGenerator(OAuth2TokenGenerator<? extends OAuth2Token>... tokenGenerators) { |
||||
Assert.notEmpty(tokenGenerators, "tokenGenerators cannot be empty"); |
||||
Assert.noNullElements(tokenGenerators, "tokenGenerator cannot be null"); |
||||
this.tokenGenerators = Collections.unmodifiableList(asList(tokenGenerators)); |
||||
} |
||||
|
||||
@Nullable |
||||
@Override |
||||
public OAuth2Token generate(OAuth2TokenContext context) { |
||||
for (OAuth2TokenGenerator<OAuth2Token> tokenGenerator : this.tokenGenerators) { |
||||
OAuth2Token token = tokenGenerator.generate(context); |
||||
if (token != null) { |
||||
return token; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
private static List<OAuth2TokenGenerator<OAuth2Token>> asList( |
||||
OAuth2TokenGenerator<? extends OAuth2Token>... tokenGenerators) { |
||||
|
||||
List<OAuth2TokenGenerator<OAuth2Token>> tokenGeneratorList = new ArrayList<>(); |
||||
for (OAuth2TokenGenerator<? extends OAuth2Token> tokenGenerator : tokenGenerators) { |
||||
tokenGeneratorList.add((OAuth2TokenGenerator<OAuth2Token>) tokenGenerator); |
||||
} |
||||
return tokenGeneratorList; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,50 @@
@@ -0,0 +1,50 @@
|
||||
/* |
||||
* Copyright 2020-2022 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.authorization; |
||||
|
||||
import java.time.Instant; |
||||
import java.util.Base64; |
||||
|
||||
import org.springframework.lang.Nullable; |
||||
import org.springframework.security.crypto.keygen.Base64StringKeyGenerator; |
||||
import org.springframework.security.crypto.keygen.StringKeyGenerator; |
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken; |
||||
import org.springframework.security.oauth2.core.OAuth2TokenType; |
||||
|
||||
/** |
||||
* An {@link OAuth2TokenGenerator} that generates an {@link OAuth2RefreshToken}. |
||||
* |
||||
* @author Joe Grandja |
||||
* @since 0.2.3 |
||||
* @see OAuth2TokenGenerator |
||||
* @see OAuth2RefreshToken |
||||
*/ |
||||
public final class OAuth2RefreshTokenGenerator implements OAuth2TokenGenerator<OAuth2RefreshToken> { |
||||
private final StringKeyGenerator refreshTokenGenerator = |
||||
new Base64StringKeyGenerator(Base64.getUrlEncoder().withoutPadding(), 96); |
||||
|
||||
@Nullable |
||||
@Override |
||||
public OAuth2RefreshToken generate(OAuth2TokenContext context) { |
||||
if (!OAuth2TokenType.REFRESH_TOKEN.equals(context.getTokenType())) { |
||||
return null; |
||||
} |
||||
Instant issuedAt = Instant.now(); |
||||
Instant expiresAt = issuedAt.plus(context.getRegisteredClient().getTokenSettings().getRefreshTokenTimeToLive()); |
||||
return new OAuth2RefreshToken(this.refreshTokenGenerator.generateKey(), issuedAt, expiresAt); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
/* |
||||
* Copyright 2020-2022 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.authorization; |
||||
|
||||
import java.time.Instant; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken; |
||||
import org.springframework.security.oauth2.core.OAuth2Token; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy; |
||||
import static org.mockito.ArgumentMatchers.any; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.when; |
||||
|
||||
/** |
||||
* Tests for {@link DelegatingOAuth2TokenGenerator}. |
||||
* |
||||
* @author Joe Grandja |
||||
*/ |
||||
public class DelegatingOAuth2TokenGeneratorTests { |
||||
|
||||
@Test |
||||
@SuppressWarnings("unchecked") |
||||
public void constructorWhenTokenGeneratorsEmptyThenThrowIllegalArgumentException() { |
||||
OAuth2TokenGenerator<OAuth2Token>[] tokenGenerators = new OAuth2TokenGenerator[0]; |
||||
assertThatThrownBy(() -> new DelegatingOAuth2TokenGenerator(tokenGenerators)) |
||||
.isInstanceOf(IllegalArgumentException.class) |
||||
.hasMessage("tokenGenerators cannot be empty"); |
||||
} |
||||
|
||||
@Test |
||||
public void constructorWhenTokenGeneratorsNullThenThrowIllegalArgumentException() { |
||||
assertThatThrownBy(() -> new DelegatingOAuth2TokenGenerator(null, null)) |
||||
.isInstanceOf(IllegalArgumentException.class) |
||||
.hasMessage("tokenGenerator cannot be null"); |
||||
} |
||||
|
||||
@Test |
||||
@SuppressWarnings("unchecked") |
||||
public void generateWhenTokenGeneratorSupportedThenReturnToken() { |
||||
OAuth2TokenGenerator<OAuth2Token> tokenGenerator1 = mock(OAuth2TokenGenerator.class); |
||||
OAuth2TokenGenerator<OAuth2Token> tokenGenerator2 = mock(OAuth2TokenGenerator.class); |
||||
OAuth2TokenGenerator<OAuth2Token> tokenGenerator3 = mock(OAuth2TokenGenerator.class); |
||||
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER, |
||||
"access-token", Instant.now(), Instant.now().plusSeconds(300)); |
||||
when(tokenGenerator3.generate(any())).thenReturn(accessToken); |
||||
|
||||
DelegatingOAuth2TokenGenerator delegatingTokenGenerator = |
||||
new DelegatingOAuth2TokenGenerator(tokenGenerator1, tokenGenerator2, tokenGenerator3); |
||||
|
||||
OAuth2Token token = delegatingTokenGenerator.generate(DefaultOAuth2TokenContext.builder().build()); |
||||
assertThat(token).isEqualTo(accessToken); |
||||
} |
||||
|
||||
@Test |
||||
@SuppressWarnings("unchecked") |
||||
public void generateWhenTokenGeneratorNotSupportedThenReturnNull() { |
||||
OAuth2TokenGenerator<OAuth2Token> tokenGenerator1 = mock(OAuth2TokenGenerator.class); |
||||
OAuth2TokenGenerator<OAuth2Token> tokenGenerator2 = mock(OAuth2TokenGenerator.class); |
||||
OAuth2TokenGenerator<OAuth2Token> tokenGenerator3 = mock(OAuth2TokenGenerator.class); |
||||
|
||||
DelegatingOAuth2TokenGenerator delegatingTokenGenerator = |
||||
new DelegatingOAuth2TokenGenerator(tokenGenerator1, tokenGenerator2, tokenGenerator3); |
||||
|
||||
OAuth2Token token = delegatingTokenGenerator.generate(DefaultOAuth2TokenContext.builder().build()); |
||||
assertThat(token).isNull(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,68 @@
@@ -0,0 +1,68 @@
|
||||
/* |
||||
* Copyright 2020-2022 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.authorization; |
||||
|
||||
import java.time.Instant; |
||||
|
||||
import org.junit.Test; |
||||
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken; |
||||
import org.springframework.security.oauth2.core.OAuth2TokenType; |
||||
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient; |
||||
import org.springframework.security.oauth2.server.authorization.client.TestRegisteredClients; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* Tests for {@link OAuth2RefreshTokenGenerator}. |
||||
* |
||||
* @author Joe Grandja |
||||
*/ |
||||
public class OAuth2RefreshTokenGeneratorTests { |
||||
private final OAuth2RefreshTokenGenerator tokenGenerator = new OAuth2RefreshTokenGenerator(); |
||||
|
||||
@Test |
||||
public void generateWhenUnsupportedTokenTypeThenReturnNull() { |
||||
// @formatter:off
|
||||
OAuth2TokenContext tokenContext = DefaultOAuth2TokenContext.builder() |
||||
.tokenType(OAuth2TokenType.ACCESS_TOKEN) |
||||
.build(); |
||||
// @formatter:on
|
||||
|
||||
assertThat(this.tokenGenerator.generate(tokenContext)).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
public void generateWhenRefreshTokenTypeThenReturnRefreshToken() { |
||||
RegisteredClient registeredClient = TestRegisteredClients.registeredClient().build(); |
||||
|
||||
// @formatter:off
|
||||
OAuth2TokenContext tokenContext = DefaultOAuth2TokenContext.builder() |
||||
.registeredClient(registeredClient) |
||||
.tokenType(OAuth2TokenType.REFRESH_TOKEN) |
||||
.build(); |
||||
// @formatter:on
|
||||
|
||||
OAuth2RefreshToken refreshToken = this.tokenGenerator.generate(tokenContext); |
||||
assertThat(refreshToken).isNotNull(); |
||||
|
||||
Instant issuedAt = Instant.now(); |
||||
Instant expiresAt = issuedAt.plus(tokenContext.getRegisteredClient().getTokenSettings().getRefreshTokenTimeToLive()); |
||||
assertThat(refreshToken.getIssuedAt()).isBetween(issuedAt.minusSeconds(1), issuedAt.plusSeconds(1)); |
||||
assertThat(refreshToken.getExpiresAt()).isBetween(expiresAt.minusSeconds(1), expiresAt.plusSeconds(1)); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue