You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ju...@apache.org on 2020/05/08 06:40:01 UTC

[fineract-cn-permitted-feign-client] 04/40: 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.

This is an automated email from the ASF dual-hosted git repository.

juhan pushed a commit to branch spring_boot_2
in repository https://gitbox.apache.org/repos/asf/fineract-cn-permitted-feign-client.git

commit bc6b05877f368083d72f8a31899632e7f7b23d6a
Author: myrle-krantz <mk...@mifos.org>
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);
     }
   }