Skip to content

Commit

Permalink
Merge pull request #165 from dinesh-aot/ff-407
Browse files Browse the repository at this point in the history
Debugging analytics Issue; bpm version changed to 4.0.7; changes made to KeyCloak migration
  • Loading branch information
linhwing authored Jun 13, 2023
2 parents 3eb0db6 + 96fdcda commit 1e2bad8
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 10 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.vscode/

*.iml
**/.idea/
*.iml
8 changes: 4 additions & 4 deletions apps/forms-flow-ai/forms-flow-bpm/pom-docker.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
<version.camundaSpringBoot>7.15.0</version.camundaSpringBoot>
<version.camundaConnect>1.2.2</version.camundaConnect><!-- 1.5.0 -->
<version.camundaMail>1.2.0</version.camundaMail><!-- 1.3.0 -->
<version.springBoot>2.4.8</version.springBoot><!-- 2.4.2 - 2.4.8 -->
<version.springSecurityOauth2>2.4.8</version.springSecurityOauth2><!-- 2.4.2 - 2.4.8 -->
<version.jackson>2.12.2</version.jackson>
<version.camundaKeycloak>2.2.1</version.camundaKeycloak>
<version.springBoot>2.6.4</version.springBoot><!-- 2.4.2 - 2.4.8 -->
<version.springSecurityOauth2>2.6.4</version.springSecurityOauth2><!-- 2.4.2 - 2.4.8 -->
<version.jackson>2.13.3</version.jackson>
<version.camundaKeycloak>2.2.3</version.camundaKeycloak>
</properties>

