From 2150f45bded5c45729c7bf6b655f4768a1202380 Mon Sep 17 00:00:00 2001 From: Michael Hirsch Date: Fri, 24 Jun 2016 14:51:18 +0200 Subject: [PATCH 1/2] use SecurityContext as thread local because it's delegated throug threads Signed-off-by: Michael Hirsch --- .../security/SecurityContextTenantAware.java | 101 +++++++++++++----- .../security/SystemSecurityContext.java | 18 ++-- 2 files changed, 88 insertions(+), 31 deletions(-) diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java index 2d8ac52df..e548acb7a 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java @@ -8,13 +8,15 @@ */ package org.eclipse.hawkbit.security; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.Collection; import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails; import org.eclipse.hawkbit.tenancy.TenantAware; import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContextImpl; /** * A {@link TenantAware} implemenation which retrieves the ID of the tenant from @@ -28,9 +30,6 @@ import org.springframework.security.core.context.SecurityContextHolder; */ public class SecurityContextTenantAware implements TenantAware { - private static final ThreadLocal TENANT_THREAD_LOCAL = new ThreadLocal<>(); - private static final ThreadLocal RUN_AS_DEPTH = new ThreadLocal<>(); - /* * (non-Javadoc) * @@ -38,9 +37,6 @@ public class SecurityContextTenantAware implements TenantAware { */ @Override public String getCurrentTenant() { - if (TENANT_THREAD_LOCAL.get() != null) { - return TENANT_THREAD_LOCAL.get(); - } final SecurityContext context = SecurityContextHolder.getContext(); if (context.getAuthentication() != null) { final Object authDetails = context.getAuthentication().getDetails(); @@ -51,29 +47,84 @@ public class SecurityContextTenantAware implements TenantAware { return null; } - /* - * (non-Javadoc) - * - * @see hawkbit.server.tenancy.TenantAware#runAsTenant(java.lang.String, - * java.util.concurrent.Callable) - */ @Override public T runAsTenant(final String tenant, final TenantRunner callable) { - AtomicInteger runAsDepth = RUN_AS_DEPTH.get(); - if (runAsDepth == null) { - runAsDepth = new AtomicInteger(1); - RUN_AS_DEPTH.set(runAsDepth); - } else { - runAsDepth.incrementAndGet(); - } - TENANT_THREAD_LOCAL.set(tenant); + final SecurityContext originalContext = SecurityContextHolder.getContext(); try { + SecurityContextHolder.setContext(buildSecurityContext(tenant)); return callable.run(); } finally { - if (runAsDepth.decrementAndGet() <= 0) { - RUN_AS_DEPTH.remove(); - TENANT_THREAD_LOCAL.remove(); - } + SecurityContextHolder.setContext(originalContext); + } + } + + private SecurityContext buildSecurityContext(final String tenant) { + final SecurityContextImpl securityContext = new SecurityContextImpl(); + securityContext.setAuthentication( + new AuthenticationDelegate(SecurityContextHolder.getContext().getAuthentication(), tenant)); + return securityContext; + } + + private class AuthenticationDelegate implements Authentication { + private static final long serialVersionUID = 1L; + + private final Authentication delegate; + private final TenantAwareAuthenticationDetails tenantAwareAuthenticationDetails; + + private AuthenticationDelegate(final Authentication delegate, final String tenant) { + this.delegate = delegate; + tenantAwareAuthenticationDetails = new TenantAwareAuthenticationDetails(tenant, false); + + } + + @Override + public boolean equals(final Object another) { + return delegate.equals(another); + } + + @Override + public String toString() { + return delegate.toString(); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public String getName() { + return delegate.getName(); + } + + @Override + public Collection getAuthorities() { + return delegate.getAuthorities(); + } + + @Override + public Object getCredentials() { + return delegate.getCredentials(); + } + + @Override + public Object getDetails() { + return tenantAwareAuthenticationDetails; + } + + @Override + public Object getPrincipal() { + return delegate.getPrincipal(); + } + + @Override + public boolean isAuthenticated() { + return delegate.isAuthenticated(); + } + + @Override + public void setAuthenticated(final boolean isAuthenticated) throws IllegalArgumentException { + delegate.setAuthenticated(isAuthenticated); } } } diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java index 78fb5818d..c0ecb8ceb 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SystemSecurityContext.java @@ -72,7 +72,7 @@ public class SystemSecurityContext { logger.debug("entering system code execution"); return tenantAware.runAsTenant(tenantAware.getCurrentTenant(), () -> { try { - setSystemContext(); + setSystemContext(oldContext); return callable.call(); } catch (final Exception e) { throw Throwables.propagate(e); @@ -93,9 +93,10 @@ public class SystemSecurityContext { return SecurityContextHolder.getContext().getAuthentication() instanceof SystemCodeAuthentication; } - private static void setSystemContext() { + private static void setSystemContext(final SecurityContext oldContext) { + final Authentication oldAuthentication = oldContext.getAuthentication(); final SecurityContextImpl securityContextImpl = new SecurityContextImpl(); - securityContextImpl.setAuthentication(new SystemCodeAuthentication()); + securityContextImpl.setAuthentication(new SystemCodeAuthentication(oldAuthentication)); SecurityContextHolder.setContext(securityContextImpl); } @@ -104,6 +105,11 @@ public class SystemSecurityContext { private static final long serialVersionUID = 1L; private static final List AUTHORITIES = Collections .singletonList(new SimpleGrantedAuthority(SpringEvalExpressions.SYSTEM_ROLE)); + private final Authentication oldAuthentication; + + private SystemCodeAuthentication(final Authentication oldAuthentication) { + this.oldAuthentication = oldAuthentication; + } @Override public String getName() { @@ -117,17 +123,17 @@ public class SystemSecurityContext { @Override public Object getCredentials() { - return null; + return oldAuthentication != null ? oldAuthentication.getCredentials() : null; } @Override public Object getDetails() { - return null; + return oldAuthentication != null ? oldAuthentication.getDetails() : null; } @Override public Object getPrincipal() { - return null; + return oldAuthentication != null ? oldAuthentication.getPrincipal() : null; } @Override From a5d84a47e070df13cfc8624330fa2f018dce0a86 Mon Sep 17 00:00:00 2001 From: Michael Hirsch Date: Fri, 24 Jun 2016 14:58:26 +0200 Subject: [PATCH 2/2] code beautify Signed-off-by: Michael Hirsch --- .../hawkbit/security/SecurityContextTenantAware.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java index e548acb7a..4b5fe7224 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextTenantAware.java @@ -24,9 +24,6 @@ import org.springframework.security.core.context.SecurityContextImpl; * {@link Authentication#getDetails()} which holds the * {@link TenantAwareAuthenticationDetails} object. * - * - * - * */ public class SecurityContextTenantAware implements TenantAware { @@ -65,6 +62,11 @@ public class SecurityContextTenantAware implements TenantAware { return securityContext; } + /** + * An {@link Authentication} implementation to delegate to an existing + * {@link Authentication} object except setting the details specifically for + * a specific tenant. + */ private class AuthenticationDelegate implements Authentication { private static final long serialVersionUID = 1L; @@ -74,7 +76,6 @@ public class SecurityContextTenantAware implements TenantAware { private AuthenticationDelegate(final Authentication delegate, final String tenant) { this.delegate = delegate; tenantAwareAuthenticationDetails = new TenantAwareAuthenticationDetails(tenant, false); - } @Override