--- /dev/null
+package com.liferay.portal.security.internalSSO;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import javax.servlet.http.HttpServletRequest;
+
+import com.liferay.portal.kernel.exception.SystemException;
+import com.liferay.portal.kernel.log.Log;
+import com.liferay.portal.kernel.log.LogFactoryUtil;
+import com.liferay.portal.model.Organization;
+import com.liferay.portal.model.User;
+import com.liferay.portal.service.UserLocalServiceUtil;
+import com.pentila.entSavoie.casManager.model.AttributSSO;
+import com.pentila.entSavoie.casManager.model.ServiceSSO;
+import com.pentila.entSavoie.casManager.service.AttributSSOLocalServiceUtil;
+import com.pentila.entSavoie.casManager.service.ServiceSSOLocalServiceUtil;
+import com.pentila.entSavoie.communityInfos.service.OrganizationMappingLocalServiceUtil;
+import com.pentila.entSavoie.directory.OrganizationFinderServiceUtil;
+import com.pentila.entSavoie.gestionServiceURL.NoSuchServiceURLException;
+import com.pentila.entSavoie.userManagement.model.LDAPMapping;
+import com.pentila.entSavoie.userManagement.service.LDAPMappingLocalServiceUtil;
+import com.pentila.entSavoie.userProperties.model.UserInternalSSO;
+import com.pentila.entSavoie.userProperties.service.UserInternalSSOLocalServiceUtil;
+import com.pentila.entSavoie.utils.ENTMainUtilsLocalServiceUtil;
+import com.pentila.entSavoie.utils.LDAPUtilsLocalServiceUtil;
+
+public class InternalSSO {
+
+ static SimpleDateFormat sortDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.000'Z'");
+
+ private static Log logger = LogFactoryUtil.getLog(InternalSSO.class);
+
+ public static String getTicket(User user, String service) {
+
+ try {
+
+
+ if (service.isEmpty()) {
+ logger.error("No service found in ticket request");
+ return "NO_SERVICE";
+ }
+
+
+ ServiceSSO monService = ServiceSSOLocalServiceUtil.getFirstServiceMatched(service);
+
+ if(monService != null){
+ // Generate a ticket for the user and store it in a cache!
+ String ssoIdK = UUID.randomUUID().toString();
+
+ // Clé du cache
+ String internalSSOUserKey="ST-ISC-"+ssoIdK;
+ // we store the ticket for a valid period of 10sec
+ // the value stored is the service concact with the userid
+ UserInternalSSOLocalServiceUtil.addUserInternalSSO(internalSSOUserKey, service + user.getUserId());
+ //ENTCacheUtils.storeObjectIntoCache(internalSSOUserKey,service + user.getUserId(),10000);
+ logger.info("ticket " + internalSSOUserKey + " stored");
+ return internalSSOUserKey;
+ }else{
+ return "NOT_ALLOWED";
+ }
+
+ } catch (Exception e) {
+ logger.error("error in getTicket acquire",e);
+ return "";
+ }
+ }
+
+ private static String getUserAttr(User user, AttributSSO attr, String returnType){
+
+
+ String attrSamlName = attr.getSamlName();
+ String attrSamlValue = "";
+
+ int attrName = Integer.valueOf(attr.getSourceAttrName());
+ boolean isCO3OrCAIRNS = ENTMainUtilsLocalServiceUtil.isDlStoreCO3(user.getCompanyId());
+
+ try{
+ LDAPMapping ldapM = LDAPMappingLocalServiceUtil.fetchLDAPMapping(user.getUserId());
+
+ switch (attrName) {
+ //uid --> uid
+ case 1:
+ attrSamlValue = ldapM.getUID();
+ break;
+ //nom --> sn
+ case 2:
+ attrSamlValue = user.getLastName();
+ break;
+ //prénom --> givenName
+ case 3:
+ attrSamlValue = user.getFirstName();
+ break;
+ //login --> ENTPersonLogin
+ case 4:
+ attrSamlValue = user.getScreenName();
+ break;
+ //date de naissance --> ENTPersonDateNaissance
+ case 5:
+ attrSamlValue = LDAPUtilsLocalServiceUtil.getLdapAttribute(user, "ENTPersonDateNaissance");
+ break;
+ //Classes --> ENTEleveClasses
+ case 6:
+ attrSamlValue = LDAPUtilsLocalServiceUtil.getLdapAttribute(user, "ENTEleveClasses");
+ break;
+ //Profil --> ENTPersonProfils
+ case 7:
+ attrSamlValue = LDAPUtilsLocalServiceUtil.getLdapAttribute(user, "ENTPersonProfils");
+ break;
+ //Niveau de formation --> ENTEleveNivFormation
+ case 8:
+ attrSamlValue = LDAPUtilsLocalServiceUtil.getLdapAttribute(user, "ENTEleveNivFormation");
+ break;
+ // ENT jointure --> ENTPersonJointure (equals UID on CO3 and CAIRNS but not on HN)
+ case 9:
+ if (!isCO3OrCAIRNS) {
+ attrSamlValue = ldapM.getUID().substring(0, ldapM.getUID().length()-3);
+ }
+ else {
+ attrSamlValue = ldapM.getUID();
+ }
+ break;
+ // ENT jointure Prefixe UT--> ENTPersonJointure
+ case 10:
+ if (!isCO3OrCAIRNS) {
+ attrSamlValue = "UT" + ldapM.getUID().substring(0, ldapM.getUID().length()-3);
+ }
+ else {
+ attrSamlValue = "UT" + ldapM.getUID();
+ }
+ break;
+ //Code postal --> ENTPersonCodePostal
+ case 11:
+ attrSamlValue = LDAPUtilsLocalServiceUtil.getLdapAttribute(user, "ENTPersonCodePostal");
+ break;
+ //email address
+ case 12:
+ attrSamlValue = user.getEmailAddress();
+ break;
+ //person role --> ENTPersonFonctions
+ case 13:
+ attrSamlValue = LDAPUtilsLocalServiceUtil.getLdapAttribute(user, "ENTPersonFonctions");
+ break;
+ default:
+ break;
+ }
+ }catch (Exception e) {
+ logger.error(e);
+ }
+
+ String result = "";
+
+ if (returnType.equals("classic")) {
+ result = String.format(classicAttributeTemplate, attrSamlName, attrSamlValue, attrSamlName);
+ }
+ else {
+ result = String.format(samlAttributeTemplate, attrSamlName, attrSamlValue);
+ }
+
+ return result;
+ }
+
+ private static String getEtabAttr(User user, AttributSSO attr, String returnType){
+ String attrSamlName = attr.getSamlName();
+ String attrSamlValue = "";
+
+ int attrName = Integer.valueOf(attr.getSourceAttrName());
+ try{
+ Organization userOrg = OrganizationFinderServiceUtil.getEtabRatachement(user);
+
+ switch (attrName) {
+ case 1:
+ attrSamlValue = OrganizationMappingLocalServiceUtil.getOrganizationStrutUAI(userOrg);
+ break;
+
+ default:
+ break;
+ }
+ }catch (Exception e) {
+ logger.error(e);
+ }
+ String result = "";
+
+ if (returnType.equals("classic")) {
+ result = String.format(classicAttributeTemplate, attrSamlName, attrSamlValue, attrSamlName);
+ }
+ else {
+ result = String.format(samlAttributeTemplate, attrSamlName, attrSamlValue);
+ }
+
+ return result;
+ }
+
+
+ public static String samlValidateTicket(String target, HttpServletRequest request) throws IOException, SystemException {
+ logger.info("Validate ticket in SAML form for: " + target);
+
+ // inside service(ServletRequest req, ServletResponse res)
+ // of a class that implements Servlet
+ // or
+ // inside doPost(HttpServletRequest req, HttpServletResponse resp)
+ // of a class that implements HTTPServlet
+ String issueInstant = sortDateFormat.format(new Date());
+ String responseID = "_" + UUID.randomUUID().toString().replace("-", "");
+
+ StringBuilder stringBuilder = new StringBuilder();
+ BufferedReader bufferedReader = null;
+ try {
+ InputStream inputStream = request.getInputStream();
+ if (inputStream != null) {
+ bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
+ char[] charBuffer = new char[128];
+ int bytesRead = -1;
+ while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
+ stringBuilder.append(charBuffer, 0, bytesRead);
+ }
+ } else {
+ stringBuilder.append("");
+ }
+ } catch (IOException ex) {
+ throw ex;
+ } finally {
+ if (bufferedReader != null) {
+ try {
+ bufferedReader.close();
+ } catch (IOException ex) {
+ throw ex;
+ }
+ }
+ }
+ // on obtient le body
+ String body = stringBuilder.toString();
+ //System.out.println(body);
+ if (body.isEmpty()) {
+ logger.error("Internal SSO : No body found in request");
+ return String.format(samlValidationFailureTemplate, issueInstant, responseID, "No body found in request");
+ }
+
+ int indexStart = body.indexOf("<samlp:AssertionArtifact>");
+ int indexEnd = body.indexOf("</samlp:AssertionArtifact>");
+
+ if (indexStart==-1 || indexEnd==-1) {
+ logger.error("Internal SSO : no ticket found");
+ return "";
+ }
+ String ticket = body.substring(indexStart+25, indexEnd);
+ ticket = ticket.replace("\n", "");
+ ticket = ticket.trim();
+
+ logger.debug("ticket found is: " + ticket);
+
+
+
+ if (ticket.isEmpty()) {
+ logger.error("Internal SSO : No ticket found in request");
+ return String.format(samlValidationFailureTemplate, issueInstant, responseID, "No ticket found in request");
+ }
+
+ if (target.isEmpty()) {
+ logger.error("Internal SSO : No target found in request");
+ return String.format(samlValidationFailureTemplate, issueInstant, responseID, "No target found in request");
+ }
+
+ User user = null;
+ // Get user from cache SSO
+ //String ssoValue = (String) ENTCacheUtils.getObjectFromCache(ticket);
+
+ UserInternalSSO uISSO = null;
+ try {
+ uISSO = UserInternalSSOLocalServiceUtil.getUserInternalSSOBySSOKey(ticket);
+ } catch (Exception e2) {
+ logger.error("Internal SSO : Ticket " + ticket + " not recognized");
+ return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Ticket " + ticket + " not recognized");
+ }
+
+ if (uISSO == null) {
+ // ticket non valid ou incorrect
+ logger.error("Internal SSO : Ticket " + ticket + " not recognized");
+ return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Ticket " + ticket + " not recognized");
+ }
+ else {
+ // ticket valid
+ String ssoValue = uISSO.getSsoValue();
+ Date ticketTime = uISSO.getTimeMarker();
+ Date now = new Date();
+
+ UserInternalSSOLocalServiceUtil.deleteUserInternalSSO(uISSO);
+ //ENTCacheUtils.removeObjectFromCache(ticket);
+ long timeRef = now.getTime()-ticketTime.getTime();
+ if (timeRef>=10000) {
+ // 10 sec entre les demandes de ticket --> on refuse!!!
+ //System.out.println(String.format(samlValidationFailureTemplate, issueInstant, responseID, "Ticket " + ticket + " recognized but timeElapsed: " + timeRef));
+ //return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Ticket " + ticket + " recognized but timeElapsed: " + timeRef);
+ }
+
+
+
+ // we check the service now
+ if (!ssoValue.toLowerCase().startsWith(target.toLowerCase())) {
+ logger.error("Internal SSO : Service " + target + " invalid for the ticket found : ssoValue="+ssoValue);
+ return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Service " + target + " invalid for the ticket found");
+ }
+
+ ServiceSSO sso = null;
+ try {
+ sso = ServiceSSOLocalServiceUtil.getFirstServiceMatched(target);
+ } catch (Exception e) {
+ logger.error("Unable to find a service in cas manager that matches target "+target, e);
+ }
+ if (sso == null) {
+ logger.error("Internal SSO : Service " + target + " not authorized");
+ return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Service " + target + " not authorized");
+ }
+
+ long serviceId = sso.getServiceSSOId();
+
+ Long userId = new Long(0);
+ try {
+ userId = Long.valueOf(ssoValue.toLowerCase().replace(target.toLowerCase(), ""));
+ } catch (Exception e) {
+ logger.error("Internal SSO : Invalid service removal", e);
+ return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Invalid service removal");
+ }
+
+ try {
+ user = UserLocalServiceUtil.getUserById(userId);
+ } catch (Exception e) {
+ logger.error("Internal SSO : Invalid user reference", e);
+ return String.format(samlValidationFailureTemplate, issueInstant, responseID, "Invalid user reference");
+ }
+
+ String ticketBody = "";
+
+ try {
+ List<AttributSSO> listAttr = AttributSSOLocalServiceUtil.getAttributSSOByServiceId(serviceId);
+ for(AttributSSO attr : listAttr){
+ int type = Integer.valueOf(attr.getSourceType());
+ if(type == 1){
+ ticketBody += getUserAttr(user, attr, "saml");
+ }else if(type == 2){
+ ticketBody += getEtabAttr(user, attr, "saml");
+ }
+ }
+ } catch (NoSuchServiceURLException e) {
+ logger.error(e);
+ } catch (SystemException e) {
+ logger.error(e);
+ }
+ logger.debug(String.format(samlValidationResponseTemplate, issueInstant, responseID, responseID, issueInstant, issueInstant, issueInstant, user.getScreenName(), ticketBody, issueInstant, user.getScreenName()));
+
+
+ return String.format(samlValidationResponseTemplate, issueInstant, responseID, responseID, issueInstant, issueInstant, issueInstant, user.getScreenName(), ticketBody, issueInstant, user.getScreenName());
+ }
+
+
+
+
+
+ }
+
+ public static String validateTicket(String key, String service) throws SystemException {
+
+ logger.info("Validate ticket for: " + key + " " + service);
+ if (key.isEmpty()) {
+ logger.error("Internal SSO INVALID_REQUEST : No ticket found in request");
+ return String.format(validationFailureTemplate, "INVALID_REQUEST", "No ticket found in request");
+ }
+
+ if (service.isEmpty()) {
+ logger.error("Internal SSO INVALID_REQUEST : No service found in request");
+ return String.format(validationFailureTemplate, "INVALID_REQUEST", "No service found in request");
+ }
+
+ User user = null;
+ // Get user from cache SSO
+
+ //String ssoValue = (String) ENTCacheUtils.getObjectFromCache(key);
+
+ UserInternalSSO uISSO = null;;
+ try {
+ uISSO = UserInternalSSOLocalServiceUtil.getUserInternalSSOBySSOKey(key);
+ } catch (Exception e2) {
+ logger.error("Internal SSO INVALID_TICKET : Ticket " + key + " not recognized");
+ return String.format(validationFailureTemplate, "INVALID_TICKET", "Ticket " + key + " not recognized");
+ }
+
+
+ if (uISSO == null) {
+ // ticket non valid ou incorrect
+ logger.error("Internal SSO INVALID_TICKET : Ticket " + key + " not recognized");
+ return String.format(validationFailureTemplate, "INVALID_TICKET", "Ticket " + key + " not recognized");
+ }
+ else {
+ // ticket valid
+ String ssoValue = uISSO.getSsoValue();
+ Date ticketTime = uISSO.getTimeMarker();
+ Date now = new Date();
+
+ UserInternalSSOLocalServiceUtil.deleteUserInternalSSO(uISSO);
+ //ENTCacheUtils.removeObjectFromCache(ticket);
+ //ENTCacheUtils.removeObjectFromCache(key);
+
+ long timeRef = now.getTime()-ticketTime.getTime();
+ if (timeRef>=10000) {
+ // 10 sec entre les demandes de ticket --> on refuse!!!
+ //return String.format(validationFailureTemplate, "INVALID_TICKET", "Ticket " + key + " recognized but timeElapsed: "+timeRef);
+ }
+
+
+ // we check the service now
+ if (!ssoValue.startsWith(service)) {
+ logger.error("Internal SSO INVALID_SERVICE :Service " + service + " invalid for the ticket found");
+ return String.format(validationFailureTemplate, "INVALID_SERVICE", "Service " + service + " invalid for the ticket found");
+ }
+
+ //
+ ServiceSSO sso = null;
+ try {
+ sso = ServiceSSOLocalServiceUtil.getFirstServiceMatched(service);
+ } catch (SystemException e1) {
+ logger.error(e1);
+ }
+ if(sso == null){
+ logger.error("Internal SSO INVALID_SERVICE :Service " + service + " invalid for the ticket found");
+ return String.format(validationFailureTemplate, "INVALID_SERVICE", "Service " + service + " invalid for the ticket found");
+ }
+
+ long serviceId = sso.getServiceSSOId();
+
+ Long userId = new Long(0);
+ try {
+ // Special case for edx
+ String userIdStr = ssoValue.replace(service, "");
+ if (userIdStr.startsWith("?next=%2F")) {
+ userIdStr = userIdStr.substring(9);
+ }
+ userId = Long.valueOf(userIdStr);
+ } catch (Exception e) {
+ logger.error("Invalid user r�ference on SSO service validate",e);
+ return String.format(validationFailureTemplate, "INTERNAL_ERROR", "Invalid service removal");
+ }
+
+ try {
+ user = UserLocalServiceUtil.getUserById(userId);
+ } catch (Exception e) {
+ logger.error("Invalid user r�ference on SSO service validate",e);
+ return String.format(validationFailureTemplate, "INTERNAL_ERROR", "Invalid user reference");
+ }
+ String ticketBody = "";
+// ticketBody += "<cas:user>" + user.getScreenName() + "</cas:user>";
+// ticketBody += "<cas:uid>" + user.getScreenName() + "</cas:uid>";
+
+ try {
+ List<AttributSSO> listAttr = AttributSSOLocalServiceUtil.getAttributSSOByServiceId(serviceId);
+ for(AttributSSO attr : listAttr){
+ int type = Integer.valueOf(attr.getSourceType());
+ if(type == 1){
+ ticketBody += getUserAttr(user, attr, "classic");
+ }else if(type == 2){
+ ticketBody += getEtabAttr(user, attr, "classic");
+ }
+ }
+ } catch (NoSuchServiceURLException e) {
+ logger.error(e);
+ } catch (SystemException e) {
+ logger.error(e);
+ }
+ logger.debug(String.format(validationResponseTemplate, ticketBody));
+ return String.format(validationResponseTemplate, ticketBody);
+ }
+ }
+
+ protected static String validationFailureTemplate = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n" +
+"<cas:authenticationFailure code=\"%s\">\n"+
+"%s\n"+
+"</cas:authenticationFailure>\n"+
+"</cas:serviceResponse>";
+
+ protected static String validationResponseTemplate = "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n" +
+ "<cas:authenticationSuccess>\n"+
+ "%s\n"+
+ "</cas:authenticationSuccess>\n"+
+ "</cas:serviceResponse>";
+
+ protected static String samlValidationFailureTemplate = "<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>\n" +
+ "<SOAP-ENV:Header/>\n"+
+ "<SOAP-ENV:Body>\n"+
+ "<Response xmlns='urn:oasis:names:tc:SAML:1.0:protocol'\n"+
+ "xmlns:saml='urn:oasis:names:tc:SAML:1.0:assertion'\n"+
+ "xmlns:samlp='urn:oasis:names:tc:SAML:1.0:protocol'\n"+
+ "xmlns:xsd='http://www.w3.org/2001/XMLSchema'\n"+
+ "xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n"+
+ "IssueInstant='%s' MajorVersion='1'\n"+
+ "MinorVersion='1' Recipient='https://www.cartabledesavoie.com'\n"+
+ "ResponseID='%s'>\n"+
+ "<Status>\n"+
+ "<StatusCode>Value='samlp:Responder'</StatusCode>\n"+
+ "<StatusMessage>%s</StatusMessage>\n"+
+ "</Status>\n"+
+ "</Response>\n"+
+ "</SOAP-ENV:Body>\n"+
+"</SOAP-ENV:Envelope>";
+
+ protected static String samlAttributeTemplate = "<Attribute AttributeName='%s' AttributeNamespace='http://www.ja-sig.org/products/cas/'><AttributeValue>%s</AttributeValue></Attribute>\n";
+ protected static String classicAttributeTemplate = "<cas:%s>%s</cas:%s>\n";
+
+
+ protected static String samlValidationResponseTemplate = "<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>\n"+
+ "<SOAP-ENV:Header />\n"+
+ "<SOAP-ENV:Body>\n"+
+ "<Response xmlns='urn:oasis:names:tc:SAML:1.0:protocol' xmlns:saml='urn:oasis:names:tc:SAML:1.0:assertion'\n"+
+ "xmlns:samlp='urn:oasis:names:tc:SAML:1.0:protocol' xmlns:xsd='http://www.w3.org/2001/XMLSchema'\n"+
+ "xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' IssueInstant='%s'\n"+
+ "MajorVersion='1' MinorVersion='1' Recipient='https://eiger.iad.vt.edu/dat/home.do'\n"+
+ "ResponseID='%s'>\n"+
+ "<Status>\n"+
+ "<StatusCode Value='samlp:Success'>\n"+
+ "</StatusCode>\n"+
+ "</Status>\n"+
+ "<Assertion xmlns='urn:oasis:names:tc:SAML:1.0:assertion' AssertionID='%s'\n"+
+ "IssueInstant='%s' Issuer='localhost' MajorVersion='1'\n"+
+ "MinorVersion='1'>\n"+
+ "<Conditions NotBefore='%s' NotOnOrAfter='%s'>\n"+
+ "<AudienceRestrictionCondition>\n"+
+ "<Audience>\n"+
+ "https://www.cartabledesavoie.com/\n"+
+ "</Audience>\n"+
+ "</AudienceRestrictionCondition>\n"+
+ "</Conditions>\n"+
+ "<AttributeStatement>\n"+
+ "<Subject>\n"+
+ "<NameIdentifier>%s</NameIdentifier>\n"+
+ "<SubjectConfirmation>\n"+
+ "<ConfirmationMethod>\n"+
+ "urn:oasis:names:tc:SAML:1.0:cm:artifact\n"+
+ "</ConfirmationMethod>\n"+
+ "</SubjectConfirmation>\n"+
+ "</Subject>\n"+
+ "%s\n"+
+ "</AttributeStatement>\n"+
+ "<AuthenticationStatement AuthenticationInstant='%s'\n"+
+ "AuthenticationMethod='urn:oasis:names:tc:SAML:1.0:am:password'>\n"+
+ "<Subject>\n"+
+ "<NameIdentifier>%s</NameIdentifier>\n"+
+ "<SubjectConfirmation>\n"+
+ "<ConfirmationMethod>\n"+
+ "urn:oasis:names:tc:SAML:1.0:cm:artifact\n"+
+ "</ConfirmationMethod>\n"+
+ "</SubjectConfirmation>\n"+
+ "</Subject>\n"+
+ "</AuthenticationStatement>\n"+
+ "</Assertion>\n"+
+ "</Response>\n"+
+ "</SOAP-ENV:Body>\n"+
+ "</SOAP-ENV:Envelope>";
+
+}