Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
14487b62eb | |||
e87a6b68a7 | |||
19f21fdd5c | |||
5ecb627dbf | |||
df37818f09 | |||
f3b70c1574 | |||
ea487fee31 | |||
9f9ededab2 | |||
116e22bbd6 | |||
f76105b979 | |||
9ad7a9e560 |
4
pom.xml
4
pom.xml
@@ -4,7 +4,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.inteligr8.activiti</groupId>
|
<groupId>com.inteligr8.activiti</groupId>
|
||||||
<artifactId>keycloak-activiti-app-ext</artifactId>
|
<artifactId>keycloak-activiti-app-ext</artifactId>
|
||||||
<version>1.1.3</version>
|
<version>1.2.1</version>
|
||||||
<name>Keycloak Authentication & Authorization for APS</name>
|
<name>Keycloak Authentication & Authorization for APS</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -87,7 +87,7 @@
|
|||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
<repository>
|
<repository>
|
||||||
<id>inteligr8-releases</id>
|
<id>inteligr8-releases</id>
|
||||||
<url>https://repos.inteligr8.com/nexus/repository/inteligr8-private</url>
|
<url>https://repos.inteligr8.com/nexus/repository/inteligr8-public</url>
|
||||||
</repository>
|
</repository>
|
||||||
<snapshotRepository>
|
<snapshotRepository>
|
||||||
<id>inteligr8-snapshots</id>
|
<id>inteligr8-snapshots</id>
|
||||||
|
@@ -0,0 +1,128 @@
|
|||||||
|
package com.inteligr8.activiti;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
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.stereotype.Component;
|
||||||
|
|
||||||
|
import com.activiti.domain.idm.Group;
|
||||||
|
import com.activiti.domain.idm.GroupCapability;
|
||||||
|
import com.activiti.domain.idm.Tenant;
|
||||||
|
import com.activiti.service.api.GroupService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ActivitiAppAdminGroupFixer implements DataFixer {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
|
private final List<String> adminCapabilities = Arrays.asList(
|
||||||
|
"access-all-models-in-tenant",
|
||||||
|
"access-editor",
|
||||||
|
"access-reports",
|
||||||
|
"publish-app-to-dashboard",
|
||||||
|
"tenant-admin",
|
||||||
|
"tenant-admin-api",
|
||||||
|
"upload-license");
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private GroupService groupService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TenantFinderService tenantFinderService;
|
||||||
|
|
||||||
|
@Value("${keycloak-ext.group.admins.name:admins}")
|
||||||
|
private String adminGroupName;
|
||||||
|
|
||||||
|
@Value("${keycloak-ext.group.admins.externalId:#{null}}")
|
||||||
|
private String adminGroupExternalId;
|
||||||
|
|
||||||
|
@Value("${keycloak-ext.group.admins.validate:false}")
|
||||||
|
private boolean validateAdministratorsGroup;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fix() {
|
||||||
|
this.logger.trace("fix()");
|
||||||
|
|
||||||
|
if (this.logger.isTraceEnabled())
|
||||||
|
this.logGroups();
|
||||||
|
if (this.validateAdministratorsGroup)
|
||||||
|
this.validateAdmins();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logGroups() {
|
||||||
|
if (this.groupService == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Collection<Tenant> tenants = this.tenantFinderService.getTenants();
|
||||||
|
for (Tenant tenant : tenants) {
|
||||||
|
this.logger.trace("Tenant: {} => {}", tenant.getId(), tenant.getName());
|
||||||
|
this.logger.trace("Functional groups: {}", this.toGroupNames(this.groupService.getFunctionalGroups(tenant.getId())));
|
||||||
|
this.logger.trace("System groups: {}", this.toGroupNames(this.groupService.getSystemGroups(tenant.getId())));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.trace("Tenant: null");
|
||||||
|
this.logger.trace("Functional groups: {}", this.toGroupNames(this.groupService.getFunctionalGroups(null)));
|
||||||
|
this.logger.trace("System groups: {}", this.toGroupNames(this.groupService.getSystemGroups(null)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateAdmins() {
|
||||||
|
if (this.groupService == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Long tenantId = this.tenantFinderService.findTenantId();
|
||||||
|
Group group = this.groupService.getGroupByExternalIdAndTenantId(this.adminGroupExternalId, tenantId);
|
||||||
|
if (group == null) {
|
||||||
|
List<Group> groups = this.groupService.getGroupByNameAndTenantId(this.adminGroupName, tenantId);
|
||||||
|
if (!groups.isEmpty())
|
||||||
|
group = groups.iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group == null) {
|
||||||
|
this.logger.info("Creating group: {} ({})", this.adminGroupName, this.adminGroupExternalId);
|
||||||
|
if (this.adminGroupExternalId != null) {
|
||||||
|
group = this.groupService.createGroupFromExternalStore(
|
||||||
|
this.adminGroupExternalId, tenantId, Group.TYPE_SYSTEM_GROUP, null, this.adminGroupName, new Date());
|
||||||
|
} else {
|
||||||
|
group = this.groupService.createGroup(this.adminGroupName, tenantId, Group.TYPE_SYSTEM_GROUP, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.debug("Checking group capabilities: {}", group.getName());
|
||||||
|
Group groupWithCaps = this.groupService.getGroup(group.getId(), false, true, false, false);
|
||||||
|
Set<String> adminCaps = new HashSet<>(this.adminCapabilities);
|
||||||
|
for (GroupCapability cap : groupWithCaps.getCapabilities())
|
||||||
|
adminCaps.remove(cap.getName());
|
||||||
|
if (!adminCaps.isEmpty()) {
|
||||||
|
this.logger.info("Granting group '{}' capabilities: {}", group.getName(), adminCaps);
|
||||||
|
this.groupService.addCapabilitiesToGroup(group.getId(), new ArrayList<>(adminCaps));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,95 @@
|
|||||||
|
package com.inteligr8.activiti;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.persistence.NonUniqueResultException;
|
||||||
|
|
||||||
|
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.stereotype.Component;
|
||||||
|
|
||||||
|
import com.activiti.domain.idm.Group;
|
||||||
|
import com.activiti.domain.idm.User;
|
||||||
|
import com.activiti.service.api.GroupService;
|
||||||
|
import com.activiti.service.api.UserService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ActivitiAppAdminMembersFixer implements DataFixer {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private GroupService groupService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TenantFinderService tenantFinderService;
|
||||||
|
|
||||||
|
@Value("${keycloak-ext.default.admins.users:#{null}}")
|
||||||
|
private String adminUserStrs;
|
||||||
|
|
||||||
|
@Value("${keycloak-ext.group.admins.name:admins}")
|
||||||
|
private String adminGroupName;
|
||||||
|
|
||||||
|
@Value("${keycloak-ext.group.admins.externalId:#{null}}")
|
||||||
|
private String adminGroupExternalId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fix() {
|
||||||
|
this.logger.trace("fix()");
|
||||||
|
|
||||||
|
if (this.adminUserStrs != null && this.adminUserStrs.length() > 0)
|
||||||
|
this.associateAdmins();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void associateAdmins() {
|
||||||
|
if (this.userService == null || this.groupService == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<String> adminUsers = Arrays.asList(this.adminUserStrs.split(","));
|
||||||
|
if (adminUsers.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Long tenantId = this.tenantFinderService.findTenantId();
|
||||||
|
List<Group> groups = null;
|
||||||
|
try {
|
||||||
|
Group group1 = this.groupService.getGroupByExternalIdAndTenantId(this.adminGroupExternalId, tenantId);
|
||||||
|
if (group1 != null)
|
||||||
|
groups = Arrays.asList(group1);
|
||||||
|
} catch (NonUniqueResultException nure) {
|
||||||
|
// suppress
|
||||||
|
}
|
||||||
|
if (groups == null)
|
||||||
|
groups = this.groupService.getGroupByNameAndTenantId(this.adminGroupName, tenantId);
|
||||||
|
|
||||||
|
this.logger.debug("Found {} admin group(s)", groups.size());
|
||||||
|
|
||||||
|
for (String email : adminUsers) {
|
||||||
|
User user = this.userService.findUserByEmailAndTenantId(email, tenantId);
|
||||||
|
if (user == null) {
|
||||||
|
this.logger.info("The user with email '{}' does not exist, so they cannot be added as an administrator", email);
|
||||||
|
} else {
|
||||||
|
this.logger.debug("Adding {} to admin group(s)", user.getEmail());
|
||||||
|
for (Group group : groups)
|
||||||
|
this.groupService.addUserToGroup(group, user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
7
src/main/java/com/inteligr8/activiti/DataFixer.java
Normal file
7
src/main/java/com/inteligr8/activiti/DataFixer.java
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package com.inteligr8.activiti;
|
||||||
|
|
||||||
|
public interface DataFixer {
|
||||||
|
|
||||||
|
void fix();
|
||||||
|
|
||||||
|
}
|
@@ -1,31 +1,16 @@
|
|||||||
package com.inteligr8.activiti;
|
package com.inteligr8.activiti;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
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.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.activiti.api.security.AlfrescoSecurityConfigOverride;
|
import com.activiti.api.security.AlfrescoSecurityConfigOverride;
|
||||||
import com.activiti.domain.idm.Group;
|
|
||||||
import com.activiti.domain.idm.GroupCapability;
|
|
||||||
import com.activiti.domain.idm.Tenant;
|
|
||||||
import com.activiti.domain.idm.User;
|
|
||||||
import com.activiti.service.api.GroupService;
|
|
||||||
import com.activiti.service.api.UserService;
|
|
||||||
import com.activiti.service.idm.TenantService;
|
|
||||||
import com.activiti.service.license.LicenseService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class/bean overrides the APS security configuration with a collection
|
* This class/bean overrides the APS security configuration with a collection
|
||||||
@@ -43,41 +28,11 @@ public class Inteligr8SecurityConfigurationRegistry implements AlfrescoSecurityC
|
|||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
private final List<String> adminCapabilities = Arrays.asList(
|
|
||||||
"access-all-models-in-tenant",
|
|
||||||
"access-editor",
|
|
||||||
"access-reports",
|
|
||||||
"publish-app-to-dashboard",
|
|
||||||
"tenant-admin",
|
|
||||||
"tenant-admin-api",
|
|
||||||
"upload-license");
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private List<ActivitiSecurityConfigAdapter> adapters;
|
private List<ActivitiSecurityConfigAdapter> adapters;
|
||||||
|
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private LicenseService licenseService;
|
private List<DataFixer> fixers;
|
||||||
|
|
||||||
@Autowired(required = false)
|
|
||||||
private TenantService tenantService;
|
|
||||||
|
|
||||||
@Autowired(required = false)
|
|
||||||
private UserService userService;
|
|
||||||
|
|
||||||
@Autowired(required = false)
|
|
||||||
private GroupService groupService;
|
|
||||||
|
|
||||||
@Value("${keycloak-ext.default.admins.users:#{null}}")
|
|
||||||
private String adminUserStrs;
|
|
||||||
|
|
||||||
@Value("${keycloak-ext.group.admins.name:admins}")
|
|
||||||
private String adminGroupName;
|
|
||||||
|
|
||||||
@Value("${keycloak-ext.group.admins.externalId:#{null}}")
|
|
||||||
private String adminGroupExternalId;
|
|
||||||
|
|
||||||
@Value("${keycloak-ext.group.admins.validate:false}")
|
|
||||||
private boolean validateAdministratorsGroup;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configureGlobal(AuthenticationManagerBuilder authmanBuilder, UserDetailsService userDetailsService) {
|
public void configureGlobal(AuthenticationManagerBuilder authmanBuilder, UserDetailsService userDetailsService) {
|
||||||
@@ -85,12 +40,10 @@ public class Inteligr8SecurityConfigurationRegistry implements AlfrescoSecurityC
|
|||||||
|
|
||||||
Collections.sort(this.adapters);
|
Collections.sort(this.adapters);
|
||||||
|
|
||||||
if (this.logger.isTraceEnabled())
|
if (this.fixers != null) {
|
||||||
this.logGroups();
|
for (DataFixer fixer : this.fixers)
|
||||||
if (this.validateAdministratorsGroup)
|
fixer.fix();
|
||||||
this.validateAdmins();
|
}
|
||||||
if (this.adminUserStrs != null && this.adminUserStrs.length() > 0)
|
|
||||||
this.associateAdmins();
|
|
||||||
|
|
||||||
for (ActivitiSecurityConfigAdapter adapter : this.adapters) {
|
for (ActivitiSecurityConfigAdapter adapter : this.adapters) {
|
||||||
if (adapter.isEnabled()) {
|
if (adapter.isEnabled()) {
|
||||||
@@ -103,90 +56,4 @@ public class Inteligr8SecurityConfigurationRegistry implements AlfrescoSecurityC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logGroups() {
|
|
||||||
if (this.groupService == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
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 void validateAdmins() {
|
|
||||||
if (this.groupService == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Long tenantId = this.findDefaultTenantId();
|
|
||||||
Group group = this.groupService.getGroupByExternalIdAndTenantId(this.adminGroupExternalId, tenantId);
|
|
||||||
if (group == null) {
|
|
||||||
List<Group> groups = this.groupService.getGroupByNameAndTenantId(this.adminGroupName, tenantId);
|
|
||||||
if (!groups.isEmpty())
|
|
||||||
group = groups.iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (group == null) {
|
|
||||||
this.logger.info("Creating group: {} ({})", this.adminGroupName, this.adminGroupExternalId);
|
|
||||||
if (this.adminGroupExternalId != null) {
|
|
||||||
group = this.groupService.createGroupFromExternalStore(
|
|
||||||
this.adminGroupExternalId, tenantId, Group.TYPE_SYSTEM_GROUP, null, this.adminGroupName, new Date());
|
|
||||||
} else {
|
|
||||||
group = this.groupService.createGroup(this.adminGroupName, tenantId, Group.TYPE_SYSTEM_GROUP, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger.debug("Checking group capabilities: {}", group.getName());
|
|
||||||
Group groupWithCaps = this.groupService.getGroup(group.getId(), false, true, false, false);
|
|
||||||
Set<String> adminCaps = new HashSet<>(this.adminCapabilities);
|
|
||||||
for (GroupCapability cap : groupWithCaps.getCapabilities())
|
|
||||||
adminCaps.remove(cap.getName());
|
|
||||||
if (!adminCaps.isEmpty()) {
|
|
||||||
this.logger.info("Granting group '{}' capabilities: {}", group.getName(), adminCaps);
|
|
||||||
this.groupService.addCapabilitiesToGroup(group.getId(), new ArrayList<>(adminCaps));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void associateAdmins() {
|
|
||||||
if (this.userService == null || this.groupService == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
List<String> adminUsers = Arrays.asList(this.adminUserStrs.split(","));
|
|
||||||
if (adminUsers.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Long tenantId = this.findDefaultTenantId();
|
|
||||||
List<Group> groups = this.groupService.getSystemGroupWithName("Administrators", tenantId);
|
|
||||||
|
|
||||||
for (String email : adminUsers) {
|
|
||||||
User user = this.userService.findUserByEmail(email);
|
|
||||||
|
|
||||||
this.logger.debug("Adding {} to {}", user.getEmail(), "Administrators");
|
|
||||||
for (Group group : groups)
|
|
||||||
this.groupService.addUserToGroup(group, user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,82 @@
|
|||||||
|
package com.inteligr8.activiti;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
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.stereotype.Component;
|
||||||
|
|
||||||
|
import com.activiti.domain.idm.Tenant;
|
||||||
|
import com.activiti.service.idm.TenantService;
|
||||||
|
import com.activiti.service.license.LicenseService;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class TenantFinderService {
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private LicenseService licenseService;
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
private TenantService tenantService;
|
||||||
|
|
||||||
|
@Value("${keycloak-ext.tenant:#{null}}")
|
||||||
|
private String tenant;
|
||||||
|
|
||||||
|
public Long findTenantId() {
|
||||||
|
Tenant tenant = this.findTenant();
|
||||||
|
return tenant == null ? null : tenant.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tenant findTenant() {
|
||||||
|
this.logger.debug("Checking for a single tenant ...");
|
||||||
|
|
||||||
|
String tenantName = null;
|
||||||
|
if (this.tenant != null) {
|
||||||
|
tenantName = this.tenant;
|
||||||
|
} else {
|
||||||
|
List<Object[]> tenants = this.tenantService.getAllTenants();
|
||||||
|
if (tenants == null || tenants.isEmpty()) {
|
||||||
|
this.logger.warn("No tenants found!");
|
||||||
|
return null;
|
||||||
|
} else if (tenants.size() == 1) {
|
||||||
|
Object[] tenant = tenants.iterator().next();
|
||||||
|
this.logger.debug("Only one tenant available; selecting it: {}", tenant[0]);
|
||||||
|
return this.tenantService.getTenant((Long)tenant[0]);
|
||||||
|
} else {
|
||||||
|
tenantName = this.licenseService.getDefaultTenantName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.debug("Trying to find by tenant name: {}", tenantName);
|
||||||
|
|
||||||
|
List<Tenant> tenants = this.tenantService.findTenantsByName(tenantName);
|
||||||
|
if (tenants == null || tenants.isEmpty()) {
|
||||||
|
this.logger.warn("Named tenant not found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.logger.debug("Found {} tenants with name {}; selecting the first one", tenants.size(), tenantName);
|
||||||
|
return tenants.iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Tenant> getTenants() {
|
||||||
|
List<Object[]> tenantObjs = this.tenantService.getAllTenants();
|
||||||
|
|
||||||
|
List<Tenant> tenants = new ArrayList<>(tenantObjs.size());
|
||||||
|
for (Object[] tenantObj : tenantObjs) {
|
||||||
|
if (tenantObj != null && tenantObj[0] != null) {
|
||||||
|
Tenant tenant = this.tenantService.getTenant((Long)tenantObj[0]);
|
||||||
|
tenants.add(tenant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tenants;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -21,12 +21,10 @@ import org.springframework.security.core.AuthenticationException;
|
|||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.activiti.domain.idm.Group;
|
import com.activiti.domain.idm.Group;
|
||||||
import com.activiti.domain.idm.Tenant;
|
|
||||||
import com.activiti.domain.idm.User;
|
import com.activiti.domain.idm.User;
|
||||||
import com.activiti.service.api.GroupService;
|
import com.activiti.service.api.GroupService;
|
||||||
import com.activiti.service.api.UserService;
|
import com.activiti.service.api.UserService;
|
||||||
import com.activiti.service.idm.TenantService;
|
import com.inteligr8.activiti.TenantFinderService;
|
||||||
import com.activiti.service.license.LicenseService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class/bean implements an Open ID Connect authenticator for Alfresco
|
* This class/bean implements an Open ID Connect authenticator for Alfresco
|
||||||
@@ -49,18 +47,15 @@ public class KeycloakActivitiAppAuthenticator extends AbstractKeycloakActivitiAu
|
|||||||
|
|
||||||
private final Pattern emailNamesPattern = Pattern.compile("([A-Za-z]+)[A-Za-z0-9]*\\.([A-Za-z]+)[A-Za-z0-9]*@.*");
|
private final Pattern emailNamesPattern = Pattern.compile("([A-Za-z]+)[A-Za-z0-9]*\\.([A-Za-z]+)[A-Za-z0-9]*@.*");
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private LicenseService licenseService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TenantService tenantService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private GroupService groupService;
|
private GroupService groupService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TenantFinderService tenantFinderService;
|
||||||
|
|
||||||
@Value("${keycloak-ext.external.id:ais}")
|
@Value("${keycloak-ext.external.id:ais}")
|
||||||
protected String externalIdmSource;
|
protected String externalIdmSource;
|
||||||
|
|
||||||
@@ -81,7 +76,7 @@ public class KeycloakActivitiAppAuthenticator extends AbstractKeycloakActivitiAu
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void preAuthenticate(Authentication auth) throws AuthenticationException {
|
public void preAuthenticate(Authentication auth) throws AuthenticationException {
|
||||||
Long tenantId = this.findDefaultTenantId();
|
Long tenantId = this.tenantFinderService.findTenantId();
|
||||||
this.logger.trace("Tenant ID: {}", tenantId);
|
this.logger.trace("Tenant ID: {}", tenantId);
|
||||||
|
|
||||||
User user = this.findUser(auth, tenantId);
|
User user = this.findUser(auth, tenantId);
|
||||||
@@ -122,27 +117,13 @@ public class KeycloakActivitiAppAuthenticator extends AbstractKeycloakActivitiAu
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void postAuthenticate(Authentication auth) throws AuthenticationException {
|
public void postAuthenticate(Authentication auth) throws AuthenticationException {
|
||||||
Long tenantId = this.findDefaultTenantId();
|
Long tenantId = this.tenantFinderService.findTenantId();
|
||||||
User user = this.findUser(auth, tenantId);
|
User user = this.findUser(auth, tenantId);
|
||||||
this.logger.debug("Inspecting user: {} => {}", user.getId(), user.getExternalId());
|
this.logger.debug("Inspecting user: {} => {}", user.getId(), user.getExternalId());
|
||||||
|
|
||||||
this.syncUserRoles(user, auth, tenantId);
|
this.syncUserRoles(user, auth, 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 User findUser(Authentication auth, Long tenantId) {
|
private User findUser(Authentication auth, Long tenantId) {
|
||||||
String email = auth.getName();
|
String email = auth.getName();
|
||||||
|
|
||||||
@@ -193,8 +174,18 @@ public class KeycloakActivitiAppAuthenticator extends AbstractKeycloakActivitiAu
|
|||||||
this.logger.trace("Inspecting group: {} => {} ({})", group.getId(), group.getName(), group.getExternalId());
|
this.logger.trace("Inspecting group: {} => {} ({})", group.getId(), group.getName(), group.getExternalId());
|
||||||
|
|
||||||
if (group.getExternalId() != null && this.removeMapEntriesByValue(roles, this.apsGroupExternalIdToKeycloakRole(group.getExternalId()))) {
|
if (group.getExternalId() != null && this.removeMapEntriesByValue(roles, this.apsGroupExternalIdToKeycloakRole(group.getExternalId()))) {
|
||||||
|
if (group.getTenantId() == null) {
|
||||||
|
// fix stray groups
|
||||||
|
group.setTenantId(tenantId);
|
||||||
|
group.setLastUpdate(new Date());
|
||||||
|
this.groupService.save(group);
|
||||||
|
}
|
||||||
// role already existed and the user is already a member
|
// role already existed and the user is already a member
|
||||||
} else if (group.getExternalId() == null && roles.remove(this.apsGroupNameToKeycloakRole(group.getName())) != null) {
|
} else if (group.getExternalId() == null && roles.remove(this.apsGroupNameToKeycloakRole(group.getName())) != null) {
|
||||||
|
// register the group as external
|
||||||
|
group.setExternalId(this.keycloakRoleToApsGroupExternalId(this.apsGroupNameToKeycloakRole(group.getName())));
|
||||||
|
group.setLastUpdate(new Date());
|
||||||
|
this.groupService.save(group);
|
||||||
// internal role already existed and the user is already a member
|
// internal role already existed and the user is already a member
|
||||||
} else {
|
} else {
|
||||||
// at this point, we have a group that the user does not have a corresponding role for
|
// at this point, we have a group that the user does not have a corresponding role for
|
||||||
|
Reference in New Issue
Block a user