Commit 44d0bf53 authored by Brian Long's avatar Brian Long
Browse files

Merge branch 'develop' into stable

parents 80729488 a856ab7d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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 &amp; Authorization for APS</name>

	<properties>
+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);
	}

}
+1 −1
Original line number Diff line number Diff line
@@ -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 {

}
+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());
	}

}
+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