<dependencyManagement>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,19 @@ private Map<String,Object> prepareRequestVariableMap(String formXML) throws IOEx
variables.put("files_entity_key", new VariableData("cciifiles"));
variables.put("submit_date_time", new VariableData(new DateTime().toString()));
variables.put("entered_by", new VariableData("orbeon"));
VariableData serviceMethodData = (VariableData)variables.get("service_method");
variables.put("engagement_source", new VariableData(serviceMethodData.getValue().toString()));
VariableData serviceChannelData = (VariableData)variables.get("service_channel");
if(serviceChannelData.getValue().toString().equals("Service BC Location")){
variables.put("service_location_type", new VariableData("service_centre"));
}else if(serviceChannelData.getValue().equals("Mobile Outreach Location")){
variables.put("service_location_type", new VariableData("mobile_outreach"));
}
variables.put("service_channel", new VariableData("Service BC Location"));
// Check if Orbeon is submitted with a value for "mobile-location"
if(variables.containsKey("mobile_location")) {
// Set location parameter to "Mobile Outreach"
variables.put("location", new VariableData("Mobile Outreach"));
LOGGER.info("Mobile Location Found: "+variables);
}
}
return variables;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ private Map<String,Object> injectAdditionalProcessingFields(DelegateExecution ex
if (StringUtils.isNotEmpty(idir)) {
prcMap.put(entry.getKey(),entry.getValue());
if(!execution.getVariables().containsKey(StringUtils.substringBefore(entry.getKey(), "_idir").concat("_name"))) {
String idirName = getName(execution, idir);
String idirName = getName(execution, variables.get("provider_idir_userid").toString());
execution.setVariable(StringUtils.substringBefore(entry.getKey(), "_idir").concat("_name"), idirName);
prcMap.put(StringUtils.substringBefore(entry.getKey(), "_idir").concat("_name"),idirName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,17 @@
public interface IUser {

default String getName(DelegateExecution execution, String userId) {
User user = execution.getProcessEngine().getIdentityService().createUserQuery().userId(userId).singleResult();
User user = getUser(execution, userId);
return user.getFirstName()+" "+user.getLastName();
}

default String getEmail(DelegateExecution execution, String userId) {
User user = execution.getProcessEngine().getIdentityService().createUserQuery().userId(userId).singleResult();
User user = getUser(execution, userId);
return user.getEmail();
}

default User getUser(DelegateExecution execution, String userId) {
userId = execution.getVariable("provider_idir_userid").toString();
return execution.getProcessEngine().getIdentityService().createUserQuery().userId(userId).singleResult();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.camunda.bpm.extension.keycloak.plugin;

import java.util.Collections;
import java.util.List;

import org.camunda.bpm.engine.identity.Group;
import org.camunda.bpm.engine.identity.User;
import org.camunda.bpm.engine.impl.interceptor.CommandContext;
import org.camunda.bpm.extension.keycloak.*;
import org.camunda.bpm.extension.keycloak.cache.QueryCache;
import org.camunda.bpm.extension.keycloak.rest.KeycloakRestTemplate;
import org.camunda.bpm.extension.keycloak.util.KeycloakPluginLogger;
import org.springframework.util.StringUtils;

/**
* @author aot
*
*/
public class KeycloakIdentityProviderSession
extends org.camunda.bpm.extension.keycloak.KeycloakIdentityProviderSession {

public KeycloakIdentityProviderSession(KeycloakConfiguration keycloakConfiguration, KeycloakRestTemplate restTemplate, KeycloakContextProvider keycloakContextProvider,
QueryCache<CacheableKeycloakUserQuery, List<User>> userQueryCache, QueryCache<CacheableKeycloakGroupQuery, List<Group>> groupQueryCache,
QueryCache<CacheableKeycloakCheckPasswordCall, Boolean> checkPasswordCache,
String webClientId, boolean enableClientAuth) {
super(keycloakConfiguration, restTemplate, keycloakContextProvider, userQueryCache, groupQueryCache, checkPasswordCache);
this.groupService = new KeycloakGroupService(keycloakConfiguration, restTemplate, keycloakContextProvider, webClientId, enableClientAuth);
this.userService = new KeycloakUserService(keycloakConfiguration, restTemplate, keycloakContextProvider, webClientId, enableClientAuth);
}

/**
* Get the group ID of the configured admin group. Enable configuration using group path as well.
* This prevents common configuration pitfalls and makes it consistent to other configuration options
* like the flag 'useGroupPathAsCamundaGroupId'.
*
* @param configuredAdminGroupName the originally configured admin group name
* @return the corresponding keycloak group ID to use: either internal keycloak ID or path, depending on config
*
* @see org.camunda.bpm.extension.keycloak.KeycloakGroupService#getKeycloakAdminGroupId(java.lang.String)
*/
public String getKeycloakAdminGroupId(String configuredAdminGroupName) {
return groupService.getKeycloakAdminGroupId(configuredAdminGroupName);
}

/**
*
* @param userQuery
* @return
*/
protected List<User> findUserByQueryCriteria(KeycloakUserQuery userQuery) {
StringBuilder resultLogger = new StringBuilder();
if (KeycloakPluginLogger.INSTANCE.isDebugEnabled()) {
resultLogger.append("Keycloak group query results: [");
}

List<User> allMatchingUsers = userQueryCache.getOrCompute(CacheableKeycloakUserQuery.of(userQuery),
this::doFindUserByQueryCriteria);
List<User> processedUsers = userService.postProcessResults(userQuery, allMatchingUsers, resultLogger);
if (KeycloakPluginLogger.INSTANCE.isDebugEnabled()) {
resultLogger.append("]");
KeycloakPluginLogger.INSTANCE.groupQueryResult(resultLogger.toString());
}

return processedUsers;
}

/**
*
* @param userQuery
* @return
*/
private List<User> doFindUserByQueryCriteria(CacheableKeycloakUserQuery userQuery) {
return StringUtils.hasLength(userQuery.getGroupId()) ?
this.userService.requestUsersByGroupId(userQuery) :
this.userService.requestUsersWithoutGroupId(userQuery);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package org.camunda.bpm.extension.keycloak.plugin;

import org.camunda.bpm.engine.identity.User;
import org.camunda.bpm.engine.impl.persistence.entity.UserEntity;
import org.camunda.bpm.extension.keycloak.KeycloakConfiguration;
import org.camunda.bpm.extension.keycloak.rest.KeycloakRestTemplate;
import org.camunda.bpm.extension.keycloak.KeycloakContextProvider;
import org.camunda.bpm.extension.keycloak.KeycloakGroupNotFoundException;
import org.camunda.bpm.extension.keycloak.CacheableKeycloakUserQuery;
import org.camunda.bpm.engine.impl.identity.IdentityProviderException;
import org.camunda.bpm.extension.keycloak.json.JsonException;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestClientException;
import org.springframework.util.StringUtils;

import java.util.logging.Logger;

import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;

import static org.camunda.bpm.extension.keycloak.json.JsonUtil.*;

/**
* Keycloak User Service.
* Custom class for Implementation of user queries against Keycloak's REST API.
*/
public class KeycloakUserService extends org.camunda.bpm.extension.keycloak.KeycloakUserService {

/** This class' logger. */
private final Logger LOGGER = Logger.getLogger(KeycloakUserService.class.getName());

private String webClientId;
private boolean enableClientAuth;

public KeycloakUserService(KeycloakConfiguration keycloakConfiguration, KeycloakRestTemplate restTemplate,
KeycloakContextProvider keycloakContextProvider,String webClientId,boolean enableClientAuth) {
super(keycloakConfiguration, restTemplate, keycloakContextProvider);
this.webClientId = webClientId;
this.enableClientAuth = enableClientAuth;
}

@Override
public List<User> requestUsersByGroupId(CacheableKeycloakUserQuery query) {
String groupId = query.getGroupId();
List<User> userList = new ArrayList<>();

try {
// get Keycloak specific groupID
String keyCloakID;
try {
keyCloakID = getKeycloakGroupID(groupId);
} catch (KeycloakGroupNotFoundException e) {
// group not found: empty search result
return Collections.emptyList();
}

// get members of this group
ResponseEntity<String> response = restTemplate.exchange(
keycloakConfiguration.getKeycloakAdminUrl() + "/groups/" + keyCloakID + "/members?max=" + getMaxQueryResultSize(),
HttpMethod.GET, String.class);
if (!response.getStatusCode().equals(HttpStatus.OK)) {
throw new IdentityProviderException(
"Unable to read group members from " + keycloakConfiguration.getKeycloakAdminUrl()
+ ": HTTP status code " + response.getStatusCodeValue());
}

JsonArray searchResult = parseAsJsonArray(response.getBody());
for (int i = 0; i < searchResult.size(); i++) {
JsonObject keycloakUser = getJsonObjectAtIndex(searchResult, i);
if (keycloakConfiguration.isUseEmailAsCamundaUserId() &&
!StringUtils.hasLength(getJsonString(keycloakUser, "email"))) {
continue;
}
if (keycloakConfiguration.isUseUsernameAsCamundaUserId() &&
!StringUtils.hasLength(getJsonString(keycloakUser, "username"))) {
continue;
}
userList.add(transformUser(keycloakUser));
}

} catch (HttpClientErrorException hcee) {
// if groupID is unknown server answers with HTTP 404 not found
if (hcee.getStatusCode().equals(HttpStatus.NOT_FOUND)) {
return Collections.emptyList();
}
throw hcee;
} catch (RestClientException | JsonException rce) {
throw new IdentityProviderException("Unable to query members of group " + groupId, rce);
}

return userList;
}

private UserEntity transformUser(JsonObject result) throws JsonException {
UserEntity user = new UserEntity();
String userId = getJsonString(result, "username");
JsonObject attributes = getJsonObject(result, "attributes");
if(attributes != null) {
JsonArray userIds = attributes.getAsJsonArray("userid");
if(userIds != null) {
userId = userIds.get(0).getAsString();
}
}

String email = getJsonString(result, "email");
String firstName = getJsonString(result, "firstName");
String lastName = getJsonString(result, "lastName");
user.setId(userId);
user.setEmail(email);
user.setFirstName(firstName);
user.setLastName(lastName);
return user;
}
}
2 changes: 1 addition & 1 deletion apps/forms-flow-ai/forms-flow-web/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ RUN npm run build
FROM artifacts.developer.gov.bc.ca/docker-remote/nginx:1.17 as production-stage
RUN mkdir /app
COPY --from=build-stage /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=build-stage /app/nginx.conf /etc/nginx/nginx.conf
EXPOSE 8080:8080
CMD ["nginx", "-g", "daemon off;"]

0 comments on commit 1e2bad8

Please sign in to comment.