Loading pom.xml +1 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>com.inteligr8.activiti</groupId> <artifactId>keycloak-activiti-app-ext</artifactId> <version>1.0.1</version> <version>1.1.0</version> <name>Keycloak Authentication & Authorization for APS</name> <properties> Loading src/main/java/com/activiti/conf/ActivitiOotbSecurityConfigurationAdapter.java 0 → 100644 +57 −0 Original line number Diff line number Diff line package com.activiti.conf; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Component; import com.inteligr8.activiti.ActivitiSecurityConfigAdapter; /** * This class/bean executes the OOTB security configuration without the * override, so you can still use its OOTB features. This will allow you to * enable/disable features, chain them, and uset he OOTB features as a * fallback or failsafe. * * This class must be in the com.activiti.conf package so it can use protected * fields and methods of the OOTB class instance. * * @author brian@inteligr8.com * @see com.activiti.conf.SecurityConfiguration */ @Component public class ActivitiOotbSecurityConfigurationAdapter implements ActivitiSecurityConfigAdapter { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Value("${keycloak-ext.ootbSecurityConfig.enabled:true}") private boolean enabled; @Autowired private SecurityConfiguration ootbSecurityConfig; @Override public boolean isEnabled() { return this.enabled; } public int getPriority() { return 0; } @Override public void configureGlobal(AuthenticationManagerBuilder authmanBuilder, UserDetailsService userDetailsService) { this.logger.trace("configureGlobal()"); this.logger.info("Using OOTB authentication"); // unset override (which has already been called in order to get here) this.ootbSecurityConfig.securityConfigOverride = null; this.ootbSecurityConfig.configureGlobal(authmanBuilder); } } src/main/java/com/activiti/extension/conf/KeycloakExtSpringComponentScanner.java +1 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages = {"com.inteligr8.activiti.ais"}) @ComponentScan(basePackages = {"com.inteligr8.activiti"}) public class KeycloakExtSpringComponentScanner { } src/main/java/com/inteligr8/activiti/ActivitiSecurityConfigAdapter.java 0 → 100644 +38 −0 Original line number Diff line number Diff line package com.inteligr8.activiti; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.userdetails.UserDetailsService; /** * @author brian@inteligr8.com */ public interface ActivitiSecurityConfigAdapter extends Comparable<ActivitiSecurityConfigAdapter> { /** * Is the adapter enabled? This allows for configurable enablement. * * @return true if enabled; false otherwise */ boolean isEnabled(); /** * The lower the value, the higher the priority. The OOTB security * configuration uses priority 0. Use negative values to supersede it. * Anything with equal priorities should be considered unordered and may * execute in a random order. * * @return A priority; may be negative or positive */ int getPriority(); /** * @see com.activiti.api.security.AlfrescoSecurityConfigOverride */ void configureGlobal(AuthenticationManagerBuilder authmanBuilder, UserDetailsService userDetailsService); @Override default int compareTo(ActivitiSecurityConfigAdapter adapter) { return Integer.compare(this.getPriority(), adapter.getPriority()); } } src/main/java/com/inteligr8/activiti/Inteligr8SecurityConfigurationRegistry.java 0 → 100644 +100 −0 Original line number Diff line number Diff line package com.inteligr8.activiti; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Component; import com.activiti.api.security.AlfrescoSecurityConfigOverride; import com.activiti.domain.idm.Group; import com.activiti.domain.idm.Tenant; import com.activiti.service.api.GroupService; import com.activiti.service.idm.TenantService; import com.activiti.service.license.LicenseService; /** * This class/bean overrides the APS security configuration with a collection * of implementations. The OOTB extension only provides one override. This * uses that extension point, but delegates it out to multiple possible * implementations. * * Order cannot be controlled, so it should not be assumed in any adapter * implementation. * * @author brian@inteligr8.com */ @Component public class Inteligr8SecurityConfigurationRegistry implements AlfrescoSecurityConfigOverride { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private List<ActivitiSecurityConfigAdapter> adapters; @Autowired(required = false) private LicenseService licenseService; @Autowired(required = false) private TenantService tenantService; @Autowired(required = false) private GroupService groupService; @Override public void configureGlobal(AuthenticationManagerBuilder authmanBuilder, UserDetailsService userDetailsService) { this.logger.trace("configureGlobal()"); Collections.sort(this.adapters); if (this.logger.isTraceEnabled()) this.logGroups(); for (ActivitiSecurityConfigAdapter adapter : this.adapters) { if (adapter.isEnabled()) { this.logger.info("Security adapter enabled: {}", adapter.getClass()); adapter.configureGlobal(authmanBuilder, userDetailsService); break; } else { this.logger.info("Security adapter disabled: {}", adapter.getClass()); } } } private void logGroups() { Long tenantId = this.findDefaultTenantId(); if (tenantId != null) { // not first boot this.logger.trace("Functional groups: {}", this.toGroupNames(this.groupService.getFunctionalGroups(tenantId))); this.logger.trace("System groups: {}", this.toGroupNames(this.groupService.getSystemGroups(tenantId))); } } private Long findDefaultTenantId() { String defaultTenantName = this.licenseService.getDefaultTenantName(); this.logger.trace("Default Tenant: {}", defaultTenantName); List<Tenant> tenants = this.tenantService.findTenantsByName(defaultTenantName); if (tenants == null || tenants.isEmpty()) { this.logger.warn("Default tenant not found"); return null; } Tenant tenant = tenants.iterator().next(); return tenant.getId(); } private Collection<String> toGroupNames(Collection<Group> groups) { List<String> groupNames = new ArrayList<>(groups.size()); for (Group group : groups) groupNames.add(group.getName() + " [" + group.getExternalId() + "]"); return groupNames; } } Loading
pom.xml +1 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ <modelVersion>4.0.0</modelVersion> <groupId>com.inteligr8.activiti</groupId> <artifactId>keycloak-activiti-app-ext</artifactId> <version>1.0.1</version> <version>1.1.0</version> <name>Keycloak Authentication & Authorization for APS</name> <properties> Loading
src/main/java/com/activiti/conf/ActivitiOotbSecurityConfigurationAdapter.java 0 → 100644 +57 −0 Original line number Diff line number Diff line package com.activiti.conf; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Component; import com.inteligr8.activiti.ActivitiSecurityConfigAdapter; /** * This class/bean executes the OOTB security configuration without the * override, so you can still use its OOTB features. This will allow you to * enable/disable features, chain them, and uset he OOTB features as a * fallback or failsafe. * * This class must be in the com.activiti.conf package so it can use protected * fields and methods of the OOTB class instance. * * @author brian@inteligr8.com * @see com.activiti.conf.SecurityConfiguration */ @Component public class ActivitiOotbSecurityConfigurationAdapter implements ActivitiSecurityConfigAdapter { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Value("${keycloak-ext.ootbSecurityConfig.enabled:true}") private boolean enabled; @Autowired private SecurityConfiguration ootbSecurityConfig; @Override public boolean isEnabled() { return this.enabled; } public int getPriority() { return 0; } @Override public void configureGlobal(AuthenticationManagerBuilder authmanBuilder, UserDetailsService userDetailsService) { this.logger.trace("configureGlobal()"); this.logger.info("Using OOTB authentication"); // unset override (which has already been called in order to get here) this.ootbSecurityConfig.securityConfigOverride = null; this.ootbSecurityConfig.configureGlobal(authmanBuilder); } }
src/main/java/com/activiti/extension/conf/KeycloakExtSpringComponentScanner.java +1 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,7 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages = {"com.inteligr8.activiti.ais"}) @ComponentScan(basePackages = {"com.inteligr8.activiti"}) public class KeycloakExtSpringComponentScanner { }
src/main/java/com/inteligr8/activiti/ActivitiSecurityConfigAdapter.java 0 → 100644 +38 −0 Original line number Diff line number Diff line package com.inteligr8.activiti; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.userdetails.UserDetailsService; /** * @author brian@inteligr8.com */ public interface ActivitiSecurityConfigAdapter extends Comparable<ActivitiSecurityConfigAdapter> { /** * Is the adapter enabled? This allows for configurable enablement. * * @return true if enabled; false otherwise */ boolean isEnabled(); /** * The lower the value, the higher the priority. The OOTB security * configuration uses priority 0. Use negative values to supersede it. * Anything with equal priorities should be considered unordered and may * execute in a random order. * * @return A priority; may be negative or positive */ int getPriority(); /** * @see com.activiti.api.security.AlfrescoSecurityConfigOverride */ void configureGlobal(AuthenticationManagerBuilder authmanBuilder, UserDetailsService userDetailsService); @Override default int compareTo(ActivitiSecurityConfigAdapter adapter) { return Integer.compare(this.getPriority(), adapter.getPriority()); } }
src/main/java/com/inteligr8/activiti/Inteligr8SecurityConfigurationRegistry.java 0 → 100644 +100 −0 Original line number Diff line number Diff line package com.inteligr8.activiti; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.stereotype.Component; import com.activiti.api.security.AlfrescoSecurityConfigOverride; import com.activiti.domain.idm.Group; import com.activiti.domain.idm.Tenant; import com.activiti.service.api.GroupService; import com.activiti.service.idm.TenantService; import com.activiti.service.license.LicenseService; /** * This class/bean overrides the APS security configuration with a collection * of implementations. The OOTB extension only provides one override. This * uses that extension point, but delegates it out to multiple possible * implementations. * * Order cannot be controlled, so it should not be assumed in any adapter * implementation. * * @author brian@inteligr8.com */ @Component public class Inteligr8SecurityConfigurationRegistry implements AlfrescoSecurityConfigOverride { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private List<ActivitiSecurityConfigAdapter> adapters; @Autowired(required = false) private LicenseService licenseService; @Autowired(required = false) private TenantService tenantService; @Autowired(required = false) private GroupService groupService; @Override public void configureGlobal(AuthenticationManagerBuilder authmanBuilder, UserDetailsService userDetailsService) { this.logger.trace("configureGlobal()"); Collections.sort(this.adapters); if (this.logger.isTraceEnabled()) this.logGroups(); for (ActivitiSecurityConfigAdapter adapter : this.adapters) { if (adapter.isEnabled()) { this.logger.info("Security adapter enabled: {}", adapter.getClass()); adapter.configureGlobal(authmanBuilder, userDetailsService); break; } else { this.logger.info("Security adapter disabled: {}", adapter.getClass()); } } } private void logGroups() { Long tenantId = this.findDefaultTenantId(); if (tenantId != null) { // not first boot this.logger.trace("Functional groups: {}", this.toGroupNames(this.groupService.getFunctionalGroups(tenantId))); this.logger.trace("System groups: {}", this.toGroupNames(this.groupService.getSystemGroups(tenantId))); } } private Long findDefaultTenantId() { String defaultTenantName = this.licenseService.getDefaultTenantName(); this.logger.trace("Default Tenant: {}", defaultTenantName); List<Tenant> tenants = this.tenantService.findTenantsByName(defaultTenantName); if (tenants == null || tenants.isEmpty()) { this.logger.warn("Default tenant not found"); return null; } Tenant tenant = tenants.iterator().next(); return tenant.getId(); } private Collection<String> toGroupNames(Collection<Group> groups) { List<String> groupNames = new ArrayList<>(groups.size()); for (Group group : groups) groupNames.add(group.getName() + " [" + group.getExternalId() + "]"); return groupNames; } }