Merge remote-tracking branch 'origin/fix_asychronous_tenant_aware_access' into fix_executor_and_exchange

This commit is contained in:
kaizimmerm
2016-06-24 15:30:40 +02:00
2 changed files with 92 additions and 34 deletions

View File

@@ -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
@@ -22,15 +24,9 @@ import org.springframework.security.core.context.SecurityContextHolder;
* {@link Authentication#getDetails()} which holds the
* {@link TenantAwareAuthenticationDetails} object.
*
*
*
*
*/
public class SecurityContextTenantAware implements TenantAware {
private static final ThreadLocal<String> TENANT_THREAD_LOCAL = new ThreadLocal<>();
private static final ThreadLocal<AtomicInteger> RUN_AS_DEPTH = new ThreadLocal<>();
/*
* (non-Javadoc)
*
@@ -38,9 +34,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 +44,88 @@ 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> T runAsTenant(final String tenant, final TenantRunner<T> 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;
}
/**
* 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;
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<? extends GrantedAuthority> 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);
}
}
}

View File

@@ -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<SimpleGrantedAuthority> 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