1 package com.liferay.portal.security.auth;
3 import java.util.ArrayList;
5 import java.util.Properties;
7 import javax.naming.Binding;
8 import javax.naming.Context;
9 import javax.naming.NamingEnumeration;
10 import javax.naming.NamingException;
11 import javax.naming.directory.Attribute;
12 import javax.naming.directory.Attributes;
13 import javax.naming.directory.SearchControls;
14 import javax.naming.directory.SearchResult;
15 import javax.naming.ldap.InitialLdapContext;
16 import javax.naming.ldap.LdapContext;
17 import javax.servlet.http.HttpServletRequest;
18 import javax.servlet.http.HttpServletResponse;
20 import com.liferay.portal.NoSuchUserException;
21 import com.liferay.portal.kernel.dao.orm.QueryUtil;
22 import com.liferay.portal.kernel.exception.PortalException;
23 import com.liferay.portal.kernel.exception.SystemException;
24 import com.liferay.portal.kernel.log.Log;
25 import com.liferay.portal.kernel.log.LogFactoryUtil;
26 import com.liferay.portal.kernel.util.OrderByComparator;
27 import com.liferay.portal.kernel.util.PropsKeys;
28 import com.liferay.portal.kernel.util.StringPool;
29 import com.liferay.portal.kernel.util.StringUtil;
30 import com.liferay.portal.kernel.util.Validator;
31 import com.liferay.portal.kernel.workflow.WorkflowConstants;
32 import com.liferay.portal.model.User;
33 import com.liferay.portal.security.ldap.LDAPLocalServiceUtil;
34 import com.liferay.portal.security.ldap.PortalLDAPUtil;
35 import com.liferay.portal.service.ExtUserLocalServiceUtil;
36 import com.liferay.portal.service.RoleLocalServiceUtil;
37 import com.liferay.portal.service.UserLocalServiceUtil;
38 import com.liferay.portal.service.persistence.UserFinderUtil;
39 import com.liferay.portal.util.PortalUtil;
40 import com.liferay.portal.util.PrefsPropsUtil;
41 import com.pentila.entSavoie.ENTRolesConstants;
42 import com.pentila.entSavoie.ENTRolesUtil;
43 import com.pentila.entSavoie.synchroLdap.impl.SynchronizationManager;
44 import com.pentila.entSavoie.utils.ENTMainUtilsLocalServiceUtil;
45 import com.liferay.portal.model.Role;
48 public class ShibbolethAutoLogin implements AutoLogin {
50 private static Log _log = LogFactoryUtil.getLog(ShibbolethAutoLogin.class);
52 public static LdapContext ctx = null;
54 public String[] login(HttpServletRequest req, HttpServletResponse res)
55 throws AutoLoginException {
56 String[] credentials = new String[3];
58 String displayName = null;
59 String frEduVecteur = null;
60 String entPersonJointure = null;
64 companyId = PortalUtil.getCompany(req).getCompanyId();
66 mail = req.getHeader("mail");
67 displayName = req.getHeader("displayName");
68 frEduVecteur = req.getHeader("FrEduVecteur");
69 entPersonJointure = req.getHeader("ENTPersonJointure");
71 // Do not remove this syso, this information we want all the time in the logs
72 if ((Validator.isNotNull(frEduVecteur) && !frEduVecteur.equals("")) || (Validator.isNotNull(mail) && !mail.equals(""))) {
73 _log.info("Shibboleth login. Mail:" + mail + " displayName:" + displayName +
74 " frEduVecteur:" + frEduVecteur + " entPersonJointure:" + entPersonJointure);
77 // 1. Authentication by identification vector
79 if (Validator.isNotNull(frEduVecteur) && !frEduVecteur.equals("")) {
80 frEduVecteur = new String( frEduVecteur.getBytes("ISO-8859-1"), "UTF-8");
82 _log.info("Shibboleth FrEduVecteur: " + frEduVecteur);
84 // Loop over vectors (separated by ';')
85 String[] vecteurs = frEduVecteur.split(";");
86 for (String vecteur: vecteurs) {
88 // Vector should contain 5 elements separated by '|' character
89 String[] vSplited = vecteur.split("\\|");
90 if (vSplited.length == 5) {
93 if (vSplited[0].equals("4")) {
95 // Vector format : 4 ||| ENTEleveStructRattachId
96 String entEleveStructRattachId = vSplited[3];
98 // Get student in LDAP
99 User user = getUserByENTEleveStructRattachId(companyId, entEleveStructRattachId);
101 credentials[0] = String.valueOf(user.getUserId());
102 credentials[1] = user.getPassword();
103 credentials[2] = Boolean.TRUE.toString();
104 _log.info("Shibboleth eleve "+user.getFullName()+" authenticated.");
110 else if(vSplited[0].equals("2")) {
112 // Vector format : 2 | Name | givenName | ENTEleveStructRattachId | ENTStructureUAI
113 // Example: 2|CERIBAT|Michel|1146907|0261032F
114 String firstName = vSplited[2];
115 String lastName = vSplited[1];
116 String entEleveStructRattachId = vSplited[3];
117 String entStructUAI = vSplited[4];
119 User user = getUserByENTEleveStructRattachId(companyId, entEleveStructRattachId, firstName, lastName, entStructUAI);
121 credentials[0] = String.valueOf(user.getUserId());
122 credentials[1] = user.getPassword();
123 credentials[2] = Boolean.TRUE.toString();
124 _log.info("Shibboleth parent "+user.getFullName()+" authenticated.");
129 _log.error("Incorrect vector length : "+vSplited.length);
134 // 2. Authentication by email
135 if (Validator.isNotNull(mail) && !mail.equals("")) {
137 _log.info("Got mail for shibboleth authentification: " + mail);
138 credentials = new String[3];
141 // Same user may have its academic adress used for both his teacher account and his parent account
142 // Here we need to authorize only non-Nat1 and Nat2 users
143 List<User> usersList = null;
145 usersList = ExtUserLocalServiceUtil.findUsersByEmail(mail);
146 } catch (Exception e) {
147 _log.error("Error while searching for users with email = "+mail, e);
149 if (usersList == null || usersList.size() == 0) {
150 _log.error("No user found with mail "+mail);
152 } else if (usersList.size() == 1) {
153 user = usersList.get(0);
155 // 2 or more candidates
156 // Return only the teacher
158 Role parentRole = RoleLocalServiceUtil.getRole(companyId, ENTRolesConstants.NATIONAL_2);
159 Role studentRole = RoleLocalServiceUtil.getRole(companyId, ENTRolesConstants.NATIONAL_1);
161 for (User candidate : usersList) {
162 if (RoleLocalServiceUtil.hasUserRole(candidate.getUserId(), studentRole.getRoleId()) || RoleLocalServiceUtil.hasUserRole(candidate.getUserId(), parentRole.getRoleId())) {
163 _log.error("Found a student or parent with an academic email address => skipping");
166 _log.error("Found a candidate with mail="+mail+", id="+candidate.getUserId());
170 } catch (Exception e) {
171 _log.error("Error when parsing candidates with mail="+mail, e);
179 _log.info("Identified agent "+user.getFullName()+"("+user.getUserId()+") by its email "+mail);
180 credentials[0] = String.valueOf(user.getUserId());
181 credentials[1] = user.getPassword();
182 credentials[2] = Boolean.TRUE.toString();
186 // 3. Authentification by ENTPersonJointure
187 if (Validator.isNotNull(entPersonJointure) && !entPersonJointure.equals("")) {
188 entPersonJointure = new String( entPersonJointure.getBytes("ISO-8859-1"), "UTF-8");
191 user = LDAPLocalServiceUtil.getUser(companyId, "ENTPersonJointure", entPersonJointure);
197 credentials[0] = String.valueOf(user.getUserId());
198 credentials[1] = user.getPassword();
199 credentials[2] = Boolean.TRUE.toString();
203 // 4. Authentification by displayName
204 if (Validator.isNotNull(displayName) && !displayName.equals("")) {
205 // Authentification via CAS CO3
206 credentials = new String[3];
211 user = UserLocalServiceUtil.getUserByScreenName(companyId, displayName);
213 catch (NoSuchUserException exc) {
215 _log.error("No Such User by internal LDAP: ShibbolethAutoLogin.login() ");
216 user = addUser(companyId, displayName);
217 } catch (Exception e) {
222 credentials[0] = String.valueOf(user.getUserId());
223 credentials[1] = user.getPassword();
224 credentials[2] = Boolean.TRUE.toString();
231 throw new AutoLoginException(e);
236 * Get a user with entEleveStructRattachId, firstName, lastName and entStructUAI
238 public static User getUserByENTEleveStructRattachId(long companyId, String entEleveStructRattachId, String firstName, String lastName, String entStructUAI) throws Exception {
240 _log.debug("Shibboleth : fetch user with firstName="+firstName+", lastName="+lastName+", entEleveStructRattachId="+entEleveStructRattachId+", entStructUAI="+entStructUAI);
245 Attributes attrs = getUserAttributesByENTEleveStructRattachId(companyId, entEleveStructRattachId);
248 _log.error("Shibboleth : no child found");
252 // We have a child in LDAP
254 // We check parental authority which regroups parents and other figures (tuteurs) instead of only checking ENTEleveParents
255 Attribute authoritesParentalesDN = attrs.get("ENTEleveAutoriteParentale");
256 if (authoritesParentalesDN != null) {
257 ctx = getContext(companyId);
258 NamingEnumeration enumeration = authoritesParentalesDN.getAll();
261 while (enumeration.hasMoreElements()) {
262 String parentDN = (String) enumeration.nextElement();
263 _log.debug("Shibboleth : parent is " + parentDN);
265 Attributes parentAttrs = ctx.getAttributes(parentDN, null);
266 String firstNameParent = parentAttrs.get("givenName").get().toString();
267 String lastNameParent = parentAttrs.get("sn").get().toString();
269 _log.debug("Shibboleth : parent found in LDAP : " + firstNameParent + " " + lastNameParent);
271 if (firstNameParent.toLowerCase().equals(firstName.toLowerCase()) &&
272 lastNameParent.toLowerCase().equals(lastName.toLowerCase())) {
273 _log.debug("Shibboleth : parent match name OK");
275 // Check on rattached etab attach
276 String ENTPersonStructRattach = parentAttrs.get("ENTPersonStructRattach").get().toString();
277 Attributes etabAttrs = ctx.getAttributes(ENTPersonStructRattach, null);
278 String entStructUAILDAP = etabAttrs.get("ENTStructureUAI").get().toString();
280 _log.debug("Shibboleth : parent entStructUAI is " + entStructUAILDAP);
282 if (entStructUAILDAP.toLowerCase().equals(entStructUAI.toLowerCase())) {
284 _log.debug("Shibboleth : parent match entStructUAI OK");
285 String login = parentAttrs.get("ENTPersonLogin").get().toString();
287 user = UserLocalServiceUtil.getUserByScreenName(companyId, login);
289 catch (NoSuchUserException exc) {
290 _log.error("No Such User parent in SQL DB with login: " + login);
293 _log.debug("Shibboleth : parent login is " + login);
299 } catch (Exception e1) {
312 public static User getUserByENTEleveStructRattachId(long companyId, String entEleveStructRattachId) throws NamingException, SystemException, PortalException {
314 Attributes attrs = getUserAttributesByENTEleveStructRattachId(companyId, entEleveStructRattachId);
320 String epl = attrs.get("ENTPersonLogin").get().toString();
321 _log.debug("Shibboleth get attrs ENTPersonLogin: " + epl);
326 user = UserLocalServiceUtil.getUserByScreenName(companyId, epl);
328 catch (NoSuchUserException exc) {
329 _log.error("No Such User in SQL DB with login: " + epl);
335 public static Attributes getUserAttributesByENTEleveStructRattachId(long companyId, String entEleveStructRattachId) throws NamingException, SystemException {
337 String baseDN = PrefsPropsUtil.getString(companyId,
338 PropsKeys.LDAP_BASE_DN);
340 SearchControls cons = new SearchControls(
341 SearchControls.SUBTREE_SCOPE,
348 NamingEnumeration<SearchResult> l;
351 ctx = getContext(companyId);
352 l = ctx.search(baseDN,
353 "(&(objectClass=ENTPerson)(ENTValidAccount=-1)(ENTEleveStructRattachId=" + entEleveStructRattachId + "))",
355 while (l.hasMoreElements()) {
356 SearchResult sr = l.next();
357 Attributes attrs = sr.getAttributes();
360 String epl = attrs.get("ENTPersonLogin").get().toString();
366 } catch (NamingException e) {
369 } catch (Exception e1) {
381 public static LdapContext getContext(long companyId) throws Exception {
383 String baseProviderURL = PrefsPropsUtil.getString(companyId,
384 PropsKeys.LDAP_BASE_PROVIDER_URL);
385 String pricipal = PrefsPropsUtil.getString(companyId,
386 PropsKeys.LDAP_SECURITY_PRINCIPAL);
387 String credentials = PrefsPropsUtil.getString(companyId,
388 PropsKeys.LDAP_SECURITY_CREDENTIALS);
390 return getContext(companyId, baseProviderURL, pricipal, credentials);
393 public static LdapContext getContext(long companyId, String providerURL,
394 String pricipal, String credentials) throws Exception {
400 Properties env = new Properties();
402 env.put(Context.INITIAL_CONTEXT_FACTORY, PrefsPropsUtil.getString(
403 companyId, PropsKeys.LDAP_FACTORY_INITIAL));
404 env.put(Context.PROVIDER_URL, providerURL);
405 env.put(Context.SECURITY_PRINCIPAL, pricipal);
406 env.put(Context.SECURITY_CREDENTIALS, credentials);
408 env.put("com.sun.jndi.ldap.connect.pool", "true");
409 env.put("com.sun.jndi.ldap.connect.pool.maxsize", "50");
410 env.put("com.sun.jndi.ldap.connect.pool.timeout", "100000");
413 ctx = new InitialLdapContext(env, null);
414 } catch (Exception e) {
424 protected User addUserByMail(long companyId, String mail)
425 throws SystemException {
427 String baseDN = PrefsPropsUtil.getString(
428 companyId, PropsKeys.LDAP_BASE_DN);
430 String filter = ENTMainUtilsLocalServiceUtil.getAuthMailFilter(companyId);
432 if (_log.isDebugEnabled()) {
433 _log.debug("Search filter before transformation " + filter);
436 filter = StringUtil.replace(
439 "@company_id@", "@email_address@", "@screen_name@"
442 String.valueOf(companyId), StringPool.BLANK, mail
445 if (_log.isDebugEnabled()) {
446 _log.debug("Search filter after transformation " + filter);
449 SearchControls cons = new SearchControls(
450 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
452 NamingEnumeration<SearchResult> enu = PortalLDAPUtil.getContext(companyId).search(
453 baseDN, filter, cons);
455 if (enu.hasMoreElements()) {
456 if (_log.isDebugEnabled()) {
457 _log.debug("Search filter returned at least one result");
460 Binding binding = enu.nextElement();
462 Attributes attrs = PortalLDAPUtil.getUserAttributes(
464 PortalLDAPUtil.getNameInNamespace(companyId, binding));
466 return SynchronizationManager.synchronizeUser(companyId, attrs, StringPool.BLANK, false);
469 throw new NoSuchUserException(
470 "User " + mail + " was not found in the LDAP server");
473 catch (Exception e) {
474 _log.error("Problem accessing LDAP server ", e);
476 throw new SystemException(
477 "Problem accessign LDAP server " + e.getMessage());
482 protected User addUser(long companyId, String screenName)
483 throws SystemException {
485 String baseDN = PrefsPropsUtil.getString(
486 companyId, PropsKeys.LDAP_BASE_DN);
489 String filter = PrefsPropsUtil.getString(
490 companyId, PropsKeys.LDAP_AUTH_SEARCH_FILTER);
492 if (_log.isDebugEnabled()) {
493 _log.debug("Search filter before transformation " + filter);
496 filter = StringUtil.replace(
499 "@company_id@", "@email_address@", "@screen_name@"
502 String.valueOf(companyId), StringPool.BLANK, screenName
505 if (_log.isDebugEnabled()) {
506 _log.debug("Search filter after transformation " + filter);
509 SearchControls cons = new SearchControls(
510 SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
512 NamingEnumeration<SearchResult> enu = PortalLDAPUtil.getContext(companyId).search(
513 baseDN, filter, cons);
515 if (enu.hasMoreElements()) {
516 if (_log.isDebugEnabled()) {
517 _log.debug("Search filter returned at least one result");
520 Binding binding = enu.nextElement();
522 Attributes attrs = PortalLDAPUtil.getUserAttributes(companyId, PortalLDAPUtil.getNameInNamespace(companyId, binding));
524 return SynchronizationManager.synchronizeUser(companyId, attrs, StringPool.BLANK, false);
527 throw new NoSuchUserException(
528 "User " + screenName + " was not found in the LDAP server");
531 catch (Exception e) {
532 _log.error("Problem accessing LDAP server ", e);
534 throw new SystemException(
535 "Problem accessign LDAP server " + e.getMessage());