This is an automated email from the ASF dual-hosted git repository. awasum pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/fineract-cn-permitted-feign-client.git
commit bc6b05877f368083d72f8a31899632e7f7b23d6a Author: myrle-krantz <[email protected]> AuthorDate: Sun May 21 17:12:19 2017 +0200 Minor changes to access token acquisition so that it can be used in rhythm where we don't know in advance which application we'll be needing a token for. --- .../ApplicationTokenedTargetInterceptor.java | 3 +- .../service/ApplicationAccessTokenService.java | 78 ++++++++-------------- .../service/TokenCacheKey.java | 72 ++++++++++++++++++++ .../service/ApplicationAccessTokenServiceTest.java | 23 ++++++- 4 files changed, 121 insertions(+), 55 deletions(-) diff --git a/library/src/main/java/io/mifos/permittedfeignclient/security/ApplicationTokenedTargetInterceptor.java b/library/src/main/java/io/mifos/permittedfeignclient/security/ApplicationTokenedTargetInterceptor.java index 4141d70..60a58ad 100644 --- a/library/src/main/java/io/mifos/permittedfeignclient/security/ApplicationTokenedTargetInterceptor.java +++ b/library/src/main/java/io/mifos/permittedfeignclient/security/ApplicationTokenedTargetInterceptor.java @@ -19,6 +19,7 @@ import feign.RequestInterceptor; import feign.RequestTemplate; import io.mifos.core.api.util.ApiConstants; import io.mifos.core.api.util.UserContextHolder; +import io.mifos.core.lang.TenantContextHolder; import io.mifos.permittedfeignclient.annotation.EndpointSet; import io.mifos.permittedfeignclient.service.ApplicationAccessTokenService; import org.springframework.util.Assert; @@ -48,7 +49,7 @@ public class ApplicationTokenedTargetInterceptor implements RequestInterceptor { public void apply(final RequestTemplate template) { UserContextHolder.getUserContext().ifPresent(userContext -> { template.header(ApiConstants.USER_HEADER, userContext.getUser()); - template.header(ApiConstants.AUTHORIZATION_HEADER, applicationAccessTokenService.getAccessToken(userContext.getUser(), endpointSetIdentifier)); + template.header(ApiConstants.AUTHORIZATION_HEADER, applicationAccessTokenService.getAccessToken(userContext.getUser(), TenantContextHolder.checkedGetIdentifier(), endpointSetIdentifier)); }); } } \ No newline at end of file diff --git a/library/src/main/java/io/mifos/permittedfeignclient/service/ApplicationAccessTokenService.java b/library/src/main/java/io/mifos/permittedfeignclient/service/ApplicationAccessTokenService.java index 082f5ec..c21752b 100644 --- a/library/src/main/java/io/mifos/permittedfeignclient/service/ApplicationAccessTokenService.java +++ b/library/src/main/java/io/mifos/permittedfeignclient/service/ApplicationAccessTokenService.java @@ -20,7 +20,7 @@ import io.mifos.anubis.security.AmitAuthenticationException; import io.mifos.anubis.token.TenantRefreshTokenSerializer; import io.mifos.anubis.token.TokenSerializationResult; import io.mifos.core.lang.ApplicationName; -import io.mifos.core.lang.TenantContextHolder; +import io.mifos.core.lang.AutoTenantContext; import io.mifos.core.lang.security.RsaKeyPairFactory; import io.mifos.identity.api.v1.client.IdentityManager; import io.mifos.identity.api.v1.domain.Authentication; @@ -30,8 +30,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -41,41 +41,6 @@ import java.util.concurrent.TimeUnit; @Component public class ApplicationAccessTokenService { private static final long REFRESH_TOKEN_LIFESPAN = TimeUnit.SECONDS.convert(1, TimeUnit.MINUTES); - private static class TokenCacheKey { - final String user; - final String tenant; - final String endpointSet; - - private TokenCacheKey(final String user, final String tenant, final String endpointSet) { - this.user = user; - this.tenant = tenant; - this.endpointSet = endpointSet; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - TokenCacheKey that = (TokenCacheKey) o; - return Objects.equals(user, that.user) && - Objects.equals(tenant, that.tenant) && - Objects.equals(endpointSet, that.endpointSet); - } - - @Override - public int hashCode() { - return Objects.hash(user, tenant, endpointSet); - } - - @Override - public String toString() { - return "TokenCacheKey{" + - "user='" + user + '\'' + - ", tenant='" + tenant + '\'' + - ", endpointSet='" + endpointSet + '\'' + - '}'; - } - } private final String applicationName; private final TenantSignatureRepository tenantSignatureRepository; @@ -111,32 +76,41 @@ public class ApplicationAccessTokenService { .build(); } - public String getAccessToken(final String user, final String endpointSetIdentifier) { - final TokenCacheKey tokenCacheKey - = new TokenCacheKey(user, TenantContextHolder.checkedGetIdentifier(), endpointSetIdentifier); + @SuppressWarnings("WeakerAccess") + public String getAccessToken(final String user, final String tenant) { + return getAccessToken(user, tenant, null); + } + + public String getAccessToken(final String user, final String tenant, final @Nullable String endpointSetIdentifier) { + final TokenCacheKey tokenCacheKey = new TokenCacheKey(user, tenant, endpointSetIdentifier); final Authentication authentication = accessTokenCache.get(tokenCacheKey); return authentication.getAccessToken(); } private Authentication createAccessToken(final TokenCacheKey tokenCacheKey) { final String refreshToken = refreshTokenCache.get(tokenCacheKey).getToken(); - return identityManager.refresh(refreshToken); + try (final AutoTenantContext ignored = new AutoTenantContext(tokenCacheKey.getTenant())) { + return identityManager.refresh(refreshToken); + } } private TokenSerializationResult createRefreshToken(final TokenCacheKey tokenCacheKey) { - final Optional<RsaKeyPairFactory.KeyPairHolder> optionalSigningKeyPair - = tenantSignatureRepository.getLatestApplicationSigningKeyPair(); + try (final AutoTenantContext ignored = new AutoTenantContext(tokenCacheKey.getTenant())) { + final Optional<RsaKeyPairFactory.KeyPairHolder> optionalSigningKeyPair + = tenantSignatureRepository.getLatestApplicationSigningKeyPair(); + + final RsaKeyPairFactory.KeyPairHolder signingKeyPair = optionalSigningKeyPair.orElseThrow(AmitAuthenticationException::missingTenant); - final RsaKeyPairFactory.KeyPairHolder signingKeyPair = optionalSigningKeyPair.orElseThrow(AmitAuthenticationException::missingTenant); + final TenantRefreshTokenSerializer.Specification specification = new TenantRefreshTokenSerializer.Specification() + .setSourceApplication(applicationName) + .setUser(tokenCacheKey.getUser()) + .setSecondsToLive(REFRESH_TOKEN_LIFESPAN) + .setPrivateKey(signingKeyPair.privateKey()) + .setKeyTimestamp(signingKeyPair.getTimestamp()); - final TenantRefreshTokenSerializer.Specification specification = new TenantRefreshTokenSerializer.Specification() - .setSourceApplication(applicationName) - .setUser(tokenCacheKey.user) - .setSecondsToLive(REFRESH_TOKEN_LIFESPAN) - .setPrivateKey(signingKeyPair.privateKey()) - .setKeyTimestamp(signingKeyPair.getTimestamp()) - .setEndpointSet(tokenCacheKey.endpointSet); + tokenCacheKey.getEndpointSet().ifPresent(specification::setEndpointSet); - return tenantRefreshTokenSerializer.build(specification); + return tenantRefreshTokenSerializer.build(specification); + } } } diff --git a/library/src/main/java/io/mifos/permittedfeignclient/service/TokenCacheKey.java b/library/src/main/java/io/mifos/permittedfeignclient/service/TokenCacheKey.java new file mode 100644 index 0000000..1d203c6 --- /dev/null +++ b/library/src/main/java/io/mifos/permittedfeignclient/service/TokenCacheKey.java @@ -0,0 +1,72 @@ +/* + * Copyright 2017 The Mifos Initiative. + * + * 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 io.mifos.permittedfeignclient.service; + +import javax.annotation.Nullable; +import java.util.Objects; +import java.util.Optional; + +/** + * @author Myrle Krantz + */ +class TokenCacheKey { + private final String user; + private final String tenant; + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + private final Optional<String> endpointSet; + + TokenCacheKey(final String user, final String tenant, final @Nullable String endpointSet) { + this.user = user; + this.tenant = tenant; + this.endpointSet = Optional.ofNullable(endpointSet); + } + + String getUser() { + return user; + } + + String getTenant() { + return tenant; + } + + Optional<String> getEndpointSet() { + return endpointSet; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TokenCacheKey that = (TokenCacheKey) o; + return Objects.equals(user, that.user) && + Objects.equals(tenant, that.tenant) && + Objects.equals(endpointSet, that.endpointSet); + } + + @Override + public int hashCode() { + return Objects.hash(user, tenant, endpointSet); + } + + @Override + public String toString() { + return "TokenCacheKey{" + + "user='" + user + '\'' + + ", tenant='" + tenant + '\'' + + ", endpointSet='" + endpointSet + '\'' + + '}'; + } +} diff --git a/library/src/test/java/io/mifos/permittedfeignclient/service/ApplicationAccessTokenServiceTest.java b/library/src/test/java/io/mifos/permittedfeignclient/service/ApplicationAccessTokenServiceTest.java index 51d3f63..29017b6 100644 --- a/library/src/test/java/io/mifos/permittedfeignclient/service/ApplicationAccessTokenServiceTest.java +++ b/library/src/test/java/io/mifos/permittedfeignclient/service/ApplicationAccessTokenServiceTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2017 The Mifos Initiative. + * + * 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 io.mifos.permittedfeignclient.service; import io.mifos.anubis.config.TenantSignatureRepository; @@ -5,6 +20,7 @@ import io.mifos.anubis.token.TenantRefreshTokenSerializer; import io.mifos.anubis.token.TokenSerializationResult; import io.mifos.core.lang.ApplicationName; import io.mifos.core.lang.AutoTenantContext; +import io.mifos.core.lang.TenantContextHolder; import io.mifos.core.lang.security.RsaKeyPairFactory; import io.mifos.identity.api.v1.client.IdentityManager; import io.mifos.identity.api.v1.domain.Authentication; @@ -48,10 +64,13 @@ public class ApplicationAccessTokenServiceTest { tenantRefreshTokenSerializerMock); try (final AutoTenantContext ignored1 = new AutoTenantContext(TENANT_NAME)) { - final String accessToken = testSubject.getAccessToken(USER_NAME, "blah"); + final String accessTokenWithoutCallEndpointSet = testSubject.getAccessToken(USER_NAME, TenantContextHolder.checkedGetIdentifier()); + Assert.assertEquals(BEARER_TOKEN_MOCK, accessTokenWithoutCallEndpointSet); + + final String accessToken = testSubject.getAccessToken(USER_NAME, TenantContextHolder.checkedGetIdentifier(), "blah"); Assert.assertEquals(BEARER_TOKEN_MOCK, accessToken); - final String accessTokenAgain = testSubject.getAccessToken(USER_NAME, "blah"); + final String accessTokenAgain = testSubject.getAccessToken(USER_NAME, TenantContextHolder.checkedGetIdentifier(), "blah"); Assert.assertEquals(BEARER_TOKEN_MOCK, accessTokenAgain); } }
