Skip to content

Commit

Permalink
Apply role hierarchy in hasPermission checks (eclipse-hawkbit#1675)
Browse files Browse the repository at this point in the history
Signed-off-by: Marinov Avgustin <[email protected]>
  • Loading branch information
avgustinmm authored Mar 7, 2024
1 parent 536bb19 commit 1640025
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,9 @@ public AuditorAware<String> auditorAware() {
*/
@Bean
@ConditionalOnMissingBean
public SystemSecurityContext systemSecurityContext(final TenantAware tenantAware) {
return new SystemSecurityContext(tenantAware);
public SystemSecurityContext systemSecurityContext(
final TenantAware tenantAware, final RoleHierarchy roleHierarchy) {
return new SystemSecurityContext(tenantAware, roleHierarchy);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
import org.eclipse.hawkbit.repository.event.remote.TargetDeletedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetCreatedEvent;
import org.eclipse.hawkbit.repository.event.remote.entity.TargetUpdatedEvent;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityChecker;
import org.eclipse.hawkbit.repository.jpa.model.helper.SecurityTokenGeneratorHolder;
import org.eclipse.hawkbit.repository.model.Action;
import org.eclipse.hawkbit.repository.model.AutoConfirmationStatus;
Expand All @@ -65,6 +64,7 @@
import org.eclipse.hawkbit.repository.model.helper.EventPublisherHolder;
import org.eclipse.hawkbit.repository.model.helper.SystemSecurityContextHolder;
import org.eclipse.hawkbit.repository.model.helper.TenantConfigurationManagementHolder;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.eclipse.hawkbit.tenancy.configuration.DurationHelper;
import org.eclipse.hawkbit.tenancy.configuration.TenantConfigurationProperties.TenantConfigurationKey;
import org.eclipse.persistence.annotations.CascadeOnDelete;
Expand Down Expand Up @@ -320,8 +320,10 @@ public void addAction(final Action action) {
*/
@Override
public String getSecurityToken() {
if (SystemSecurityContextHolder.getInstance().getSystemSecurityContext().isCurrentThreadSystemCode()
|| SecurityChecker.hasPermission(SpPermission.READ_TARGET_SEC_TOKEN)) {
final SystemSecurityContext systemSecurityContext =
SystemSecurityContextHolder.getInstance().getSystemSecurityContext();
if (systemSecurityContext.isCurrentThreadSystemCode() ||
systemSecurityContext.hasPermission(SpPermission.READ_TARGET_SEC_TOKEN)) {
return securityToken;
}
return null;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.apache.commons.lang3.RandomStringUtils;
import org.awaitility.Awaitility;
import org.eclipse.hawkbit.im.authentication.SpPermission;
import org.eclipse.hawkbit.im.authentication.SpRole;
import org.eclipse.hawkbit.repository.FilterParams;
import org.eclipse.hawkbit.repository.Identifiable;
import org.eclipse.hawkbit.repository.builder.TargetUpdate;
Expand Down Expand Up @@ -189,6 +190,14 @@ void getTargetSecurityTokenOnlyWithCorrectPermission() throws Exception {
final String securityTokenWithReadPermission = SecurityContextSwitch.runAs(
SecurityContextSwitch.withUser("OnlyTargetReadPermission", false, SpPermission.READ_TARGET_SEC_TOKEN),
createdTarget::getSecurityToken);
// retrieve security token only with ROLE_TARGET_ADMIN permission
final String securityTokenWithTargetAdminPermission = SecurityContextSwitch.runAs(
SecurityContextSwitch.withUser("OnlyTargetAdminPermission", false, SpRole.TARGET_ADMIN),
createdTarget::getSecurityToken);
// retrieve security token only with ROLE_TENANT_ADMIN permission
final String securityTokenWithTenantAdminPermission = SecurityContextSwitch.runAs(
SecurityContextSwitch.withUser("OnlyTenantAdminPermission", false, SpRole.TENANT_ADMIN),
createdTarget::getSecurityToken);

// retrieve security token as system code execution
final String securityTokenAsSystemCode = systemSecurityContext.runAsSystem(createdTarget::getSecurityToken);
Expand All @@ -199,6 +208,8 @@ void getTargetSecurityTokenOnlyWithCorrectPermission() throws Exception {

assertThat(createdTarget.getSecurityToken()).isEqualTo("token");
assertThat(securityTokenWithReadPermission).isNotNull();
assertThat(securityTokenWithTargetAdminPermission).isNotNull();
assertThat(securityTokenWithTenantAdminPermission).isNotNull();
assertThat(securityTokenAsSystemCode).isNotNull();

assertThat(securityTokenWithoutPermission).isNull();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.eclipse.hawkbit.cache.DownloadIdCache;
import org.eclipse.hawkbit.cache.TenantAwareCacheManager;
import org.eclipse.hawkbit.event.BusProtoStuffMessageConverter;
import org.eclipse.hawkbit.im.authentication.SpRole;
import org.eclipse.hawkbit.repository.RolloutApprovalStrategy;
import org.eclipse.hawkbit.repository.RolloutStatusCache;
import org.eclipse.hawkbit.repository.event.ApplicationEventFilter;
Expand Down Expand Up @@ -67,6 +68,7 @@
import org.springframework.integration.support.locks.LockRegistry;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService;
import org.springframework.security.concurrent.DelegatingSecurityContextScheduledExecutorService;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
Expand Down Expand Up @@ -106,7 +108,9 @@ SecurityTokenGenerator securityTokenGenerator() {

@Bean
SystemSecurityContext systemSecurityContext(final TenantAware tenantAware) {
return new SystemSecurityContext(tenantAware);
final RoleHierarchyImpl hierarchy = new RoleHierarchyImpl();
hierarchy.setHierarchy(SpRole.DEFAULT_ROLE_HIERARCHY);
return new SystemSecurityContext(tenantAware, hierarchy);
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;

Expand All @@ -22,13 +23,15 @@
import org.eclipse.hawkbit.im.authentication.TenantAwareAuthenticationDetails;
import org.eclipse.hawkbit.im.authentication.SpPermission.SpringEvalExpressions;
import org.eclipse.hawkbit.tenancy.TenantAware;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
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.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.util.ObjectUtils;

/**
* A Service which provide to run system code.
Expand All @@ -37,15 +40,26 @@
public class SystemSecurityContext {

private final TenantAware tenantAware;
private final RoleHierarchy roleHierarchy;

/**
* Autowired constructor.
*
* @param tenantAware
* the tenant aware bean to retrieve the current tenant
* @param tenantAware the tenant aware bean to retrieve the current tenant
*/
public SystemSecurityContext(final TenantAware tenantAware) {
this(tenantAware, null);
}

/**
* Autowired constructor.
*
* @param tenantAware the tenant aware bean to retrieve the current tenant
* @param roleHierarchy the roleHierarchy that is applied
*/
public SystemSecurityContext(final TenantAware tenantAware, final RoleHierarchy roleHierarchy) {
this.tenantAware = tenantAware;
this.roleHierarchy = roleHierarchy;
}

/**
Expand Down Expand Up @@ -160,6 +174,27 @@ public boolean isCurrentThreadSystemCode() {
return SecurityContextHolder.getContext().getAuthentication() instanceof SystemCodeAuthentication;
}

public boolean hasPermission(final String permission) {
final SecurityContext context = SecurityContextHolder.getContext();
if (context != null) {
final Authentication authentication = context.getAuthentication();
if (authentication != null) {
Collection<? extends GrantedAuthority> grantedAuthorities = authentication.getAuthorities();
if (!ObjectUtils.isEmpty(grantedAuthorities)) {
if (roleHierarchy != null) {
grantedAuthorities = roleHierarchy.getReachableGrantedAuthorities(grantedAuthorities);
}
for (final GrantedAuthority authority : grantedAuthorities) {
if (authority.getAuthority().equals(permission)) {
return true;
}
}
}
}
}
return false;
}

private void setCustomSecurityContext(final String tenantId, final Object principal,
final Collection<? extends GrantedAuthority> authorities) {
final AnonymousAuthenticationToken authenticationToken = new AnonymousAuthenticationToken(
Expand Down

0 comments on commit 1640025

Please sign in to comment.