PageRenderTime 115ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/jbpm-human-task/jbpm-human-task-core/src/main/java/org/jbpm/services/task/identity/LDAPUserInfoImpl.java

https://github.com/mariofusco/jbpm
Java | 390 lines | 300 code | 71 blank | 19 comment | 70 complexity | cbdf7e8c72b2e4982845f6731d6d4b61 MD5 | raw file
  1. /*
  2. * Copyright 2012 JBoss Inc
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.jbpm.services.task.identity;
  17. import java.util.ArrayList;
  18. import java.util.Iterator;
  19. import java.util.List;
  20. import java.util.Properties;
  21. import javax.naming.Context;
  22. import javax.naming.NamingEnumeration;
  23. import javax.naming.NamingException;
  24. import javax.naming.directory.Attribute;
  25. import javax.naming.directory.SearchControls;
  26. import javax.naming.directory.SearchResult;
  27. import javax.naming.ldap.InitialLdapContext;
  28. import org.kie.api.task.model.Group;
  29. import org.kie.api.task.model.OrganizationalEntity;
  30. import org.kie.api.task.model.User;
  31. import org.kie.internal.task.api.TaskModelProvider;
  32. import org.kie.internal.task.api.UserInfo;
  33. import org.kie.internal.task.api.model.InternalOrganizationalEntity;
  34. import org.slf4j.Logger;
  35. import org.slf4j.LoggerFactory;
  36. public class LDAPUserInfoImpl extends AbstractUserGroupInfo implements UserInfo {
  37. private static final Logger logger = LoggerFactory.getLogger(LDAPUserInfoImpl.class);
  38. protected static final String DEFAULT_PROPERTIES_NAME = "classpath:/jbpm.user.info.properties";
  39. public static final String BIND_USER = "ldap.bind.user";
  40. public static final String BIND_PWD = "ldap.bind.pwd";
  41. public static final String USER_CTX = "ldap.user.ctx";
  42. public static final String ROLE_CTX = "ldap.role.ctx";
  43. public static final String USER_FILTER = "ldap.user.filter";
  44. public static final String ROLE_FILTER = "ldap.role.filter";
  45. public static final String ROLE_MEMBERS_FILTER = "ldap.role.members.filter";
  46. public static final String EMAIL_ATTR_ID = "ldap.email.attr.id";
  47. public static final String NAME_ATTR_ID = "ldap.name.attr.id";
  48. public static final String LANG_ATTR_ID = "ldap.lang.attr.id";
  49. public static final String MEMBER_ATTR_ID = "ldap.member.attr.id";
  50. public static final String USER_ATTR_ID = "ldap.user.attr.id";
  51. public static final String ROLE_ATTR_ID = "ldap.role.attr.id";
  52. public static final String IS_ENTITY_ID_DN = "ldap.entity.id.dn";
  53. public static final String SEARCH_SCOPE = "ldap.search.scope";
  54. protected static final String[] requiredProperties = {USER_CTX, ROLE_CTX, USER_FILTER, ROLE_FILTER};
  55. private Properties config;
  56. //no no-arg constructor to prevent cdi from auto deploy
  57. public LDAPUserInfoImpl(boolean activate) {
  58. String propertiesLocation = System.getProperty("jbpm.user.info.properties");
  59. config = readProperties(propertiesLocation, DEFAULT_PROPERTIES_NAME);
  60. validate();
  61. }
  62. public LDAPUserInfoImpl(Properties config) {
  63. this.config = config;
  64. validate();
  65. }
  66. public String getDisplayName(OrganizationalEntity entity) {
  67. String context = null;
  68. String filter = null;
  69. String attrId = null;
  70. if (entity instanceof User) {
  71. context = this.config.getProperty(USER_CTX);
  72. filter = this.config.getProperty(USER_FILTER);
  73. attrId = this.config.getProperty(NAME_ATTR_ID, "displayName");
  74. } else if (entity instanceof Group) {
  75. context = this.config.getProperty(ROLE_CTX);
  76. filter = this.config.getProperty(ROLE_FILTER);
  77. attrId = this.config.getProperty(NAME_ATTR_ID, "displayName");
  78. } else {
  79. throw new IllegalArgumentException("Unknown organizational entity " + entity);
  80. }
  81. String result = searchLdap(context, filter, attrId, entity);
  82. return result;
  83. }
  84. public Iterator<OrganizationalEntity> getMembersForGroup(Group group) {
  85. InitialLdapContext ctx = null;
  86. List<OrganizationalEntity> memebers = new ArrayList<OrganizationalEntity>();
  87. try {
  88. ctx = buildInitialLdapContext();
  89. String roleContext = this.config.getProperty(ROLE_CTX);
  90. String roleFilter = this.config.getProperty(ROLE_MEMBERS_FILTER, this.config.getProperty(ROLE_FILTER));
  91. String roleAttrId = this.config.getProperty(MEMBER_ATTR_ID, "member");
  92. roleFilter = roleFilter.replaceAll("\\{0\\}", group.getId());
  93. SearchControls constraints = new SearchControls();
  94. String searchScope = this.config.getProperty(SEARCH_SCOPE);
  95. if (searchScope != null) {
  96. constraints.setSearchScope(parseSearchScope(searchScope));
  97. }
  98. NamingEnumeration<SearchResult> result = ctx.search(roleContext, roleFilter, constraints);
  99. while (result.hasMore()) {
  100. SearchResult sr = result.next();
  101. Attribute member = sr.getAttributes().get(roleAttrId);
  102. for (int i = 0; i < member.size(); i++) {
  103. User user = TaskModelProvider.getFactory().newUser();
  104. ((InternalOrganizationalEntity) user).setId(member.get(i).toString());
  105. memebers.add(user);
  106. }
  107. }
  108. result.close();
  109. } catch (Exception e) {
  110. e.printStackTrace();
  111. }finally {
  112. if (ctx != null) {
  113. try {
  114. ctx.close();
  115. } catch (NamingException e) {
  116. e.printStackTrace();
  117. }
  118. }
  119. }
  120. return memebers.iterator();
  121. }
  122. public boolean hasEmail(Group group) {
  123. InitialLdapContext ctx = null;
  124. boolean exists = false;
  125. try {
  126. ctx = buildInitialLdapContext();
  127. String roleContext = this.config.getProperty(ROLE_CTX);
  128. String roleFilter = this.config.getProperty(ROLE_FILTER);
  129. String roleAttrId = this.config.getProperty(EMAIL_ATTR_ID, "mail");
  130. roleFilter = roleFilter.replaceAll("\\{0\\}", group.getId());
  131. SearchControls constraints = new SearchControls();
  132. String searchScope = this.config.getProperty(SEARCH_SCOPE);
  133. if (searchScope != null) {
  134. constraints.setSearchScope(parseSearchScope(searchScope));
  135. }
  136. NamingEnumeration<SearchResult> result = ctx.search(roleContext, roleFilter, constraints);
  137. if (result.hasMore()) {
  138. SearchResult sr = result.next();
  139. Attribute ldapGroupEmail = sr.getAttributes().get(roleAttrId);
  140. if (ldapGroupEmail != null && ldapGroupEmail.get() != null) {
  141. exists = true;
  142. }
  143. }
  144. result.close();
  145. } catch (Exception e) {
  146. e.printStackTrace();
  147. }finally {
  148. if (ctx != null) {
  149. try {
  150. ctx.close();
  151. } catch (NamingException e) {
  152. e.printStackTrace();
  153. }
  154. }
  155. }
  156. return exists;
  157. }
  158. public String getEmailForEntity(OrganizationalEntity entity) {
  159. String context = null;
  160. String filter = null;
  161. String attrId = null;
  162. if (entity instanceof User) {
  163. context = this.config.getProperty(USER_CTX);
  164. filter = this.config.getProperty(USER_FILTER);
  165. attrId = this.config.getProperty(EMAIL_ATTR_ID, "mail");
  166. } else if (entity instanceof Group) {
  167. context = this.config.getProperty(ROLE_CTX);
  168. filter = this.config.getProperty(ROLE_FILTER);
  169. attrId = this.config.getProperty(EMAIL_ATTR_ID, "mail");
  170. } else {
  171. throw new IllegalArgumentException("Unknown organizational entity " + entity);
  172. }
  173. String result = searchLdap(context, filter, attrId, entity);
  174. return result;
  175. }
  176. public String getLanguageForEntity(OrganizationalEntity entity) {
  177. String context = null;
  178. String filter = null;
  179. String attrId = null;
  180. if (entity instanceof User) {
  181. context = this.config.getProperty(USER_CTX);
  182. filter = this.config.getProperty(USER_FILTER);
  183. attrId = this.config.getProperty(LANG_ATTR_ID, "locale");
  184. } else if (entity instanceof Group) {
  185. context = this.config.getProperty(ROLE_CTX);
  186. filter = this.config.getProperty(ROLE_FILTER);
  187. attrId = this.config.getProperty(LANG_ATTR_ID, "locale");
  188. } else {
  189. throw new IllegalArgumentException("Unknown organizational entity " + entity);
  190. }
  191. String result = searchLdap(context, filter, attrId, entity);
  192. if (result == null) {
  193. // defaults to en-UK
  194. result = "en-UK";
  195. }
  196. return result;
  197. }
  198. protected void validate() {
  199. if (this.config == null) {
  200. throw new IllegalArgumentException("No configuration found for LDAPUserInfoImpl, aborting...");
  201. }
  202. StringBuffer missingRequiredProps = new StringBuffer();
  203. for (String requiredProp : requiredProperties) {
  204. if (!this.config.containsKey(requiredProp)) {
  205. if (missingRequiredProps.length() > 0) {
  206. missingRequiredProps.append(", ");
  207. }
  208. missingRequiredProps.append(requiredProp);
  209. }
  210. }
  211. if (missingRequiredProps.length() > 0) {
  212. logger.debug("Validation failed due to missing required properties: {}", missingRequiredProps.toString());
  213. throw new IllegalArgumentException("Missing required properties to configure LDAPUserInfoImpl: " + missingRequiredProps.toString());
  214. }
  215. }
  216. protected InitialLdapContext buildInitialLdapContext() throws NamingException {
  217. // Set defaults for key values if they are missing
  218. String factoryName = this.config.getProperty(Context.INITIAL_CONTEXT_FACTORY);
  219. if (factoryName == null) {
  220. factoryName = "com.sun.jndi.ldap.LdapCtxFactory";
  221. this.config.setProperty(Context.INITIAL_CONTEXT_FACTORY, factoryName);
  222. }
  223. String authType = this.config.getProperty(Context.SECURITY_AUTHENTICATION);
  224. if (authType == null) {
  225. this.config.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
  226. }
  227. String protocol = this.config.getProperty(Context.SECURITY_PROTOCOL);
  228. String providerURL = (String) this.config.getProperty(Context.PROVIDER_URL);
  229. if (providerURL == null) {
  230. providerURL = "ldap://localhost:"+ ((protocol != null && protocol.equals("ssl")) ? "636" : "389");
  231. this.config.setProperty(Context.PROVIDER_URL, providerURL);
  232. }
  233. String binduser = this.config.getProperty(BIND_USER);
  234. if (binduser != null) {
  235. this.config.setProperty(Context.SECURITY_PRINCIPAL, binduser);
  236. }
  237. String bindpwd = this.config.getProperty(BIND_PWD);
  238. if (binduser != null) {
  239. this.config.setProperty(Context.SECURITY_CREDENTIALS, bindpwd);
  240. }
  241. if (logger.isDebugEnabled()) {
  242. logger.debug("Using following InitialLdapContext properties:");
  243. logger.debug("Factory {}", this.config.getProperty(Context.INITIAL_CONTEXT_FACTORY));
  244. logger.debug("Authentication {}", this.config.getProperty(Context.SECURITY_AUTHENTICATION));
  245. logger.debug("Protocol {}", this.config.getProperty(Context.SECURITY_PROTOCOL));
  246. logger.debug("Provider URL {}", this.config.getProperty(Context.PROVIDER_URL));
  247. }
  248. return new InitialLdapContext(this.config, null);
  249. }
  250. protected String searchLdap(String context, String filter, String attrId, OrganizationalEntity entity) {
  251. InitialLdapContext ctx = null;
  252. String result = null;
  253. try {
  254. ctx = buildInitialLdapContext();
  255. String entityId = entity.getId();
  256. if (Boolean.parseBoolean(this.config.getProperty(IS_ENTITY_ID_DN, "false"))) {
  257. entityId = extractUserId(entityId, entity);
  258. }
  259. filter = filter.replaceAll("\\{0\\}",entityId);
  260. SearchControls constraints = new SearchControls();
  261. String searchScope = this.config.getProperty(SEARCH_SCOPE);
  262. if (searchScope != null) {
  263. constraints.setSearchScope(parseSearchScope(searchScope));
  264. }
  265. NamingEnumeration<SearchResult> ldapResult = ctx.search(context, filter, constraints);
  266. if (ldapResult.hasMore()) {
  267. SearchResult sr = ldapResult.next();
  268. Attribute entry = sr.getAttributes().get(attrId);
  269. if (entry != null) {
  270. result = (String) entry.get();
  271. }
  272. }
  273. ldapResult.close();
  274. } catch (Exception e) {
  275. e.printStackTrace();
  276. }finally {
  277. if (ctx != null) {
  278. try {
  279. ctx.close();
  280. } catch (NamingException e) {
  281. e.printStackTrace();
  282. }
  283. }
  284. }
  285. return result;
  286. }
  287. protected String extractUserId(String userDN, OrganizationalEntity entity) {
  288. String[] attributes = userDN.split(",");
  289. if (attributes.length == 1) {
  290. return userDN;
  291. }
  292. String entityAttrId = null;
  293. if (entity instanceof User) {
  294. entityAttrId = this.config.getProperty(USER_ATTR_ID, "uid");
  295. } else if (entity instanceof Group) {
  296. entityAttrId = this.config.getProperty(ROLE_ATTR_ID, "cn");
  297. }
  298. if (attributes != null) {
  299. for (String attribute : attributes) {
  300. String[] keyValue = attribute.split("=");
  301. if (keyValue[0].equalsIgnoreCase(entityAttrId)) {
  302. return keyValue[1];
  303. }
  304. }
  305. }
  306. return null;
  307. }
  308. protected int parseSearchScope(String searchScope) {
  309. logger.debug("Search scope: {}", searchScope);
  310. if ("OBJECT_SCOPE".equals(searchScope))
  311. return 0;
  312. else if ("ONELEVEL_SCOPE".equals(searchScope))
  313. return 1;
  314. else if ("SUBTREE_SCOPE".equals(searchScope))
  315. return 2;
  316. // Default set to ONELEVEL_SCOPE
  317. return 1;
  318. }
  319. }