Add AccessContext.asTenant and use where possible (#2838)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -12,6 +12,7 @@ package org.eclipse.hawkbit.context;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@@ -78,10 +79,7 @@ public class AccessContext {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Sometimes 'system' need to override the auditor when do create/modify actions in context of a tenant and user.
|
||||
// Though this could be made using runAsTenantAsUser sometimes (as in transaction) this override is needed
|
||||
// after runAsTenantAsUser (because it seems that auditor is got in commit time).
|
||||
// So this thread local variable provides option to override explicitly the auditor.
|
||||
// Sometimes 'system' need to override the auditor when do create/modify actions in context of an actor
|
||||
private static final ThreadLocal<String> ACTOR_OVERRIDE = new ThreadLocal<>();
|
||||
|
||||
// Return the current actor / auditor / principal name. It could be a user (person), technical user, device, etc.
|
||||
@@ -143,6 +141,34 @@ public class AccessContext {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a given {@link Runnable} within a current authorities with set tenant in the context.
|
||||
*
|
||||
* @param tenant the tenant to be set in context.
|
||||
* @param runnable the runnable to call within the tenant context
|
||||
*/
|
||||
public static void asTenant(final String tenant, final Runnable runnable) {
|
||||
asTenant(tenant, () -> {
|
||||
runnable.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a given {@link Supplier} within a current authorities with set tenant in the context.
|
||||
*
|
||||
* @param tenant the tenant to be set in context.
|
||||
* @param supplier the supplier to call within the tenant context
|
||||
* @return the return value of the {@link Supplier#get()} method.
|
||||
*/
|
||||
public static <T> T asTenant(final String tenant, final Supplier<T> supplier) {
|
||||
final SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(new AuthenticationDelegate(
|
||||
tenant, Optional.ofNullable(actor()).orElse(SYSTEM_ACTOR),
|
||||
SecurityContextHolder.getContext().getAuthentication()));
|
||||
return withSecurityContext(securityContext, supplier);
|
||||
}
|
||||
|
||||
public static void asActor(final String actor, final Runnable runnable) {
|
||||
asActor(actor, () -> {
|
||||
runnable.run();
|
||||
@@ -219,14 +245,12 @@ public class AccessContext {
|
||||
* @return the return value of the {@link Supplier#get()} method.
|
||||
*/
|
||||
public static <T> T asSystemAsTenant(final String tenant, final Supplier<T> supplier) {
|
||||
final SecurityContext currentContext = SecurityContextHolder.getContext();
|
||||
log.debug("Entering system code execution");
|
||||
try {
|
||||
log.debug("Entering system code execution");
|
||||
final SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(new SystemCodeAuthentication(tenant));
|
||||
return withSecurityContext(securityContext, supplier);
|
||||
} finally {
|
||||
SecurityContextHolder.setContext(currentContext);
|
||||
log.debug("Leaving system code execution");
|
||||
}
|
||||
}
|
||||
@@ -446,4 +470,83 @@ public class AccessContext {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An {@link Authentication} implementation to delegate to an existing {@link Authentication} object except setting the details
|
||||
* specifically for a specific tenant and user.
|
||||
*/
|
||||
private static final class AuthenticationDelegate implements Authentication {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Authentication delegate;
|
||||
private final TenantAwareUser principal;
|
||||
private final TenantAwareAuthenticationDetails tenantAwareAuthenticationDetails;
|
||||
|
||||
private AuthenticationDelegate(final String tenant, final String username, final Authentication delegate) {
|
||||
this.delegate = delegate;
|
||||
principal = new TenantAwareUser(username, username, delegate != null ? delegate.getAuthorities() : Collections.emptyList(), tenant);
|
||||
tenantAwareAuthenticationDetails = new TenantAwareAuthenticationDetails(tenant, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return delegate != null ? delegate.hashCode() : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object another) {
|
||||
if (another instanceof Authentication anotherAuthentication) {
|
||||
return Objects.equals(delegate, anotherAuthentication) &&
|
||||
Objects.equals(principal, anotherAuthentication.getPrincipal()) &&
|
||||
Objects.equals(tenantAwareAuthenticationDetails, anotherAuthentication.getDetails());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return delegate != null ? delegate.toString() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return delegate != null ? delegate.getName() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return principal.getAuthorities();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return delegate != null ? delegate.getCredentials() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDetails() {
|
||||
return tenantAwareAuthenticationDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthenticated() {
|
||||
return delegate == null || delegate.isAuthenticated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticated(final boolean isAuthenticated) {
|
||||
if (delegate == null) {
|
||||
return;
|
||||
}
|
||||
delegate.setAuthenticated(isAuthenticated);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,11 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.context;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.eclipse.hawkbit.auth.SpRole;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -23,32 +23,36 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
class SystemSecurityContextTest {
|
||||
class AccessContextAsSystemTest {
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("test", "pass", List.of(new SimpleGrantedAuthority("anonymous")));
|
||||
final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
|
||||
"test", "pass", List.of(new SimpleGrantedAuthority("anonymous")));
|
||||
auth.setDetails("string details");
|
||||
test(auth);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWithNullPrincipal() {
|
||||
final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(null, "pass", List.of(new SimpleGrantedAuthority("anonymous")));
|
||||
final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
|
||||
null, "pass", List.of(new SimpleGrantedAuthority("anonymous")));
|
||||
auth.setDetails("string details");
|
||||
test(auth);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWithNullCredentials() {
|
||||
final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("test", null, List.of(new SimpleGrantedAuthority("anonymous")));
|
||||
final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
|
||||
"test", null, List.of(new SimpleGrantedAuthority("anonymous")));
|
||||
auth.setDetails("string details");
|
||||
test(auth);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWitAllNull() {
|
||||
final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(null, null, List.of(new SimpleGrantedAuthority("anonymous")));
|
||||
final UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
|
||||
null, null, List.of(new SimpleGrantedAuthority("anonymous")));
|
||||
auth.setDetails(null);
|
||||
test(auth);
|
||||
}
|
||||
@@ -59,10 +63,10 @@ class SystemSecurityContextTest {
|
||||
SecurityContextHolder.setContext(sc);
|
||||
asSystemAsTenant("tenant", () -> {
|
||||
final Authentication currentAuth = SecurityContextHolder.getContext().getAuthentication();
|
||||
Assertions.assertThat(currentAuth.getClass().getSimpleName()).isEqualTo("SystemCodeAuthentication");
|
||||
Assertions.assertThat(currentAuth.getCredentials()).isNull();
|
||||
Assertions.assertThat(currentAuth.getAuthorities()).isEqualTo(List.of(new SimpleGrantedAuthority(SpRole.SYSTEM_ROLE)));
|
||||
Assertions.assertThat(currentAuth.getDetails()).isEqualTo(new TenantAwareAuthenticationDetails("tenant", false));
|
||||
assertThat(currentAuth.getClass().getSimpleName()).isEqualTo("SystemCodeAuthentication");
|
||||
assertThat(currentAuth.getCredentials()).isNull();
|
||||
assertThat(currentAuth.getAuthorities()).isEqualTo(List.of(new SimpleGrantedAuthority(SpRole.SYSTEM_ROLE)));
|
||||
assertThat(currentAuth.getDetails()).isEqualTo(new TenantAwareAuthenticationDetails("tenant", false));
|
||||
});
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
Reference in New Issue
Block a user