You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dlab.apache.org by bh...@apache.org on 2019/09/02 09:17:19 UTC
[incubator-dlab] branch dlab_refactored updated: DLAB-1022 add
possibility to cache keycloak token on DLab side
This is an automated email from the ASF dual-hosted git repository.
bhliva pushed a commit to branch dlab_refactored
in repository https://gitbox.apache.org/repos/asf/incubator-dlab.git
The following commit(s) were added to refs/heads/dlab_refactored by this push:
new 29d61e5 DLAB-1022 add possibility to cache keycloak token on DLab side
29d61e5 is described below
commit 29d61e5b23c737bd35808bd52e023bb55d4cedf3
Author: bhliva <bo...@epam.com>
AuthorDate: Mon Sep 2 12:13:14 2019 +0300
DLAB-1022 add possibility to cache keycloak token on DLab side
---
.../dlab/backendapi/SelfServiceApplication.java | 58 ++--------------------
.../backendapi/auth/KeycloakAuthenticator.java | 49 ++++++++++++++++++
.../filters}/DropwizardBearerTokenFilterImpl.java | 2 +-
.../com/epam/dlab/backendapi/dao/SecurityDAO.java | 31 +++++++++---
.../dropwizard/bundles/DlabKeycloakBundle.java | 40 +++++++++++++++
.../listeners/MongoStartupListener.java | 2 +-
.../listeners/RestoreHandlerStartupListener.java | 2 +-
7 files changed, 120 insertions(+), 64 deletions(-)
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java
index 78ae616..1ef045c 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java
@@ -19,15 +19,14 @@
package com.epam.dlab.backendapi;
-import com.epam.dlab.auth.UserInfo;
-import com.epam.dlab.backendapi.auth.SelfServiceSecurityAuthorizer;
import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
import com.epam.dlab.backendapi.dao.IndexCreator;
import com.epam.dlab.backendapi.domain.EnvStatusListener;
import com.epam.dlab.backendapi.domain.ExploratoryLibCache;
+import com.epam.dlab.backendapi.dropwizard.bundles.DlabKeycloakBundle;
+import com.epam.dlab.backendapi.dropwizard.listeners.MongoStartupListener;
+import com.epam.dlab.backendapi.dropwizard.listeners.RestoreHandlerStartupListener;
import com.epam.dlab.backendapi.healthcheck.MongoHealthCheck;
-import com.epam.dlab.backendapi.listeners.MongoStartupListener;
-import com.epam.dlab.backendapi.listeners.RestoreHandlerStartupListener;
import com.epam.dlab.backendapi.modules.ModuleFactory;
import com.epam.dlab.backendapi.resources.*;
import com.epam.dlab.backendapi.resources.callback.*;
@@ -45,15 +44,10 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.name.Names;
-import de.ahus1.keycloak.dropwizard.AbstractKeycloakAuthenticator;
-import de.ahus1.keycloak.dropwizard.KeycloakBundle;
-import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
import de.thomaskrille.dropwizard_template_config.TemplateConfigBundle;
import de.thomaskrille.dropwizard_template_config.TemplateConfigBundleConfiguration;
import io.dropwizard.Application;
import io.dropwizard.assets.AssetsBundle;
-import io.dropwizard.auth.Authenticator;
-import io.dropwizard.auth.Authorizer;
import io.dropwizard.forms.MultiPartBundle;
import io.dropwizard.jersey.setup.JerseyEnvironment;
import io.dropwizard.jetty.BiDiGzipHandler;
@@ -68,14 +62,9 @@ import lombok.extern.slf4j.Slf4j;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerWrapper;
-import org.keycloak.KeycloakSecurityContext;
-import org.keycloak.representations.AccessToken;
import javax.servlet.DispatcherType;
-import javax.servlet.http.HttpServletRequest;
-import java.security.Principal;
import java.util.EnumSet;
-import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -111,46 +100,7 @@ public class SelfServiceApplication extends Application<SelfServiceApplicationCo
new TemplateConfigBundleConfiguration().fileIncludePath(ServiceUtils.getConfPath())
));
- bootstrap.addBundle(new KeycloakBundle<SelfServiceApplicationConfiguration>() {
- @Override
- protected KeycloakConfiguration getKeycloakConfiguration(SelfServiceApplicationConfiguration configuration) {
- return configuration.getKeycloakConfiguration();
- }
-
- @Override
- protected Class<? extends Principal> getUserClass() {
- return UserInfo.class;
- }
-
- @Override
- protected Authorizer createAuthorizer() {
- return new SelfServiceSecurityAuthorizer();
- }
-
- @Override
- protected Authenticator createAuthenticator(KeycloakConfiguration configuration) {
- class KeycloakAuthenticator extends AbstractKeycloakAuthenticator<UserInfo> {
-
- private KeycloakAuthenticator(KeycloakConfiguration keycloakConfiguration) {
- super(keycloakConfiguration);
- }
-
- @Override
- protected UserInfo prepareAuthentication(KeycloakSecurityContext keycloakSecurityContext,
- HttpServletRequest httpServletRequest,
- KeycloakConfiguration keycloakConfiguration) {
- final AccessToken token = keycloakSecurityContext.getToken();
- final UserInfo userInfo = new UserInfo(token.getPreferredUsername(),
- keycloakSecurityContext.getTokenString());
- final AccessToken.Access resourceAccess =
- token.getResourceAccess(keycloakConfiguration.getResource());
- Optional.ofNullable(resourceAccess).ifPresent(ra -> userInfo.addRoles(ra.getRoles()));
- return userInfo;
- }
- }
- return new KeycloakAuthenticator(configuration);
- }
- });
+ bootstrap.addBundle(new DlabKeycloakBundle());
}
@Override
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/KeycloakAuthenticator.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/KeycloakAuthenticator.java
new file mode 100644
index 0000000..8c42f22
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/KeycloakAuthenticator.java
@@ -0,0 +1,49 @@
+package com.epam.dlab.backendapi.auth;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.SelfServiceApplication;
+import com.epam.dlab.backendapi.dao.SecurityDAO;
+import de.ahus1.keycloak.dropwizard.AbstractKeycloakAuthenticator;
+import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
+import io.dropwizard.auth.AuthenticationException;
+import org.apache.commons.lang3.StringUtils;
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.representations.AccessToken;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.HttpHeaders;
+import java.util.Optional;
+
+public class KeycloakAuthenticator extends AbstractKeycloakAuthenticator<UserInfo> {
+
+ private static final String TOKEN_PREFIX = "Bearer ";
+
+ public KeycloakAuthenticator(KeycloakConfiguration keycloakConfiguration) {
+ super(keycloakConfiguration);
+ }
+
+ @Override
+ public Optional<UserInfo> authenticate(HttpServletRequest request) throws AuthenticationException {
+ final String token = StringUtils.substringAfter(request.getHeader(HttpHeaders.AUTHORIZATION), TOKEN_PREFIX);
+ final Optional<UserInfo> cachedUser =
+ SelfServiceApplication.getInjector().getInstance(SecurityDAO.class).getUser(token);
+ if (!cachedUser.isPresent()) {
+ return super.authenticate(request);
+ } else {
+ return cachedUser;
+ }
+ }
+
+ @Override
+ protected UserInfo prepareAuthentication(KeycloakSecurityContext keycloakSecurityContext,
+ HttpServletRequest httpServletRequest,
+ KeycloakConfiguration keycloakConfiguration) {
+ final AccessToken token = keycloakSecurityContext.getToken();
+ final UserInfo userInfo = new UserInfo(token.getPreferredUsername(),
+ keycloakSecurityContext.getTokenString());
+ final AccessToken.Access resourceAccess =
+ token.getResourceAccess(keycloakConfiguration.getResource());
+ Optional.ofNullable(resourceAccess).ifPresent(ra -> userInfo.addRoles(ra.getRoles()));
+ return userInfo;
+ }
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/DropwizardBearerTokenFilterImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/filters/DropwizardBearerTokenFilterImpl.java
similarity index 93%
rename from services/self-service/src/main/java/com/epam/dlab/backendapi/DropwizardBearerTokenFilterImpl.java
rename to services/self-service/src/main/java/com/epam/dlab/backendapi/auth/filters/DropwizardBearerTokenFilterImpl.java
index 9be4251..8c72669 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/DropwizardBearerTokenFilterImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/filters/DropwizardBearerTokenFilterImpl.java
@@ -1,4 +1,4 @@
-package com.epam.dlab.backendapi;
+package com.epam.dlab.backendapi.auth.filters;
import org.keycloak.adapters.AdapterDeploymentContext;
import org.keycloak.adapters.KeycloakDeployment;
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SecurityDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SecurityDAO.java
index 7fb59a4..a0bcfc0 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SecurityDAO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SecurityDAO.java
@@ -19,7 +19,9 @@
package com.epam.dlab.backendapi.dao;
+import com.epam.dlab.auth.UserInfo;
import com.epam.dlab.auth.dto.UserCredentialDTO;
+import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
import com.epam.dlab.exceptions.DlabException;
import com.epam.dlab.util.UsernameUtils;
import com.google.inject.Singleton;
@@ -33,8 +35,7 @@ import java.util.stream.Collectors;
import static com.epam.dlab.backendapi.dao.MongoCollections.LOGIN_ATTEMPTS;
import static com.epam.dlab.backendapi.dao.MongoCollections.ROLES;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.ne;
+import static com.mongodb.client.model.Filters.*;
import static com.mongodb.client.model.Projections.*;
/**
@@ -43,6 +44,10 @@ import static com.mongodb.client.model.Projections.*;
@Singleton
public class SecurityDAO extends BaseDAO {
+ private SelfServiceApplicationConfiguration conf;
+ private static final String SECURITY_COLLECTION = "security";
+ private static final String TOKEN_RESPONSE = "tokenResponse";
+
/**
* Write the attempt of user login into Mongo database.
*
@@ -71,16 +76,28 @@ public class SecurityDAO extends BaseDAO {
}
public void saveUser(String userName, AccessTokenResponse accessTokenResponse) {
- updateOne("security", eq(ID, userName),
+ updateOne(SECURITY_COLLECTION, eq(ID, userName),
new Document(SET,
- new Document().append(ID, userName).append("created", new Date()).append("tokenResponse",
- convertToBson(accessTokenResponse))),
+ new Document()
+ .append(ID, userName)
+ .append("created", new Date())
+ .append("last_access", new Date())
+ .append(TOKEN_RESPONSE, convertToBson(accessTokenResponse))),
true);
}
+ public Optional<UserInfo> getUser(String token) {
+ return Optional.ofNullable(mongoService.getCollection(SECURITY_COLLECTION)
+ .findOneAndUpdate(and(eq(TOKEN_RESPONSE + ".access_token", token), gte("last_access",
+ new Date(new Date().getTime() - conf.getInactiveUserTimeoutMillSec()))), new Document("$set",
+ new Document("last_access", new Date()))))
+ .map(d -> new UserInfo(d.getString(ID), token));
+ }
+
+
public Optional<AccessTokenResponse> getTokenResponse(String user) {
- return findOne("security", eq(ID, user), Projections.fields(include("tokenResponse")))
- .map(d -> convertFromDocument((Document) d.get("tokenResponse"), AccessTokenResponse.class));
+ return findOne(SECURITY_COLLECTION, eq(ID, user), Projections.fields(include(TOKEN_RESPONSE)))
+ .map(d -> convertFromDocument((Document) d.get(TOKEN_RESPONSE), AccessTokenResponse.class));
}
@SuppressWarnings("unchecked")
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/bundles/DlabKeycloakBundle.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/bundles/DlabKeycloakBundle.java
new file mode 100644
index 0000000..5089c1c
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/bundles/DlabKeycloakBundle.java
@@ -0,0 +1,40 @@
+package com.epam.dlab.backendapi.dropwizard.bundles;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.auth.KeycloakAuthenticator;
+import com.epam.dlab.backendapi.auth.SelfServiceSecurityAuthorizer;
+import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
+import com.google.inject.Inject;
+import de.ahus1.keycloak.dropwizard.KeycloakBundle;
+import de.ahus1.keycloak.dropwizard.KeycloakConfiguration;
+import io.dropwizard.auth.Authenticator;
+import io.dropwizard.auth.Authorizer;
+import io.dropwizard.setup.Environment;
+
+import java.security.Principal;
+
+public class DlabKeycloakBundle extends KeycloakBundle<SelfServiceApplicationConfiguration> {
+
+ @Inject
+ private KeycloakAuthenticator authenticator;
+
+ @Override
+ protected KeycloakConfiguration getKeycloakConfiguration(SelfServiceApplicationConfiguration configuration) {
+ return configuration.getKeycloakConfiguration();
+ }
+
+ @Override
+ protected Class<? extends Principal> getUserClass() {
+ return UserInfo.class;
+ }
+
+ @Override
+ protected Authorizer createAuthorizer() {
+ return new SelfServiceSecurityAuthorizer();
+ }
+
+ @Override
+ protected Authenticator createAuthenticator(KeycloakConfiguration configuration) {
+ return new KeycloakAuthenticator(configuration);
+ }
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/listeners/MongoStartupListener.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/listeners/MongoStartupListener.java
similarity index 98%
rename from services/self-service/src/main/java/com/epam/dlab/backendapi/listeners/MongoStartupListener.java
rename to services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/listeners/MongoStartupListener.java
index d9e7abd..f94028a 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/listeners/MongoStartupListener.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/listeners/MongoStartupListener.java
@@ -1,4 +1,4 @@
-package com.epam.dlab.backendapi.listeners;
+package com.epam.dlab.backendapi.dropwizard.listeners;
import com.epam.dlab.backendapi.conf.CloudConfiguration;
import com.epam.dlab.backendapi.conf.SelfServiceApplicationConfiguration;
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/listeners/RestoreHandlerStartupListener.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/listeners/RestoreHandlerStartupListener.java
similarity index 96%
rename from services/self-service/src/main/java/com/epam/dlab/backendapi/listeners/RestoreHandlerStartupListener.java
rename to services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/listeners/RestoreHandlerStartupListener.java
index 7d94b77..73f5961 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/listeners/RestoreHandlerStartupListener.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dropwizard/listeners/RestoreHandlerStartupListener.java
@@ -17,7 +17,7 @@
* under the License.
*/
-package com.epam.dlab.backendapi.listeners;
+package com.epam.dlab.backendapi.dropwizard.listeners;
import com.epam.dlab.rest.client.RESTService;
import io.dropwizard.lifecycle.ServerLifecycleListener;
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@dlab.apache.org
For additional commands, e-mail: commits-help@dlab.apache.org