/*
* Copyright 2012 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jbpm.services.task.identity;
import java.util.List;
import java.util.Properties;
import javax.naming.directory.SearchResult;
import org.kie.api.task.UserGroupCallback;
/**
* LDAP integration for Task Service to collect user and role/group information.
* <p>
* Following is a list of all supported properties:
* <ul>
* <li>ldap.bind.user (optional if LDAP server accepts anonymous access)</li>
* <li>ldap.bind.pwd (optional if LDAP server accepts anonymous access</li>
* <li>ldap.user.ctx (mandatory)</li>
* <li>ldap.role.ctx (mandatory)</li>
* <li>ldap.user.roles.ctx (optional, if not given ldap.role.ctx will be used)</li>
* <li>ldap.user.filter (mandatory)</li>
* <li>ldap.role.filter (mandatory)</li>
* <li>ldap.user.roles.filter (mandatory)</li>
* <li>ldap.user.attr.id (optional, if not given 'uid' will be used)</li>
* <li>ldap.roles.attr.id (optional, if not given 'cn' will be used)</li>
* <li>ldap.user.id.dn (optional, is user id a DN, instructs the callback to query for user DN before searching for roles, default false)</li>
* <li>ldap.search.scope (optional, if not given 'ONELEVEL_SCOPE' will be used) possible values are: OBJECT_SCOPE, ONELEVEL_SCOPE, SUBTREE_SCOPE</li>
* <li>java.naming.factory.initial</li>
* <li>java.naming.security.authentication</li>
* <li>java.naming.security.protocol</li>
* <li>java.naming.provider.url</li>
* <li></li>
* </ul>
* </p>
*/
public class LDAPUserGroupCallbackImpl extends AbstractLDAPUserGroupInfo implements UserGroupCallback {
private static final String DEFAULT_PROPERTIES_NAME = "jbpm.usergroup.callback";
public static final String USER_CTX = "ldap.user.ctx";
public static final String ROLE_CTX = "ldap.role.ctx";
public static final String USER_ROLES_CTX = "ldap.user.roles.ctx";
public static final String USER_FILTER = "ldap.user.filter";
public static final String ROLE_FILTER = "ldap.role.filter";
public static final String USER_ROLES_FILTER = "ldap.user.roles.filter";
public static final String USER_ATTR_ID = "ldap.user.attr.id";
public static final String ROLE_ATTR_ID = "ldap.roles.attr.id";
public static final String IS_USER_ID_DN = "ldap.user.id.dn";
public static final String SEARCH_SCOPE = "ldap.search.scope";
private static final String[] REQUIRED_PROPERTIES = {USER_CTX, ROLE_CTX, USER_FILTER, ROLE_FILTER, USER_ROLES_FILTER};
private static final String DEFAULT_USER_ID_DN = "false";
/**
* Constructor needs to have at least one (unused) parameter in order to prevent CDI from automatic deployment.
* Configuration properties are loaded from a file specified by jbpm.usergroup.callback system property or
* classpath:/jbpm.usergroup.callback.properties file.
* @param activate ignored
*/
public LDAPUserGroupCallbackImpl(boolean activate) {
super(REQUIRED_PROPERTIES, DEFAULT_PROPERTIES_NAME);
}
/**
* @param config LDAP configuration properties
*/
public LDAPUserGroupCallbackImpl(Properties config) {
super(REQUIRED_PROPERTIES, config);
}
@Override
public boolean existsUser(String userId) {
String context = getConfigProperty(USER_CTX);
String filter = getConfigProperty(USER_FILTER);
String attributeId = getConfigProperty(USER_ATTR_ID, DEFAULT_USER_ATTR_ID);
return existsEntity(userId, context, filter, attributeId);
}
@Override
public boolean existsGroup(String groupId) {
String context = getConfigProperty(ROLE_CTX);
String filter = getConfigProperty(ROLE_FILTER);
String attributeId = getConfigProperty(ROLE_ATTR_ID, DEFAULT_ROLE_ATTR_ID);
return existsEntity(groupId, context, filter, attributeId);
}
private boolean existsEntity(String entityId, String context, String filter, String attributeId) {
String ldapEntityId = ldapSearcher.search(context, filter, entityId).getSingleAttributeResult(attributeId);
return entityId.equals(ldapEntityId);
}
@Override
public List<String> getGroupsForUser(String userId) {
String roleContext = getConfigProperty(USER_ROLES_CTX, getConfigProperty(ROLE_CTX));
String roleFilter = getConfigProperty(USER_ROLES_FILTER);
String roleAttributeId = getConfigProperty(ROLE_ATTR_ID, DEFAULT_ROLE_ATTR_ID);
String userDn = userId;
if (!isUserIdDn()) {
String userContext = getConfigProperty(USER_CTX);
String userFilter = getConfigProperty(USER_FILTER);
SearchResult searchResult = ldapSearcher.search(userContext, userFilter, userId).getSingleSearchResult();
userDn = searchResult.getNameInNamespace();
}
return ldapSearcher.search(roleContext, roleFilter, userDn).getAttributeResults(roleAttributeId);
}
private boolean isUserIdDn() {
return Boolean.parseBoolean(getConfigProperty(IS_USER_ID_DN, DEFAULT_USER_ID_DN));
}
}