Improved AccessContext (#3029)
Signed-off-by: Avgustin Marinov <Avgustin.Marinov@bosch.com>
This commit is contained in:
@@ -9,9 +9,16 @@
|
||||
*/
|
||||
package org.eclipse.hawkbit.auth;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
/**
|
||||
* Software provisioning roles that implies set of permissions and reflects high-level roles.
|
||||
@@ -29,6 +36,7 @@ public final class SpRole {
|
||||
public static final String SYSTEM_ROLE = "ROLE_SYSTEM_CODE";
|
||||
/** The role which contains in the spring security context in case a controller is authenticated */
|
||||
public static final String CONTROLLER_ROLE = "ROLE_CONTROLLER";
|
||||
public static final Collection<GrantedAuthority> CONTROLLER_AUTHORITIES = List.of(new SimpleGrantedAuthority(CONTROLLER_ROLE));
|
||||
|
||||
private static final String IMPLIES = " > ";
|
||||
private static final String LINE_BREAK = "\n";
|
||||
@@ -85,4 +93,16 @@ public final class SpRole {
|
||||
TENANT_ADMIN_HIERARCHY +
|
||||
SYSTEM_ROLE_HIERARCHY;
|
||||
// @formatter:on
|
||||
|
||||
public static boolean isController() {
|
||||
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null) {
|
||||
return false;
|
||||
}
|
||||
final Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
|
||||
if (authorities == CONTROLLER_AUTHORITIES) {
|
||||
return true;
|
||||
}
|
||||
return authorities.size() == 1 && CONTROLLER_ROLE.equals(authorities.iterator().next().getAuthority());
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,8 @@ import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAwareUser;
|
||||
import lombok.Data;
|
||||
import org.eclipse.hawkbit.context.Principal;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAwareUserProperties;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.boot.security.autoconfigure.SecurityProperties;
|
||||
@@ -47,12 +47,11 @@ public class StaticAuthenticationProvider extends DaoAuthenticationProvider {
|
||||
@Override
|
||||
protected @NonNull Authentication createSuccessAuthentication(
|
||||
@NonNull final Object principal, final Authentication authentication, final UserDetails user) {
|
||||
final UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
|
||||
principal, authentication.getCredentials(), user.getAuthorities());
|
||||
result.setDetails(user instanceof TenantAwareUser tenantAwareUser
|
||||
? new TenantAwareAuthenticationDetails(tenantAwareUser.getTenant(), false)
|
||||
: user);
|
||||
return result;
|
||||
return new UsernamePasswordAuthenticationToken(
|
||||
user instanceof TenantAwareUser tenantAwareUser
|
||||
? new Principal(tenantAwareUser.getTenant(), tenantAwareUser.getUsername())
|
||||
: principal,
|
||||
authentication.getCredentials(), user.getAuthorities());
|
||||
}
|
||||
|
||||
private static UserDetailsService userDetailsService(
|
||||
@@ -61,9 +60,7 @@ public class StaticAuthenticationProvider extends DaoAuthenticationProvider {
|
||||
tenantAwareUserProperties.getUser().forEach((username, user) -> {
|
||||
final String password = password(user.getPassword());
|
||||
final List<GrantedAuthority> credentials = createAuthorities(user.getRoles(), user.getPermissions(), Collections::emptyList);
|
||||
userPrincipals.add(ObjectUtils.isEmpty(user.getTenant())
|
||||
? new User(username, password, credentials)
|
||||
: new TenantAwareUser(username, password, credentials, user.getTenant()));
|
||||
userPrincipals.add(new TenantAwareUser(username, password, credentials, user.getTenant()));
|
||||
});
|
||||
|
||||
if (securityProperties != null && !securityProperties.getUser().isPasswordGenerated()) {
|
||||
@@ -136,4 +133,20 @@ public class StaticAuthenticationProvider extends DaoAuthenticationProvider {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
private static class TenantAwareUser extends User {
|
||||
|
||||
private final String tenant;
|
||||
|
||||
private TenantAwareUser(
|
||||
final String username, final String password, final Collection<? extends GrantedAuthority> authorities, final String tenant) {
|
||||
super(username, password, authorities);
|
||||
this.tenant = tenant;
|
||||
}
|
||||
|
||||
private String getTenant() {
|
||||
return tenant;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ 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;
|
||||
@@ -25,8 +24,7 @@ import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.eclipse.hawkbit.auth.SpRole;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAwareUser;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
@@ -57,7 +55,7 @@ public class AccessContext {
|
||||
* @return could be empty if there is nothing to serialize or context aware is not supported.
|
||||
*/
|
||||
public static Optional<String> securityContext() {
|
||||
return Optional.ofNullable(SecurityContextHolder.getContext()).map(AccessContext::serialize);
|
||||
return Optional.of(SecurityContextHolder.getContext()).map(AccessContext::serialize);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,9 +67,7 @@ public class AccessContext {
|
||||
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication != null) {
|
||||
final Object principal = authentication.getPrincipal();
|
||||
if (authentication.getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareAuthenticationDetails) {
|
||||
return tenantAwareAuthenticationDetails.tenant();
|
||||
} else if (principal instanceof TenantAwareUser tenantAwareUser) {
|
||||
if (principal instanceof Principal tenantAwareUser) {
|
||||
return tenantAwareUser.getTenant();
|
||||
}
|
||||
}
|
||||
@@ -270,12 +266,9 @@ public class AccessContext {
|
||||
}
|
||||
|
||||
private static String resolve(final Authentication authentication) {
|
||||
if (authentication.getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareDetails && tenantAwareDetails.controller()) {
|
||||
return "CONTROLLER_PLUG_AND_PLAY";
|
||||
}
|
||||
final Object principal = authentication.getPrincipal();
|
||||
if (principal instanceof ActorAware actorAware) {
|
||||
return actorAware.getActor();
|
||||
if (principal instanceof Principal hawkbitPrincipal) {
|
||||
return hawkbitPrincipal.getActor();
|
||||
}
|
||||
if (principal instanceof UserDetails userDetails) {
|
||||
return userDetails.getUsername();
|
||||
@@ -316,11 +309,6 @@ public class AccessContext {
|
||||
return authentication == null || !authentication.isAuthenticated() || authentication.getPrincipal() == null;
|
||||
}
|
||||
|
||||
public interface ActorAware {
|
||||
|
||||
String getActor();
|
||||
}
|
||||
|
||||
// simplified info for the security context keeping just the basic info needed for background execution of
|
||||
// controller authentication is not supported - always is false
|
||||
// only authenticated user is supported
|
||||
@@ -343,16 +331,12 @@ public class AccessContext {
|
||||
if (!authentication.isAuthenticated()) {
|
||||
throw new IllegalStateException("Only authenticated context could be serialized");
|
||||
}
|
||||
if (authentication.getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareDetails) {
|
||||
if (tenantAwareDetails.controller()) {
|
||||
throw new IllegalStateException("Controller authentication context is not supported");
|
||||
}
|
||||
tenant = tenantAwareDetails.tenant();
|
||||
} else if (authentication.getPrincipal() instanceof TenantAwareUser tenantAwareUser) {
|
||||
tenant = tenantAwareUser.getTenant();
|
||||
|
||||
if (authentication.getPrincipal() instanceof Principal principal) {
|
||||
tenant = principal.getTenant();
|
||||
}
|
||||
|
||||
// keep the auditor, ofr audit purposes,
|
||||
// keep the auditor, for audit purposes,
|
||||
// sets principal to the resolved auditor and then deserialized authentication will return it as principal
|
||||
// since the class is not known to auditor aware - it shall used default - principal as auditor
|
||||
auditor = resolve(authentication);
|
||||
@@ -361,8 +345,7 @@ public class AccessContext {
|
||||
|
||||
private SecurityContext toSecurityContext() {
|
||||
final SecurityContext ctx = SecurityContextHolder.createEmptyContext();
|
||||
final Object details = tenant == null ? null : new TenantAwareAuthenticationDetails(tenant, false);
|
||||
final ActorAware principal = () -> auditor;
|
||||
final Principal principal = new Principal(tenant, auditor);
|
||||
final Collection<? extends GrantedAuthority> grantedAuthorities = Stream.of(authorities).map(SimpleGrantedAuthority::new).toList();
|
||||
ctx.setAuthentication(new Authentication() {
|
||||
|
||||
@@ -372,7 +355,7 @@ public class AccessContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
public @NonNull Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return grantedAuthorities;
|
||||
}
|
||||
|
||||
@@ -383,7 +366,7 @@ public class AccessContext {
|
||||
|
||||
@Override
|
||||
public Object getDetails() {
|
||||
return details;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -417,12 +400,10 @@ public class AccessContext {
|
||||
|
||||
private static final List<SimpleGrantedAuthority> AUTHORITIES = List.of(new SimpleGrantedAuthority(SpRole.SYSTEM_ROLE));
|
||||
|
||||
private final TenantAwareAuthenticationDetails details;
|
||||
private final TenantAwareUser principal;
|
||||
private final Principal principal;
|
||||
|
||||
private SystemCodeAuthentication(final String tenant) {
|
||||
details = new TenantAwareAuthenticationDetails(tenant, false);
|
||||
principal = new TenantAwareUser(SYSTEM_ACTOR, SYSTEM_ACTOR, AUTHORITIES, tenant);
|
||||
principal = new Principal(tenant, SYSTEM_ACTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -431,7 +412,7 @@ public class AccessContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
public @NonNull Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return AUTHORITIES;
|
||||
}
|
||||
|
||||
@@ -442,7 +423,7 @@ public class AccessContext {
|
||||
|
||||
@Override
|
||||
public Object getDetails() {
|
||||
return details;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -471,13 +452,11 @@ public class AccessContext {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final Authentication delegate;
|
||||
private final TenantAwareUser principal;
|
||||
private final TenantAwareAuthenticationDetails tenantAwareAuthenticationDetails;
|
||||
private final Principal principal;
|
||||
|
||||
private AuthenticationDelegate(final String tenant, final String username, final Authentication delegate) {
|
||||
this.delegate = delegate;
|
||||
principal = new TenantAwareUser(username, username, delegate == null ? Collections.emptyList() : delegate.getAuthorities(), tenant);
|
||||
tenantAwareAuthenticationDetails = new TenantAwareAuthenticationDetails(tenant, false);
|
||||
principal = new Principal(tenant, username);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -489,8 +468,7 @@ public class AccessContext {
|
||||
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());
|
||||
Objects.equals(principal, anotherAuthentication.getPrincipal());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -507,8 +485,8 @@ public class AccessContext {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return principal.getAuthorities();
|
||||
public @NonNull Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return delegate.getAuthorities();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -518,7 +496,7 @@ public class AccessContext {
|
||||
|
||||
@Override
|
||||
public Object getDetails() {
|
||||
return tenantAwareAuthenticationDetails;
|
||||
return delegate.getDetails();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,7 +21,6 @@ import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
||||
import org.slf4j.MDC;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@@ -61,22 +60,14 @@ public class Mdc {
|
||||
return callable.call();
|
||||
}
|
||||
|
||||
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null) {
|
||||
if (SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
return callable.call();
|
||||
}
|
||||
|
||||
final String tenant;
|
||||
if (authentication.getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareAuthenticationDetails) {
|
||||
tenant = tenantAwareAuthenticationDetails.tenant();
|
||||
} else {
|
||||
tenant = null;
|
||||
}
|
||||
|
||||
final String tenant = AccessContext.tenant();
|
||||
final String actor = Optional.ofNullable(AccessContext.actor())
|
||||
.filter(ctxActor -> !ctxActor.equals(AccessContext.SYSTEM_ACTOR)) // null and system are the same - system actor
|
||||
.orElse(null);
|
||||
|
||||
return asTenantAsActor0(tenant, actor, callable);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Contributors to the Eclipse Foundation
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.context;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
import lombok.Value;
|
||||
import lombok.experimental.NonFinal;
|
||||
|
||||
/**
|
||||
* Represent an actor in the scope of the tenant
|
||||
*/
|
||||
@Value
|
||||
@NonFinal
|
||||
public class Principal implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
String tenant;
|
||||
String actor;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.tenancy;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
|
||||
/**
|
||||
* An authentication details object {@link AbstractAuthenticationToken#getDetails()} which is stored in the
|
||||
* spring security authentication token details to transport the principal and tenant in the security context session.
|
||||
*/
|
||||
public record TenantAwareAuthenticationDetails(String tenant, boolean controller) implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015 Bosch Software Innovations GmbH and others
|
||||
*
|
||||
* This program and the accompanying materials are made
|
||||
* available under the terms of the Eclipse Public License 2.0
|
||||
* which is available at https://www.eclipse.org/legal/epl-2.0/
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.eclipse.hawkbit.tenancy;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
|
||||
/**
|
||||
* A software provisioning user principal definition stored in the {@link SecurityContext} which contains the user specific attributes.
|
||||
*/
|
||||
@Getter
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class TenantAwareUser extends User {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String tenant;
|
||||
|
||||
public TenantAwareUser(
|
||||
final String username, final String password, final Collection<? extends GrantedAuthority> authorities,
|
||||
final String tenant) {
|
||||
super(username, password, authorities == null ? Collections.emptyList() : authorities);
|
||||
this.tenant = tenant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@ import static org.eclipse.hawkbit.context.AccessContext.asSystemAsTenant;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.hawkbit.auth.SpRole;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@@ -66,7 +65,6 @@ class AccessContextAsSystemTest {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.hawkbit.auth.SpPermission;
|
||||
import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@@ -33,31 +32,28 @@ class SecurityContextSerializerTest {
|
||||
@Test
|
||||
void testJsonSerialization() {
|
||||
final SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
final Principal principal = new Principal("my_tenant", "user");
|
||||
final UsernamePasswordAuthenticationToken userPassAuthentication = new UsernamePasswordAuthenticationToken(
|
||||
"user", null, AUTHORITIES.stream().map(SimpleGrantedAuthority::new).toList());
|
||||
final TenantAwareAuthenticationDetails details = new TenantAwareAuthenticationDetails("my_tenant", false);
|
||||
userPassAuthentication.setDetails(details);
|
||||
principal, null, AUTHORITIES.stream().map(SimpleGrantedAuthority::new).toList());
|
||||
securityContext.setAuthentication(userPassAuthentication);
|
||||
|
||||
final String serialized = serialize(securityContext);
|
||||
final SecurityContext deserialized = deserialize(serialized);
|
||||
final Authentication authentication = deserialized.getAuthentication();
|
||||
assertThat(resolve(authentication)).hasToString("user");
|
||||
assertThat(authentication.getPrincipal()).isEqualTo(principal);
|
||||
assertThat(authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet()))
|
||||
.isEqualTo(AUTHORITIES);
|
||||
assertThat(authentication.isAuthenticated()).isTrue();
|
||||
assertThat(authentication.getDetails()).isEqualTo(details);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testJsonSerializationSize() {
|
||||
final SecurityContext securityContext = SecurityContextHolder.getContext();
|
||||
final UsernamePasswordAuthenticationToken userPassAuthentication = new UsernamePasswordAuthenticationToken(
|
||||
"FirstName.FamilyName@domain1.domain0.com",
|
||||
new Principal("my_test_enant", "FirstName.FamilyName@domain1.domain0.com"),
|
||||
Map.of("should not be in" + bigString(10_000), "the output" + bigString(15_000)),
|
||||
AUTHORITIES.stream().map(SimpleGrantedAuthority::new).toList());
|
||||
final TenantAwareAuthenticationDetails details = new TenantAwareAuthenticationDetails("my_test_enant", false);
|
||||
userPassAuthentication.setDetails(details);
|
||||
securityContext.setAuthentication(userPassAuthentication);
|
||||
|
||||
final String serialized = serialize(securityContext);
|
||||
|
||||
Reference in New Issue
Block a user