From c31e5b1265e1d00bb5f269fcf49a492eef633247 Mon Sep 17 00:00:00 2001 From: Avgustin Marinov Date: Fri, 5 Sep 2025 16:07:46 +0300 Subject: [PATCH] Define auditor aware principal (#2654) Allowing for cusomising auditor by extenders Signed-off-by: Avgustin Marinov --- .../security/SecurityContextSerializer.java | 12 +++++++----- .../security/SpringSecurityAuditorAware.java | 15 ++++++++++++--- .../security/SecurityContextSerializerTest.java | 4 ++-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java index 427d8cdd8..43c388545 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SecurityContextSerializer.java @@ -26,6 +26,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AccessLevel; import lombok.Data; import lombok.NoArgsConstructor; +import org.eclipse.hawkbit.security.SpringSecurityAuditorAware.AuditorAwarePrincipal; import org.eclipse.hawkbit.tenancy.TenantAwareAuthenticationDetails; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; @@ -140,11 +141,11 @@ public interface SecurityContextSerializer { @Serial private static final long serialVersionUID = 1L; - private String principal; - private String[] authorities; - private boolean authenticated; private String tenant; private boolean controller; + private String auditor; + private String[] authorities; + private boolean authenticated; SecCtxInfo(final SecurityContext securityContext) { final Authentication authentication = securityContext.getAuthentication(); @@ -158,7 +159,7 @@ public interface SecurityContextSerializer { // keep the auditor, ofr 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 - principal = SpringSecurityAuditorAware.resolveAuditor(authentication); + auditor = SpringSecurityAuditorAware.resolveAuditor(authentication); authorities = authentication.getAuthorities().stream().map(Object::toString).toArray(String[]::new); authenticated = authentication.isAuthenticated(); } @@ -166,6 +167,7 @@ public interface SecurityContextSerializer { private SecurityContext toSecurityContext() { final SecurityContext ctx = SecurityContextHolder.createEmptyContext(); final Object details = tenant == null ? null : new TenantAwareAuthenticationDetails(tenant, controller); + final AuditorAwarePrincipal principal = () -> auditor; final Collection grantedAuthorities = Stream.of(authorities).map(SimpleGrantedAuthority::new).toList(); ctx.setAuthentication(new Authentication() { @@ -202,7 +204,7 @@ public interface SecurityContextSerializer { @Override public String getName() { - return principal; + return auditor; } }); return ctx; diff --git a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java index fc41f7a7c..5529baebc 100644 --- a/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java +++ b/hawkbit-security-core/src/main/java/org/eclipse/hawkbit/security/SpringSecurityAuditorAware.java @@ -63,16 +63,25 @@ public class SpringSecurityAuditorAware implements AuditorAware { if (authentication.getDetails() instanceof TenantAwareAuthenticationDetails tenantAwareDetails && tenantAwareDetails.controller()) { return "CONTROLLER_PLUG_AND_PLAY"; } - if (authentication.getPrincipal() instanceof UserDetails userDetails) { + final Object principal = authentication.getPrincipal(); + if (principal instanceof AuditorAwarePrincipal auditorAwarePrincipal) { + return auditorAwarePrincipal.getAuditor(); + } + if (principal instanceof UserDetails userDetails) { return userDetails.getUsername(); } - if (authentication.getPrincipal() instanceof OidcUser oidcUser) { + if (principal instanceof OidcUser oidcUser) { return oidcUser.getPreferredUsername(); } - return authentication.getPrincipal().toString(); + return principal.toString(); } private static boolean isAuthenticationInvalid(final Authentication authentication) { return authentication == null || !authentication.isAuthenticated() || authentication.getPrincipal() == null; } + + public interface AuditorAwarePrincipal { + + String getAuditor(); + } } \ No newline at end of file diff --git a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/SecurityContextSerializerTest.java b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/SecurityContextSerializerTest.java index 10b3a152c..edbc19724 100644 --- a/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/SecurityContextSerializerTest.java +++ b/hawkbit-security-core/src/test/java/org/eclipse/hawkbit/security/SecurityContextSerializerTest.java @@ -42,7 +42,7 @@ class SecurityContextSerializerTest { final String serialized = JSON_SERIALIZATION.serialize(securityContext); final SecurityContext deserialized = JSON_SERIALIZATION.deserialize(serialized); final Authentication authentication = deserialized.getAuthentication(); - assertThat(authentication.getPrincipal()).hasToString("user"); + assertThat(SpringSecurityAuditorAware.resolveAuditor(authentication)).hasToString("user"); assertThat(authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).toList()).isEqualTo(AUTHORITIES); assertThat(authentication.isAuthenticated()).isTrue(); assertThat(authentication.getDetails()).isEqualTo(details); @@ -76,7 +76,7 @@ class SecurityContextSerializerTest { assertThat(oldSerialized).isNotEqualTo(newSerialized); final Authentication deserializedOld = JSON_SERIALIZATION.deserialize(oldSerialized).getAuthentication(); final Authentication deserializedNew = JSON_SERIALIZATION.deserialize(newSerialized).getAuthentication(); - assertThat(deserializedOld.getPrincipal()).hasToString(deserializedNew.getPrincipal().toString()); + assertThat(SpringSecurityAuditorAware.resolveAuditor(deserializedOld)).hasToString(SpringSecurityAuditorAware.resolveAuditor(deserializedNew)); assertThat(deserializedOld.getAuthorities()).isEqualTo(deserializedNew.getAuthorities()); assertThat(deserializedOld.isAuthenticated()).isEqualTo(deserializedNew.isAuthenticated()); }