Execute rollouts and auto assignments in the correct user context (#1100)
* Execute rollouts and auto assignments in correct user context Signed-off-by: Stefan Behl <stefan.behl@bosch.io> * Fix PR review findings Signed-off-by: Stefan Behl <stefan.behl@bosch.io> * Cleanup usage of lenient Signed-off-by: Stefan Behl <stefan.behl@bosch.io>
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2020 Bosch.IO GmbH and others.
|
||||
*
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.hawkbit.security;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver;
|
||||
|
||||
/**
|
||||
* An implementation of the {@link UserAuthoritiesResolver} that is based on
|
||||
* in-memory user permissions.
|
||||
*/
|
||||
public class InMemoryUserAuthoritiesResolver implements UserAuthoritiesResolver {
|
||||
|
||||
private final Map<String, List<String>> usernamesToAuthorities;
|
||||
|
||||
/**
|
||||
* Constructs the resolver based on the given authority lookup map.
|
||||
*
|
||||
* @param usernamesToAuthorities
|
||||
* The authority map to read from. Must not be <code>null</code>.
|
||||
*/
|
||||
public InMemoryUserAuthoritiesResolver(final Map<String, List<String>> usernamesToAuthorities) {
|
||||
this.usernamesToAuthorities = usernamesToAuthorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getUserAuthorities(final String tenant, final String username) {
|
||||
// we can ignore the tenant here (no multi-tenancy by default)
|
||||
final Collection<String> authorities = usernamesToAuthorities.get(username);
|
||||
if (authorities == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return authorities;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,14 +8,16 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.security;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
|
||||
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
|
||||
import org.eclipse.hawkbit.im.authentication.UserPrincipal;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAware;
|
||||
import org.eclipse.hawkbit.tenancy.UserAuthoritiesResolver;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
@@ -24,14 +26,32 @@ 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
|
||||
* the {@link SecurityContext#getAuthentication()}
|
||||
* A {@link TenantAware} implementation which retrieves the ID of the tenant
|
||||
* from the {@link SecurityContext#getAuthentication()}
|
||||
* {@link Authentication#getDetails()} which holds the
|
||||
* {@link TenantAwareAuthenticationDetails} object.
|
||||
*
|
||||
*/
|
||||
public class SecurityContextTenantAware implements TenantAware {
|
||||
|
||||
public static final String SYSTEM_USER = "system";
|
||||
private static final Collection<? extends GrantedAuthority> SYSTEM_AUTHORITIES = Collections
|
||||
.singletonList(new SimpleGrantedAuthority(SpringEvalExpressions.SYSTEM_ROLE));
|
||||
|
||||
private final UserAuthoritiesResolver authoritiesResolver;
|
||||
|
||||
/**
|
||||
* Creates the {@link SecurityContextTenantAware} based on the given
|
||||
* {@link UserAuthoritiesResolver}.
|
||||
*
|
||||
* @param authoritiesResolver
|
||||
* Resolver to retrieve the authorities for a given user. Must
|
||||
* not be <code>null</code>.
|
||||
*/
|
||||
public SecurityContextTenantAware(final UserAuthoritiesResolver authoritiesResolver) {
|
||||
this.authoritiesResolver = authoritiesResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentTenant() {
|
||||
final SecurityContext context = SecurityContextHolder.getContext();
|
||||
@@ -59,44 +79,68 @@ public class SecurityContextTenantAware implements TenantAware {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T runAsTenant(final String tenant, final TenantRunner<T> callable) {
|
||||
public <T> T runAsTenant(final String tenant, final TenantRunner<T> tenantRunner) {
|
||||
return runInContext(buildSystemSecurityContext(tenant), tenantRunner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T runAsTenantAsUser(final String tenant, final String username, final TenantRunner<T> tenantRunner) {
|
||||
final List<SimpleGrantedAuthority> authorities = runAsSystem(
|
||||
() -> authoritiesResolver.getUserAuthorities(tenant, username).stream().map(SimpleGrantedAuthority::new)
|
||||
.collect(Collectors.toList()));
|
||||
return runInContext(buildUserSecurityContext(tenant, username, authorities), tenantRunner);
|
||||
}
|
||||
|
||||
private static <T> T runInContext(final SecurityContext context, final TenantRunner<T> tenantRunner) {
|
||||
final SecurityContext originalContext = SecurityContextHolder.getContext();
|
||||
try {
|
||||
SecurityContextHolder.setContext(buildSecurityContext(tenant));
|
||||
return callable.run();
|
||||
SecurityContextHolder.setContext(context);
|
||||
return tenantRunner.run();
|
||||
} finally {
|
||||
SecurityContextHolder.setContext(originalContext);
|
||||
}
|
||||
}
|
||||
|
||||
private static SecurityContext buildSecurityContext(final String tenant) {
|
||||
private static SecurityContext buildSystemSecurityContext(final String tenant) {
|
||||
return buildUserSecurityContext(tenant, SYSTEM_USER, SYSTEM_AUTHORITIES);
|
||||
}
|
||||
|
||||
private static <T> T runAsSystem(final TenantRunner<T> tenantRunner) {
|
||||
final SecurityContext currentContext = SecurityContextHolder.getContext();
|
||||
try {
|
||||
SystemSecurityContext.setSystemContext(currentContext);
|
||||
return tenantRunner.run();
|
||||
} finally {
|
||||
SecurityContextHolder.setContext(currentContext);
|
||||
}
|
||||
}
|
||||
|
||||
private static SecurityContext buildUserSecurityContext(final String tenant, final String username,
|
||||
final Collection<? extends GrantedAuthority> authorities) {
|
||||
final SecurityContextImpl securityContext = new SecurityContextImpl();
|
||||
securityContext.setAuthentication(
|
||||
new AuthenticationDelegate(SecurityContextHolder.getContext().getAuthentication(), tenant));
|
||||
securityContext.setAuthentication(new AuthenticationDelegate(
|
||||
SecurityContextHolder.getContext().getAuthentication(), tenant, username, authorities));
|
||||
return securityContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link Authentication} implementation to delegate to an existing
|
||||
* {@link Authentication} object except setting the details specifically for
|
||||
* a specific tenant.
|
||||
* a specific tenant and user.
|
||||
*/
|
||||
private static final class AuthenticationDelegate implements Authentication {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String SYSTEM_USER = "system";
|
||||
private static final Collection<? extends GrantedAuthority> SYSTEM_AUTHORITIES = Arrays
|
||||
.asList(new SimpleGrantedAuthority(SpringEvalExpressions.SYSTEM_ROLE));
|
||||
private final Authentication delegate;
|
||||
|
||||
private final UserPrincipal systemPrincipal;
|
||||
private final UserPrincipal principal;
|
||||
|
||||
private final TenantAwareAuthenticationDetails tenantAwareAuthenticationDetails;
|
||||
|
||||
private AuthenticationDelegate(final Authentication delegate, final String tenant) {
|
||||
private AuthenticationDelegate(final Authentication delegate, final String tenant, final String username,
|
||||
final Collection<? extends GrantedAuthority> authorities) {
|
||||
this.delegate = delegate;
|
||||
this.systemPrincipal = new UserPrincipal(SYSTEM_USER, SYSTEM_USER, SYSTEM_USER, SYSTEM_USER, SYSTEM_USER,
|
||||
null, tenant, SYSTEM_AUTHORITIES);
|
||||
this.principal = new UserPrincipal(username, username, null, null, username, null, tenant, authorities);
|
||||
tenantAwareAuthenticationDetails = new TenantAwareAuthenticationDetails(tenant, false);
|
||||
}
|
||||
|
||||
@@ -112,27 +156,27 @@ public class SecurityContextTenantAware implements TenantAware {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (delegate != null) ? delegate.toString() : null;
|
||||
return delegate != null ? delegate.toString() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (delegate != null) ? delegate.hashCode() : -1;
|
||||
return delegate != null ? delegate.hashCode() : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return (delegate != null) ? delegate.getName() : null;
|
||||
return delegate != null ? delegate.getName() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return (delegate != null) ? delegate.getAuthorities() : Collections.emptyList();
|
||||
return delegate != null ? delegate.getAuthorities() : Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return (delegate != null) ? delegate.getCredentials() : null;
|
||||
return delegate != null ? delegate.getCredentials() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -142,7 +186,7 @@ public class SecurityContextTenantAware implements TenantAware {
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return systemPrincipal;
|
||||
return principal;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -171,7 +171,7 @@ public class SystemSecurityContext {
|
||||
SecurityContextHolder.setContext(securityContextImpl);
|
||||
}
|
||||
|
||||
private static void setSystemContext(final SecurityContext oldContext) {
|
||||
static void setSystemContext(final SecurityContext oldContext) {
|
||||
final Authentication oldAuthentication = oldContext.getAuthentication();
|
||||
final SecurityContextImpl securityContextImpl = new SecurityContextImpl();
|
||||
securityContextImpl.setAuthentication(new SystemCodeAuthentication(oldAuthentication));
|
||||
|
||||
Reference in New Issue
Block a user