added APS v2.x compatibility
This commit is contained in:
16
pom.xml
16
pom.xml
@@ -3,8 +3,8 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.inteligr8.activiti</groupId>
|
||||
<artifactId>keycloak-activiti-app-ext</artifactId>
|
||||
<version>1.3-SNAPSHOT</version>
|
||||
<artifactId>keycloak-activiti-app-ext</artifactId>
|
||||
<version>1.3-SNAPSHOT</version>
|
||||
<name>Keycloak Authentication & Authorization for APS</name>
|
||||
|
||||
<properties>
|
||||
@@ -12,9 +12,9 @@
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<maven.compiler.release>11</maven.compiler.release>
|
||||
|
||||
<aps.version>1.11.1.1</aps.version>
|
||||
<keycloak.version>6.0.1</keycloak.version>
|
||||
<spring-security-oauth2.version>2.0.17.RELEASE</spring-security-oauth2.version>
|
||||
<aps.version>2.3.2</aps.version>
|
||||
<keycloak.version>10.0.2</keycloak.version>
|
||||
<spring-security-oauth2.version>2.5.2.RELEASE</spring-security-oauth2.version>
|
||||
<slf4j.version>1.7.26</slf4j.version>
|
||||
</properties>
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
<version>${keycloak.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Needed for Activiti App Identity Service inheritance/override -->
|
||||
<dependency>
|
||||
<groupId>com.activiti</groupId>
|
||||
<artifactId>activiti-app</artifactId>
|
||||
@@ -44,6 +45,7 @@
|
||||
<classifier>classes</classifier>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Needed for the Activiti App Public API -->
|
||||
<dependency>
|
||||
<groupId>com.activiti</groupId>
|
||||
<artifactId>activiti-app-logic</artifactId>
|
||||
@@ -53,6 +55,10 @@
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>alfresco-private</id>
|
||||
<url>https://artifacts.alfresco.com/nexus/content/groups/private</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>activiti-releases</id>
|
||||
<url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-enterprise-releases</url>
|
||||
|
@@ -1,162 +0,0 @@
|
||||
package com.inteligr8.activiti.keycloak;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.activiti.engine.IdentityService;
|
||||
import org.activiti.engine.identity.Group;
|
||||
import org.activiti.engine.identity.User;
|
||||
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.context.annotation.Lazy;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* This is an unused implementation for non-APS installation. It is not tested
|
||||
* and probably pointless.
|
||||
*
|
||||
* @author brian.long@yudrio.com
|
||||
*/
|
||||
@Component("keycloak-ext.activiti-engine.authenticator")
|
||||
@Lazy
|
||||
public class KeycloakActivitiEngineAuthenticator extends AbstractKeycloakActivitiAuthenticator {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
private IdentityService identityService;
|
||||
|
||||
@Value("${keycloak-ext.group.prefix:KEYCLOAK_}")
|
||||
private String groupPrefix;
|
||||
|
||||
/**
|
||||
* This method validates that the user exists, if not, it creates the
|
||||
* missing user. Without this functionality, SSO straight up fails.
|
||||
*/
|
||||
@Override
|
||||
public void preAuthenticate(Authentication auth) throws AuthenticationException {
|
||||
User user = this.findUser(auth);
|
||||
if (user == null) {
|
||||
if (this.createMissingUser) {
|
||||
this.logger.debug("User does not yet exist; creating the user: {}", auth.getName());
|
||||
|
||||
user = this.createUser(auth);
|
||||
this.logger.debug("Created user: {} => {}", user.getId(), user.getEmail());
|
||||
|
||||
if (this.clearNewUserDefaultGroups) {
|
||||
this.logger.debug("Clearing groups: {}", user.getId());
|
||||
List<Group> groups = this.identityService.createGroupQuery()
|
||||
.groupMember(user.getId())
|
||||
.list();
|
||||
for (Group group : groups)
|
||||
this.identityService.deleteMembership(user.getId(), group.getId());
|
||||
}
|
||||
} else {
|
||||
this.logger.info("User does not exist; user creation is disabled: {}", auth.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method validates that the groups exist, if not, it creates the
|
||||
* missing ones. Without this functionality, SSO works, but the user's
|
||||
* authorities are not synchronized.
|
||||
*/
|
||||
@Override
|
||||
public void postAuthenticate(Authentication auth) throws AuthenticationException {
|
||||
User user = this.findUser(auth);
|
||||
this.logger.debug("Inspecting user: {} => {}", user.getId(), user.getEmail());
|
||||
|
||||
this.syncUserRoles(user, auth);
|
||||
}
|
||||
|
||||
private User findUser(Authentication auth) {
|
||||
String email = auth.getName();
|
||||
|
||||
User user = this.identityService.createUserQuery()
|
||||
.userEmail(email)
|
||||
.singleResult();
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
private User createUser(Authentication auth) {
|
||||
User user = this.identityService.newUser(auth.getName());
|
||||
user.setEmail(auth.getName());
|
||||
this.identityService.saveUser(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
private void syncUserRoles(User user, Authentication auth) {
|
||||
Map<String, String> roles = this.getKeycloakRoles(auth);
|
||||
if (roles == null) {
|
||||
this.logger.debug("The user roles could not be determined; skipping sync: {}", user.getEmail());
|
||||
return;
|
||||
}
|
||||
|
||||
// check Activiti groups
|
||||
List<Group> groups = this.identityService.createGroupQuery()
|
||||
.groupMember(user.getEmail())
|
||||
.list();
|
||||
this.logger.debug("User is currently a member of {} groups", groups.size());
|
||||
for (Group group : groups) {
|
||||
if (!group.getId().startsWith(this.groupPrefix) && this.syncInternalGroups)
|
||||
continue;
|
||||
|
||||
this.logger.trace("Inspecting group: {} => {} ({})", group.getId(), group.getName(), group.getType());
|
||||
if (roles.remove(this.activitiGroupIdToKeycloakRole(group.getId())) != null) {
|
||||
this.logger.trace("Group and membership already exist: {} => {}", user.getEmail(), group.getName());
|
||||
// already a member of the group
|
||||
} else {
|
||||
if (this.syncGroupRemove) {
|
||||
this.logger.trace("Group membership not in OIDC token; removing from group: {} => {}", user.getEmail(), group.getName());
|
||||
this.identityService.deleteMembership(user.getId(), group.getId());
|
||||
} else {
|
||||
this.logger.debug("User/group membership sync disabled; not removing user from group: {} => {}", user.getId(), group.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.debug("Unaddressed OIDC roles: {}", roles);
|
||||
|
||||
// check remainder/unaddressed roles
|
||||
for (Entry<String, String> role : roles.entrySet()) {
|
||||
this.logger.trace("Inspecting role: {}", role);
|
||||
|
||||
Group group = this.identityService.createGroupQuery()
|
||||
.groupId(this.keycloakRoleToActivitiGroupId(role.getKey()))
|
||||
.singleResult();
|
||||
if (group == null) {
|
||||
if (this.createMissingGroup) {
|
||||
this.logger.trace("Group does not exist; creating one");
|
||||
group = this.identityService.newGroup(this.keycloakRoleToActivitiGroupId(role.getKey()));
|
||||
group.setName(role.getValue());
|
||||
this.identityService.saveGroup(group);
|
||||
} else {
|
||||
this.logger.info("Group does not exist; group creation is disabled: {}", role.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
if (group != null && this.syncGroupAdd) {
|
||||
this.logger.trace("Group membership not in Activiti; adding to group: {} => {}", user.getEmail(), group.getName());
|
||||
this.identityService.createMembership(user.getId(), group.getId());
|
||||
} else {
|
||||
this.logger.debug("User/group membership sync disabled; not adding user to group: {} => {}", user.getId(), group.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String keycloakRoleToActivitiGroupId(String role) {
|
||||
return this.groupPrefix + role;
|
||||
}
|
||||
|
||||
private String activitiGroupIdToKeycloakRole(String groupId) {
|
||||
return groupId.startsWith(this.groupPrefix) ? groupId.substring(this.groupPrefix.length()) : groupId;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user