1 package com.liferay.portal.security.internalSSO;
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.InputStreamReader;
7 import java.text.SimpleDateFormat;
10 import java.util.UUID;
12 import javax.servlet.http.HttpServletRequest;
14 import com.liferay.portal.kernel.exception.SystemException;
15 import com.liferay.portal.kernel.log.Log;
16 import com.liferay.portal.kernel.log.LogFactoryUtil;
17 import com.liferay.portal.model.Organization;
18 import com.liferay.portal.model.User;
19 import com.liferay.portal.service.UserLocalServiceUtil;
20 import com.pentila.entSavoie.casManager.model.AttributSSO;
21 import com.pentila.entSavoie.casManager.model.ServiceSSO;
22 import com.pentila.entSavoie.casManager.service.AttributSSOLocalServiceUtil;
23 import com.pentila.entSavoie.casManager.service.ServiceSSOLocalServiceUtil;
24 import com.pentila.entSavoie.communityInfos.service.OrganizationMappingLocalServiceUtil;
25 import com.pentila.entSavoie.directory.OrganizationFinderServiceUtil;
26 import com.pentila.entSavoie.gestionServiceURL.NoSuchServiceURLException;
27 import com.pentila.entSavoie.userManagement.model.LDAPMapping;
28 import com.pentila.entSavoie.userManagement.service.LDAPMappingLocalServiceUtil;
29 import com.pentila.entSavoie.userProperties.model.UserInternalSSO;
30 import com.pentila.entSavoie.userProperties.service.UserInternalSSOLocalServiceUtil;
31 import com.pentila.entSavoie.utils.ENTMainUtilsLocalServiceUtil;
32 import com.pentila.entSavoie.utils.LDAPUtilsLocalServiceUtil;
34 public class InternalSSO {
36 static SimpleDateFormat sortDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.000'Z'");
38 private static Log logger = LogFactoryUtil.getLog(InternalSSO.class);
40 public static String getTicket(User user, String service) {
45 if (service.isEmpty()) {
46 logger.error("No service found in ticket request");
51 ServiceSSO monService = ServiceSSOLocalServiceUtil.getFirstServiceMatched(service);
53 if(monService != null){
54 // Generate a ticket for the user and store it in a cache!
55 String ssoIdK = UUID.randomUUID().toString();
58 String internalSSOUserKey="ST-ISC-"+ssoIdK;
59 // we store the ticket for a valid period of 10sec
60 // the value stored is the service concact with the userid
61 UserInternalSSOLocalServiceUtil.addUserInternalSSO(internalSSOUserKey, service + user.getUserId());
62 //ENTCacheUtils.storeObjectIntoCache(internalSSOUserKey,service + user.getUserId(),10000);
63 logger.info("ticket " + internalSSOUserKey + " stored");
64 return internalSSOUserKey;
69 } catch (Exception e) {
70 logger.error("error in getTicket acquire",e);
75 private static String getUserAttr(User user, AttributSSO attr, String returnType){
78 String attrSamlName = attr.getSamlName();
79 String attrSamlValue = "";
81 int attrName = Integer.valueOf(attr.getSourceAttrName());
82 boolean isCO3OrCAIRNS = ENTMainUtilsLocalServiceUtil.isDlStoreCO3(user.getCompanyId());
85 LDAPMapping ldapM = LDAPMappingLocalServiceUtil.fetchLDAPMapping(user.getUserId());
90 attrSamlValue = ldapM.getUID();
94 attrSamlValue = user.getLastName();
96 //prénom --> givenName
98 attrSamlValue = user.getFirstName();
100 //login --> ENTPersonLogin
102 attrSamlValue = user.getScreenName();
104 //date de naissance --> ENTPersonDateNaissance
106 attrSamlValue = LDAPUtilsLocalServiceUtil.getLdapAttribute(user, "ENTPersonDateNaissance");
108 //Classes --> ENTEleveClasses
110 attrSamlValue = LDAPUtilsLocalServiceUtil.getLdapAttribute(user, "ENTEleveClasses");
112 //Profil --> ENTPersonProfils
114 attrSamlValue = LDAPUtilsLocalServiceUtil.getLdapAttribute(user, "ENTPersonProfils");
116 //Niveau de formation --> ENTEleveNivFormation
118 attrSamlValue = LDAPUtilsLocalServiceUtil.getLdapAttribute(user, "ENTEleveNivFormation");
120 // ENT jointure --> ENTPersonJointure (equals UID on CO3 and CAIRNS but not on HN)
122 if (!isCO3OrCAIRNS) {
123 attrSamlValue = ldapM.getUID().substring(0, ldapM.getUID().length()-3);
126 attrSamlValue = ldapM.getUID();
129 // ENT jointure Prefixe UT--> ENTPersonJointure
131 if (!isCO3OrCAIRNS) {
132 attrSamlValue = "UT" + ldapM.getUID().substring(0, ldapM.getUID().length()-3);
135 attrSamlValue = "UT" + ldapM.getUID();
138 //Code postal --> ENTPersonCodePostal
140 attrSamlValue = LDAPUtilsLocalServiceUtil.getLdapAttribute(user, "ENTPersonCodePostal");
144 attrSamlValue = user.getEmailAddress();
146 //person role --> ENTPersonFonctions
148 attrSamlValue = LDAPUtilsLocalServiceUtil.getLdapAttribute(user, "ENTPersonFonctions");
153 }catch (Exception e) {
159 if (returnType.equals("classic")) {
160 result = String.format(classicAttributeTemplate, attrSamlName, attrSamlValue, attrSamlName);
163 result = String.format(samlAttributeTemplate, attrSamlName, attrSamlValue);
169 private static String getEtabAttr(User user, AttributSSO attr, String returnType){
170 String attrSamlName = attr.getSamlName();
171 String attrSamlValue = "";
173 int attrName = Integer.valueOf(attr.getSourceAttrName());
175 Organization userOrg = OrganizationFinderServiceUtil.getEtabRatachement(user);
179 attrSamlValue = OrganizationMappingLocalServiceUtil.getOrganizationStrutUAI(userOrg);
185 }catch (Exception e) {
190 if (returnType.equals("classic")) {
191 result = String.format(classicAttributeTemplate, attrSamlName, attrSamlValue, attrSamlName);
194 result = String.format(samlAttributeTemplate, attrSamlName, attrSamlValue);
201 public static String samlValidateTicket(String target, HttpServletRequest request) throws IOException, SystemException {
202 logger.info("Validate ticket in SAML form for: " + target);
204 // inside service(ServletRequest req, ServletResponse res)
205 // of a class that implements Servlet
207 // inside doPost(HttpServletRequest req, HttpServletResponse resp)
208 // of a class that implements HTTPServlet
209 String issueInstant = sortDateFormat.format(new Date());
210 String responseID = "_" + UUID.randomUUID().toString().replace("-", "");
212 StringBuilder stringBuilder = new StringBuilder();
213 BufferedReader bufferedReader = null;
215 InputStream inputStream = request.getInputStream();
216 if (inputStream != null) {
217 bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
218 char[] charBuffer = new char[128];
220 while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
221 stringBuilder.append(charBuffer, 0, bytesRead);
224 stringBuilder.append("");
226 } catch (IOException ex) {
229 if (bufferedReader != null) {
231 bufferedReader.close();
232 } catch (IOException ex) {
237 // on obtient le body
238 String body = stringBuilder.toString();
239 //System.out.println(body);
240 if (body.isEmpty()) {
241 logger.error("Internal SSO : No body found in request");
242 return String.format(samlValidationFailureTemplate, issueInstant, responseID, "No body found in request");
245 int indexStart = body.indexOf("<samlp:AssertionArtifact>");
246 int indexEnd = body.indexOf("</samlp:AssertionArtifact>");
248 if (indexStart==-1 || indexEnd==-1) {
249 logger.error("Internal SSO : no ticket found");
252 String ticket = body.substring(indexStart+25, indexEnd);
253 ticket = ticket.replace("\n", "");
254 ticket = ticket.trim();
256 logger.debug("ticket found is: " + ticket);
260 if (ticket.isEmpty()) {
261 logger.error("Internal SSO : No ticket found in request");
262 return String.format(samlValidationFailureTemplate, issueInstant, responseID, "No ticket found in request");
265 if (target.isEmpty()) {
266 logger.error("Internal SSO : No target found in request");
267 return String.format(samlValidationFailureTemplate, issueInstant, responseID, "No target found in request");
271 // Get user from cache SSO
272 //String ssoValue = (String) ENTCacheUtils.getObjectFromCache(ticket);
274 UserInternalSSO uISSO = null;
276 uISSO = UserInternalSSOLocalServiceUtil.getUserInternalSSOBySSOKey(ticket);
277 } catch (Exception e2) {
278 logger.error("Internal SSO : Ticket " + ticket + " not recognized");
279 return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Ticket " + ticket + " not recognized");
283 // ticket non valid ou incorrect
284 logger.error("Internal SSO : Ticket " + ticket + " not recognized");
285 return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Ticket " + ticket + " not recognized");
289 String ssoValue = uISSO.getSsoValue();
290 Date ticketTime = uISSO.getTimeMarker();
291 Date now = new Date();
293 UserInternalSSOLocalServiceUtil.deleteUserInternalSSO(uISSO);
294 //ENTCacheUtils.removeObjectFromCache(ticket);
295 long timeRef = now.getTime()-ticketTime.getTime();
296 if (timeRef>=10000) {
297 // 10 sec entre les demandes de ticket --> on refuse!!!
298 //System.out.println(String.format(samlValidationFailureTemplate, issueInstant, responseID, "Ticket " + ticket + " recognized but timeElapsed: " + timeRef));
299 //return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Ticket " + ticket + " recognized but timeElapsed: " + timeRef);
304 // we check the service now
305 if (!ssoValue.toLowerCase().startsWith(target.toLowerCase())) {
306 logger.error("Internal SSO : Service " + target + " invalid for the ticket found : ssoValue="+ssoValue);
307 return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Service " + target + " invalid for the ticket found");
310 ServiceSSO sso = null;
312 sso = ServiceSSOLocalServiceUtil.getFirstServiceMatched(target);
313 } catch (Exception e) {
314 logger.error("Unable to find a service in cas manager that matches target "+target, e);
317 logger.error("Internal SSO : Service " + target + " not authorized");
318 return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Service " + target + " not authorized");
321 long serviceId = sso.getServiceSSOId();
323 Long userId = new Long(0);
325 userId = Long.valueOf(ssoValue.toLowerCase().replace(target.toLowerCase(), ""));
326 } catch (Exception e) {
327 logger.error("Internal SSO : Invalid service removal", e);
328 return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Invalid service removal");
332 user = UserLocalServiceUtil.getUserById(userId);
333 } catch (Exception e) {
334 logger.error("Internal SSO : Invalid user reference", e);
335 return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Invalid user reference");
338 String ticketBody = "";
341 List<AttributSSO> listAttr = AttributSSOLocalServiceUtil.getAttributSSOByServiceId(serviceId);
342 for(AttributSSO attr : listAttr){
343 int type = Integer.valueOf(attr.getSourceType());
345 ticketBody += getUserAttr(user, attr, "saml");
347 ticketBody += getEtabAttr(user, attr, "saml");
350 } catch (NoSuchServiceURLException e) {
352 } catch (SystemException e) {
355 logger.debug(String.format(samlValidationResponseTemplate, issueInstant, responseID, responseID, issueInstant, issueInstant, issueInstant, user.getScreenName(), ticketBody, issueInstant, user.getScreenName()));
358 return String.format(samlValidationResponseTemplate, issueInstant, responseID, responseID, issueInstant, issueInstant, issueInstant, user.getScreenName(), ticketBody, issueInstant, user.getScreenName());
367 public static String validateTicket(String key, String service) throws SystemException {
369 logger.info("Validate ticket for: " + key + " " + service);
371 logger.error("Internal SSO INVALID_REQUEST : No ticket found in request");
372 return String.format(validationFailureTemplate, "INVALID_REQUEST", "No ticket found in request");
375 if (service.isEmpty()) {
376 logger.error("Internal SSO INVALID_REQUEST : No service found in request");
377 return String.format(validationFailureTemplate, "INVALID_REQUEST", "No service found in request");
381 // Get user from cache SSO
383 //String ssoValue = (String) ENTCacheUtils.getObjectFromCache(key);
385 UserInternalSSO uISSO = null;;
387 uISSO = UserInternalSSOLocalServiceUtil.getUserInternalSSOBySSOKey(key);
388 } catch (Exception e2) {
389 logger.error("Internal SSO INVALID_TICKET : Ticket " + key + " not recognized");
390 return String.format(validationFailureTemplate, "INVALID_TICKET", "Ticket " + key + " not recognized");
395 // ticket non valid ou incorrect
396 logger.error("Internal SSO INVALID_TICKET : Ticket " + key + " not recognized");
397 return String.format(validationFailureTemplate, "INVALID_TICKET", "Ticket " + key + " not recognized");
401 String ssoValue = uISSO.getSsoValue();
402 Date ticketTime = uISSO.getTimeMarker();
403 Date now = new Date();
405 UserInternalSSOLocalServiceUtil.deleteUserInternalSSO(uISSO);
406 //ENTCacheUtils.removeObjectFromCache(ticket);
407 //ENTCacheUtils.removeObjectFromCache(key);
409 long timeRef = now.getTime()-ticketTime.getTime();
410 if (timeRef>=10000) {
411 // 10 sec entre les demandes de ticket --> on refuse!!!
412 //return String.format(validationFailureTemplate, "INVALID_TICKET", "Ticket " + key + " recognized but timeElapsed: "+timeRef);
416 // we check the service now
417 if (!ssoValue.startsWith(service)) {
418 logger.error("Internal SSO INVALID_SERVICE :Service " + service + " invalid for the ticket found");
419 return String.format(validationFailureTemplate, "INVALID_SERVICE", "Service " + service + " invalid for the ticket found");
423 ServiceSSO sso = null;
425 sso = ServiceSSOLocalServiceUtil.getFirstServiceMatched(service);
426 } catch (SystemException e1) {
430 logger.error("Internal SSO INVALID_SERVICE :Service " + service + " invalid for the ticket found");
431 return String.format(validationFailureTemplate, "INVALID_SERVICE", "Service " + service + " invalid for the ticket found");
434 long serviceId = sso.getServiceSSOId();
436 Long userId = new Long(0);
438 // Special case for edx
439 String userIdStr = ssoValue.replace(service, "");
440 if (userIdStr.startsWith("?next=%2F")) {
441 userIdStr = userIdStr.substring(9);
443 userId = Long.valueOf(userIdStr);
444 } catch (Exception e) {
445 logger.error("Invalid user r�ference on SSO service validate",e);
446 return String.format(validationFailureTemplate, "INTERNAL_ERROR", "Invalid service removal");
450 user = UserLocalServiceUtil.getUserById(userId);
451 } catch (Exception e) {
452 logger.error("Invalid user r�ference on SSO service validate",e);
453 return String.format(validationFailureTemplate, "INTERNAL_ERROR", "Invalid user reference");
455 String ticketBody = "";
456 // ticketBody += "<cas:user>" + user.getScreenName() + "</cas:user>";
457 // ticketBody += "<cas:uid>" + user.getScreenName() + "</cas:uid>";
460 List<AttributSSO> listAttr = AttributSSOLocalServiceUtil.getAttributSSOByServiceId(serviceId);
461 for(AttributSSO attr : listAttr){
462 int type = Integer.valueOf(attr.getSourceType());
464 ticketBody += getUserAttr(user, attr, "classic");
466 ticketBody += getEtabAttr(user, attr, "classic");
469 } catch (NoSuchServiceURLException e) {
471 } catch (SystemException e) {
474 logger.debug(String.format(validationResponseTemplate, ticketBody));
475 return String.format(validationResponseTemplate, ticketBody);
479 protected static String validationFailureTemplate = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n" +
480 "<cas:authenticationFailure code=\"%s\">\n"+
482 "</cas:authenticationFailure>\n"+
483 "</cas:serviceResponse>";
485 protected static String validationResponseTemplate = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n" +
486 "<cas:authenticationSuccess>\n"+
488 "</cas:authenticationSuccess>\n"+
489 "</cas:serviceResponse>";
491 protected static String samlValidationFailureTemplate = "<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>\n" +
492 "<SOAP-ENV:Header/>\n"+
494 "<Response xmlns='urn:oasis:names:tc:SAML:1.0:protocol'\n"+
495 "xmlns:saml='urn:oasis:names:tc:SAML:1.0:assertion'\n"+
496 "xmlns:samlp='urn:oasis:names:tc:SAML:1.0:protocol'\n"+
497 "xmlns:xsd='http://www.w3.org/2001/XMLSchema'\n"+
498 "xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n"+
499 "IssueInstant='%s' MajorVersion='1'\n"+
500 "MinorVersion='1' Recipient='https://www.cartabledesavoie.com'\n"+
501 "ResponseID='%s'>\n"+
503 "<StatusCode>Value='samlp:Responder'</StatusCode>\n"+
504 "<StatusMessage>%s</StatusMessage>\n"+
507 "</SOAP-ENV:Body>\n"+
508 "</SOAP-ENV:Envelope>";
510 protected static String samlAttributeTemplate = "<Attribute AttributeName='%s' AttributeNamespace='http://www.ja-sig.org/products/cas/'><AttributeValue>%s</AttributeValue></Attribute>\n";
511 protected static String classicAttributeTemplate = "<cas:%s>%s</cas:%s>\n";
514 protected static String samlValidationResponseTemplate = "<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>\n"+
515 "<SOAP-ENV:Header />\n"+
517 "<Response xmlns='urn:oasis:names:tc:SAML:1.0:protocol' xmlns:saml='urn:oasis:names:tc:SAML:1.0:assertion'\n"+
518 "xmlns:samlp='urn:oasis:names:tc:SAML:1.0:protocol' xmlns:xsd='http://www.w3.org/2001/XMLSchema'\n"+
519 "xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' IssueInstant='%s'\n"+
520 "MajorVersion='1' MinorVersion='1' Recipient='https://eiger.iad.vt.edu/dat/home.do'\n"+
521 "ResponseID='%s'>\n"+
523 "<StatusCode Value='samlp:Success'>\n"+
526 "<Assertion xmlns='urn:oasis:names:tc:SAML:1.0:assertion' AssertionID='%s'\n"+
527 "IssueInstant='%s' Issuer='localhost' MajorVersion='1'\n"+
528 "MinorVersion='1'>\n"+
529 "<Conditions NotBefore='%s' NotOnOrAfter='%s'>\n"+
530 "<AudienceRestrictionCondition>\n"+
532 "https://www.cartabledesavoie.com/\n"+
534 "</AudienceRestrictionCondition>\n"+
536 "<AttributeStatement>\n"+
538 "<NameIdentifier>%s</NameIdentifier>\n"+
539 "<SubjectConfirmation>\n"+
540 "<ConfirmationMethod>\n"+
541 "urn:oasis:names:tc:SAML:1.0:cm:artifact\n"+
542 "</ConfirmationMethod>\n"+
543 "</SubjectConfirmation>\n"+
546 "</AttributeStatement>\n"+
547 "<AuthenticationStatement AuthenticationInstant='%s'\n"+
548 "AuthenticationMethod='urn:oasis:names:tc:SAML:1.0:am:password'>\n"+
550 "<NameIdentifier>%s</NameIdentifier>\n"+
551 "<SubjectConfirmation>\n"+
552 "<ConfirmationMethod>\n"+
553 "urn:oasis:names:tc:SAML:1.0:cm:artifact\n"+
554 "</ConfirmationMethod>\n"+
555 "</SubjectConfirmation>\n"+
557 "</AuthenticationStatement>\n"+
560 "</SOAP-ENV:Body>\n"+
561 "</SOAP-ENV:Envelope>";