/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2008 Sun Microsystems Inc. All Rights Reserved * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the License). You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * https://opensso.dev.java.net/public/CDDLv1.0.html or * opensso/legal/CDDLv1.0.txt * See the License for the specific language governing * permission and limitations under the License. * * When distributing Covered Code, include this CDDL * Header Notice in each file and include the License file * at opensso/legal/CDDLv1.0.txt. * If applicable, add the following below the CDDL Header, * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * $Id: ValidateSAML2.java,v 1.4 2009/11/20 22:45:57 ggennaro Exp $ * * Portions Copyrighted 2014-2016 ForgeRock AS. */ package com.sun.identity.workflow; import com.sun.identity.common.HttpURLConnectionManager; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.util.Iterator; import java.util.List; import java.util.MissingResourceException; import java.util.ResourceBundle; import com.sun.identity.saml2.common.SAML2Constants; import com.sun.identity.saml2.common.SAML2Utils; import com.sun.identity.saml2.jaxb.entityconfig.IDPSSOConfigElement; import com.sun.identity.saml2.jaxb.entityconfig.SPSSOConfigElement; import com.sun.identity.saml2.jaxb.metadata.IDPSSODescriptorElement; import com.sun.identity.saml2.jaxb.metadata.SPSSODescriptorElement; import com.sun.identity.saml2.jaxb.metadata.SingleLogoutServiceElement; import com.sun.identity.saml2.jaxb.metadata.SingleSignOnServiceElement; import com.sun.identity.saml2.meta.SAML2MetaException; import com.sun.identity.saml2.meta.SAML2MetaManager; import com.sun.identity.shared.debug.Debug; import com.sun.identity.shared.locale.Locale; public class ValidateSAML2 { private static Debug debug = Debug.getInstance("workflow"); private static final String LOGIN_URL = "/UI/Login"; private static final String LOGOUT_URL = "/UI/Logout"; private String realm; private String idpEntityId; private String spEntityId; private String idpMetaAlias; private String spMetaAlias; private String idpBaseURL; private String spBaseURL; private boolean bFedlet = false; public ValidateSAML2(String realm, String idp, String sp) throws WorkflowException { this.realm = realm; setIDPEntityId(idp); setSPEntityId(sp); validateIDP(); validateSP(); } private void validateIDP() throws WorkflowException { try { SAML2MetaManager mm = SAML2Utils.getSAML2MetaManager(); IDPSSODescriptorElement elt = mm.getIDPSSODescriptor( realm, idpEntityId); if (elt == null) { Object[] param = {idpEntityId}; throw new WorkflowException("cannot.locate.idp", param); } if (idpMetaAlias != null) { IDPSSOConfigElement idpConfig = mm.getIDPSSOConfig(realm, idpEntityId); if (idpConfig == null) { Object[] param = {idpEntityId}; throw new WorkflowException("cannot.locate.idp", param); } else { if (!idpConfig.getMetaAlias().equals(idpMetaAlias)) { Object[] param = {idpEntityId}; throw new WorkflowException("cannot.locate.idp", param); } } } List ssoServiceList = elt.getSingleSignOnService(); idpBaseURL = getIDPBaseURL(ssoServiceList); if (idpBaseURL == null) { Object[] param = {idpEntityId}; throw new WorkflowException("cannot.locate.idp.loginURL", param); } validateURL(idpBaseURL); } catch (SAML2MetaException ex) { debug.error("ValidateSAML2: Error while validating IdP", ex); Object[] param = {idpEntityId}; throw new WorkflowException("cannot.locate.idp", param); } } private String getIDPBaseURL(List ssoServiceList) { String url = null; if ((ssoServiceList != null) && !ssoServiceList.isEmpty()) { for (Iterator i = ssoServiceList.iterator(); i.hasNext() && (url == null);) { SingleSignOnServiceElement sso = (SingleSignOnServiceElement) i.next(); if ((sso != null) && (sso.getBinding() != null)) { String ssoURL = sso.getLocation(); int loc = ssoURL.indexOf("/metaAlias/"); if (loc != -1) { String tmp = ssoURL.substring(0, loc); loc = tmp.lastIndexOf("/"); url = tmp.substring(0, loc); } } } } return url; } private void validateSP() throws WorkflowException { try { SAML2MetaManager mm = SAML2Utils.getSAML2MetaManager(); SPSSODescriptorElement elt = mm.getSPSSODescriptor( realm, spEntityId); if (elt == null) { Object[] param = {spEntityId}; throw new WorkflowException("cannot.locate.sp", param); } if (spMetaAlias != null) { SPSSOConfigElement spConfig = mm.getSPSSOConfig(realm, spEntityId); if (spConfig == null) { Object[] param = {spEntityId}; throw new WorkflowException("cannot.locate.sp", param); } else { if (!spConfig.getMetaAlias().equals(spMetaAlias)) { Object[] param = {spEntityId}; throw new WorkflowException("cannot.locate.sp", param); } } } List sloServiceList = elt.getSingleLogoutService(); spBaseURL = getSPBaseURL(sloServiceList); if (spBaseURL == null) { bFedlet = true; } else { validateURL(spBaseURL); } } catch (SAML2MetaException ex) { debug.error("ValidateSAML2: Error while validating SP", ex); Object[] param = {spEntityId}; throw new WorkflowException("cannot.locate.sp", param); } } private void validateURL(String strUrl) throws WorkflowException { try { URL url = new URL(strUrl); URLConnection connection = HttpURLConnectionManager.getConnection(url); connection.connect(); } catch (MalformedURLException ex) { Object[] params = {strUrl}; throw new WorkflowException("malformedurl", params); } catch (IOException ex) { debug.error("ValidateSAML2: IO Error while validating URL", ex); Object[] params = {strUrl}; throw new WorkflowException("unable.to.reach.url", params); } } private String getSPBaseURL(List sloServiceList) { String url = null; if ((sloServiceList != null) && !sloServiceList.isEmpty()) { for (Iterator i = sloServiceList.iterator(); i.hasNext() && (url == null);) { SingleLogoutServiceElement sso = (SingleLogoutServiceElement) i.next(); if ((sso != null) && (sso.getBinding() != null)) { String ssoURL = sso.getLocation(); int loc = ssoURL.indexOf("/metaAlias/"); if (loc != -1) { String tmp = ssoURL.substring(0, loc); loc = tmp.lastIndexOf("/"); url = tmp.substring(0, loc); } } } } return url; } private void setIDPEntityId(String idp) { int idx = idp.indexOf("("); if (idx != -1) { int idx1 = idp.indexOf(")", idx); if (idx1 != -1) { idpEntityId = idp.substring(0, idx); idpMetaAlias = idp.substring(idx+1, idx1); } else { idpEntityId = idp; } } else { idpEntityId = idp; } } private void setSPEntityId(String sp) { int idx = sp.indexOf("("); if (idx != -1) { int idx1 = sp.indexOf(")", idx); if (idx1 != -1) { spEntityId = sp.substring(0, idx); spMetaAlias = sp.substring(idx+1, idx1); } else { spEntityId = sp; } } else { spEntityId = sp; } } public static String getMessage(String key, String locale) { try { ResourceBundle rb = ResourceBundle.getBundle( "workflowMessages", Locale.getLocale(locale)); return rb.getString(key); } catch (MissingResourceException e) { return null; } } public String getIDPEntityId() { return idpEntityId; } public String getSPEntityId() { return spEntityId; } public String getIDPLoginURL() { return idpBaseURL + LOGIN_URL; } public String getSPLoginURL() { return spBaseURL + LOGIN_URL; } public String getIDPLogoutURL() { return idpBaseURL + LOGOUT_URL; } public String getSPLogoutURL() { return spBaseURL + LOGOUT_URL; } public boolean isFedlet() { return bFedlet; } public boolean isGoogleSP() { if( this.spEntityId != null ) { if( this.spEntityId.contains("google.com") ) { return true; } } return false; } public boolean isSalesforceSP() { if( this.spEntityId != null ) { if( this.spEntityId.contains("salesforce.com") ) { return true; } } return false; } public boolean isIDPHosted() { return (idpMetaAlias != null) && (idpMetaAlias.length() > 0); } public String getSSOURL() { if (idpMetaAlias != null) { try { if (bFedlet) { String url = idpBaseURL + "/idpssoinit"; url += "?metaAlias=" + URLEncoder.encode(idpMetaAlias, "UTF-8") + "&spEntityID=" + URLEncoder.encode(spEntityId, "UTF-8") + "&binding=" + URLEncoder.encode("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", "UTF-8"); if( isGoogleSP() ) { url += "&NameIDFormat=" + URLEncoder.encode(SAML2Constants.NAMEID_FORMAT_NAMESPACE_V_1_1 + "unspecified", "UTF-8"); } else if( !isSalesforceSP() ){ url += "&NameIDFormat=" + URLEncoder.encode(SAML2Constants.NAMEID_FORMAT_NAMESPACE + "transient", "UTF-8"); } return url; } else { return idpBaseURL + "/idpssoinit?metaAlias=" + URLEncoder.encode(idpMetaAlias, "UTF-8") + "&spEntityID=" + URLEncoder.encode(spEntityId, "UTF-8"); } } catch (UnsupportedEncodingException ex) { return ""; } } else { try { return spBaseURL + "/spssoinit?metaAlias=" + URLEncoder.encode(spMetaAlias, "UTF-8") + "&idpEntityID=" + URLEncoder.encode(idpEntityId, "UTF-8"); } catch (UnsupportedEncodingException ex) { return ""; } } } public String getSLOURL() { if (idpMetaAlias != null) { try { return idpBaseURL + "/saml2/jsp/idpSingleLogoutInit.jsp?metaAlias=" + URLEncoder.encode(idpMetaAlias, "UTF-8"); } catch (UnsupportedEncodingException ex) { return ""; } } else { try { return spBaseURL + "/saml2/jsp/spSingleLogoutInit.jsp?metaAlias=" + URLEncoder.encode(spMetaAlias, "UTF-8") + "&idpEntityID=" + URLEncoder.encode(idpEntityId, "UTF-8"); } catch (UnsupportedEncodingException ex) { return ""; } } } public String getAccountTerminationURL() { if (idpMetaAlias != null) { try { return idpBaseURL + "/saml2/jsp/idpMNIRequestInit.jsp?metaAlias=" + URLEncoder.encode(idpMetaAlias, "UTF-8") + "&spEntityID=" + URLEncoder.encode(spEntityId, "UTF-8") + "&requestType=Terminate"; } catch (UnsupportedEncodingException ex) { return ""; } } else { try { return spBaseURL + "/saml2/jsp/spMNIRequestInit.jsp?metaAlias=" + URLEncoder.encode(spMetaAlias, "UTF-8") + "&idpEntityID=" + URLEncoder.encode(idpEntityId, "UTF-8") + "&requestType=Terminate"; } catch (UnsupportedEncodingException ex) { return ""; } } } }