diff --git a/components/agents/org.wso2.carbon.identity.sso.agent/src/main/java/org/wso2/carbon/identity/sso/agent/bean/LoggedInSessionBean.java b/components/agents/org.wso2.carbon.identity.sso.agent/src/main/java/org/wso2/carbon/identity/sso/agent/bean/LoggedInSessionBean.java index 2dfa5c16d2..3228466a0d 100644 --- a/components/agents/org.wso2.carbon.identity.sso.agent/src/main/java/org/wso2/carbon/identity/sso/agent/bean/LoggedInSessionBean.java +++ b/components/agents/org.wso2.carbon.identity.sso.agent/src/main/java/org/wso2/carbon/identity/sso/agent/bean/LoggedInSessionBean.java @@ -22,11 +22,16 @@ import org.openid4java.discovery.DiscoveryInformation; import org.opensaml.saml2.core.Assertion; import org.opensaml.saml2.core.Response; +import org.wso2.carbon.identity.sso.agent.SSOAgentException; +import org.wso2.carbon.identity.sso.agent.util.SSOAgentUtils; +import java.io.IOException; +import java.io.Serializable; +import java.util.HashMap; import java.util.List; import java.util.Map; -public class LoggedInSessionBean { +public class LoggedInSessionBean implements Serializable{ private OpenID openId; @@ -48,7 +53,7 @@ public void setOpenId(OpenID openId) { this.openId = openId; } - public static class AccessTokenResponseBean { + public static class AccessTokenResponseBean implements Serializable{ private String accessToken; @@ -94,6 +99,11 @@ public String toString() { Gson gson = new Gson(); return gson.toJson(this); } + + public AccessTokenResponseBean deSerialize(String accessTokenResponseBeanString) { + Gson gson = new Gson(); + return gson.fromJson(accessTokenResponseBeanString, AccessTokenResponseBean.class); + } } public class OpenID { @@ -129,7 +139,7 @@ public void setSubjectAttributes(Map> subjectAttributes) { } } - public class SAML2SSO { + public class SAML2SSO implements Serializable{ private String subjectId; @@ -147,6 +157,49 @@ public class SAML2SSO { private Map subjectAttributes; + private void writeObject(java.io.ObjectOutputStream stream) + throws IOException { + + stream.writeObject(subjectId); + + stream.writeObject(responseString); + + stream.writeObject(assertionString); + + stream.writeObject(sessionIndex); + if (accessTokenResponseBean != null) { + stream.writeObject(accessTokenResponseBean.toString()); + } else { + stream.writeObject(""); + } + stream.writeObject(subjectAttributes); + } + + private void readObject(java.io.ObjectInputStream stream) + throws IOException, ClassNotFoundException, SSOAgentException { + + subjectId = (String) stream.readObject(); + + responseString = (String) stream.readObject(); + if (responseString != null && !"".equals(responseString)) { + response = (Response) SSOAgentUtils.unmarshall(responseString); + } + + assertionString = (String) stream.readObject(); + if (responseString != null && !"".equals(assertionString)) { + assertion = (Assertion) SSOAgentUtils.unmarshall(assertionString); + } + + sessionIndex = (String) stream.readObject(); + String accessTokenResponseBeanString = (String) stream.readObject(); + if (!"".equals(accessTokenResponseBeanString)) { + accessTokenResponseBean = accessTokenResponseBean.deSerialize(accessTokenResponseBeanString); + } else { + accessTokenResponseBean = null; + } + subjectAttributes = (Map) stream.readObject(); + } + public String getSubjectId() { return subjectId; } diff --git a/components/agents/org.wso2.carbon.identity.sso.agent/src/main/java/org/wso2/carbon/identity/sso/agent/saml/SAML2SSOManager.java b/components/agents/org.wso2.carbon.identity.sso.agent/src/main/java/org/wso2/carbon/identity/sso/agent/saml/SAML2SSOManager.java index d10120a4bc..447c422030 100644 --- a/components/agents/org.wso2.carbon.identity.sso.agent/src/main/java/org/wso2/carbon/identity/sso/agent/saml/SAML2SSOManager.java +++ b/components/agents/org.wso2.carbon.identity.sso.agent/src/main/java/org/wso2/carbon/identity/sso/agent/saml/SAML2SSOManager.java @@ -19,11 +19,9 @@ package org.wso2.carbon.identity.sso.agent.saml; import org.apache.xerces.impl.Constants; -import org.apache.xerces.util.SecurityManager; import org.apache.xml.security.signature.XMLSignature; import org.joda.time.DateTime; import org.opensaml.Configuration; -import org.opensaml.DefaultBootstrap; import org.opensaml.common.SAMLVersion; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.common.Extensions; @@ -31,10 +29,11 @@ import org.opensaml.saml2.core.impl.*; import org.opensaml.saml2.ecp.RelayState; import org.opensaml.saml2.encryption.Decrypter; -import org.opensaml.xml.ConfigurationException; import org.opensaml.xml.XMLObject; import org.opensaml.xml.encryption.EncryptedKey; -import org.opensaml.xml.io.*; +import org.opensaml.xml.io.Marshaller; +import org.opensaml.xml.io.MarshallerFactory; +import org.opensaml.xml.io.MarshallingException; import org.opensaml.xml.security.SecurityHelper; import org.opensaml.xml.security.credential.Credential; import org.opensaml.xml.security.keyinfo.KeyInfoCredentialResolver; @@ -43,7 +42,6 @@ import org.opensaml.xml.util.Base64; import org.opensaml.xml.util.XMLHelper; import org.opensaml.xml.validation.ValidationException; -import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.bootstrap.DOMImplementationRegistry; import org.w3c.dom.ls.DOMImplementationLS; @@ -53,20 +51,17 @@ import org.wso2.carbon.identity.sso.agent.SSOAgentException; import org.wso2.carbon.identity.sso.agent.bean.LoggedInSessionBean; import org.wso2.carbon.identity.sso.agent.bean.SSOAgentConfig; -import org.wso2.carbon.identity.sso.agent.util.CarbonEntityResolver; import org.wso2.carbon.identity.sso.agent.util.SAMLSignatureValidator; import org.wso2.carbon.identity.sso.agent.util.SSOAgentUtils; -import org.xml.sax.SAXException; import javax.crypto.SecretKey; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.*; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.HashMap; import java.util.List; @@ -108,18 +103,7 @@ public SAML2SSOManager(SSOAgentConfig ssoAgentConfig) throws SSOAgentException { } catch (InstantiationException e) { throw new SSOAgentException("Error loading custom signature validator class", e); } - try { - if (!bootStrapped) { - synchronized (this) { - if (!bootStrapped) { - DefaultBootstrap.bootstrap(); - bootStrapped = true; - } - } - } - } catch (ConfigurationException e) { - throw new SSOAgentException("Error while bootstrapping OpenSAML library", e); - } + SSOAgentUtils.doBootstrap(); } /** @@ -280,7 +264,7 @@ public void processResponse(HttpServletRequest request, HttpServletResponse resp if (saml2SSOResponse != null) { String decodedResponse = new String(Base64.decode(saml2SSOResponse)); - XMLObject samlObject = unmarshall(decodedResponse); + XMLObject samlObject = SSOAgentUtils.unmarshall(decodedResponse); if (samlObject instanceof LogoutResponse) { //This is a SAML response for a single logout request from the SP doSLO(request); @@ -310,11 +294,11 @@ public void doSLO(HttpServletRequest request) throws SSOAgentException { XMLObject saml2Object = null; if (request.getParameter(SSOAgentConstants.SAML2SSO.HTTP_POST_PARAM_SAML2_AUTH_REQ) != null) { - saml2Object = unmarshall(new String(Base64.decode(request.getParameter( + saml2Object = SSOAgentUtils.unmarshall(new String(Base64.decode(request.getParameter( SSOAgentConstants.SAML2SSO.HTTP_POST_PARAM_SAML2_AUTH_REQ)))); } if (saml2Object == null) { - saml2Object = unmarshall(new String(Base64.decode(request.getParameter( + saml2Object = SSOAgentUtils.unmarshall(new String(Base64.decode(request.getParameter( SSOAgentConstants.SAML2SSO.HTTP_POST_PARAM_SAML2_RESP)))); } if (saml2Object instanceof LogoutRequest) { @@ -334,7 +318,12 @@ public void doSLO(HttpServletRequest request) throws SSOAgentException { Set sessions = SSOAgentSessionManager.invalidateAllSessions(request.getSession(false)); for (HttpSession session : sessions) { - session.invalidate(); + try { + session.invalidate(); + } catch (IllegalStateException ignore) { + //ignore + //session is already invalidated + } } } } else { @@ -350,7 +339,7 @@ protected void processSSOResponse(HttpServletRequest request) throws SSOAgentExc String saml2ResponseString = new String(Base64.decode(request.getParameter( SSOAgentConstants.SAML2SSO.HTTP_POST_PARAM_SAML2_RESP))); - Response saml2Response = (Response) unmarshall(saml2ResponseString); + Response saml2Response = (Response) SSOAgentUtils.unmarshall(saml2ResponseString); sessionBean.getSAML2SSO().setResponseString(saml2ResponseString); sessionBean.getSAML2SSO().setSAMLResponse(saml2Response); @@ -562,39 +551,6 @@ protected String encodeRequestMessage(RequestAbstractType requestMessage, String } } - protected XMLObject unmarshall(String saml2SSOString) throws SSOAgentException { - - try { - String decodedString = decodeHTMLCharacters(saml2SSOString); - DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); - documentBuilderFactory.setNamespaceAware(true); - - documentBuilderFactory.setExpandEntityReferences(false); - documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - SecurityManager securityManager = new SecurityManager(); - securityManager.setEntityExpansionLimit(ENTITY_EXPANSION_LIMIT); - documentBuilderFactory.setAttribute(SECURITY_MANAGER_PROPERTY, securityManager); - - DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder(); - docBuilder.setEntityResolver(new CarbonEntityResolver()); - ByteArrayInputStream is = new ByteArrayInputStream(decodedString.getBytes()); - Document document = docBuilder.parse(is); - Element element = document.getDocumentElement(); - UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory(); - Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(element); - return unmarshaller.unmarshall(element); - } catch (ParserConfigurationException e) { - throw new SSOAgentException("Error in unmarshalling SAML2SSO Request from the encoded String", e); - } catch (UnmarshallingException e) { - throw new SSOAgentException("Error in unmarshalling SAML2SSO Request from the encoded String", e); - } catch (SAXException e) { - throw new SSOAgentException("Error in unmarshalling SAML2SSO Request from the encoded String", e); - } catch (IOException e) { - throw new SSOAgentException("Error in unmarshalling SAML2SSO Request from the encoded String", e); - } - - } - private String decodeHTMLCharacters(String encodedStr) { return encodedStr.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">") diff --git a/components/agents/org.wso2.carbon.identity.sso.agent/src/main/java/org/wso2/carbon/identity/sso/agent/util/SSOAgentUtils.java b/components/agents/org.wso2.carbon.identity.sso.agent/src/main/java/org/wso2/carbon/identity/sso/agent/util/SSOAgentUtils.java index 2d454239fa..5926c4c561 100644 --- a/components/agents/org.wso2.carbon.identity.sso.agent/src/main/java/org/wso2/carbon/identity/sso/agent/util/SSOAgentUtils.java +++ b/components/agents/org.wso2.carbon.identity.sso.agent/src/main/java/org/wso2/carbon/identity/sso/agent/util/SSOAgentUtils.java @@ -20,24 +20,33 @@ import org.apache.xml.security.c14n.Canonicalizer; import org.apache.xml.security.signature.XMLSignature; +import org.opensaml.Configuration; +import org.opensaml.DefaultBootstrap; import org.opensaml.saml2.core.AuthnRequest; import org.opensaml.saml2.core.LogoutRequest; +import org.opensaml.xml.ConfigurationException; import org.opensaml.xml.XMLObject; import org.opensaml.xml.XMLObjectBuilder; -import org.opensaml.xml.io.Marshaller; -import org.opensaml.xml.io.MarshallerFactory; +import org.opensaml.xml.io.*; import org.opensaml.xml.security.x509.X509Credential; import org.opensaml.xml.signature.KeyInfo; import org.opensaml.xml.signature.Signature; import org.opensaml.xml.signature.Signer; import org.opensaml.xml.signature.X509Data; import org.opensaml.xml.util.Base64; +import org.w3c.dom.Document; +import org.w3c.dom.Element; import org.wso2.carbon.identity.sso.agent.SSOAgentConstants; import org.wso2.carbon.identity.sso.agent.SSOAgentException; +import org.xml.sax.SAXException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.Writer; import java.net.URLEncoder; @@ -51,6 +60,7 @@ public class SSOAgentUtils { private static Logger LOGGER = Logger.getLogger(SSOAgentConstants.LOGGER_NAME); + private static boolean isBootStrapped = false; /** * Generates a unique Id for Authentication Requests @@ -78,6 +88,17 @@ public static String createID() { return String.valueOf(chars); } + public static void doBootstrap() throws SSOAgentException { + if (!isBootStrapped) { + try { + DefaultBootstrap.bootstrap(); + isBootStrapped = true; + } catch (ConfigurationException e) { + throw new SSOAgentException("Error in bootstrapping the OpenSAML2 library", e); + } + } + } + /** * Sign the SAML AuthnRequest message * @@ -88,7 +109,8 @@ public static String createID() { * @throws org.wso2.carbon.identity.sso.agent.SSOAgentException */ public static AuthnRequest setSignature(AuthnRequest authnRequest, String signatureAlgorithm, - X509Credential cred) throws SSOAgentException { + X509Credential cred) throws SSOAgentException { + doBootstrap(); try { Signature signature = (Signature) buildXMLObject(Signature.DEFAULT_ELEMENT_NAME); signature.setSigningCredential(cred); @@ -186,6 +208,7 @@ public static LogoutRequest setSignature(LogoutRequest logoutRequest, String sig public static void addDeflateSignatureToHTTPQueryString(StringBuilder httpQueryString, X509Credential cred) throws SSOAgentException { + doBootstrap(); try { httpQueryString.append("&SigAlg=" + URLEncoder.encode(XMLSignature.ALGO_ID_SIGNATURE_RSA, "UTF-8").trim()); @@ -212,6 +235,7 @@ public static void addDeflateSignatureToHTTPQueryString(StringBuilder httpQueryS * @throws SSOAgentException */ private static XMLObject buildXMLObject(QName objectQName) throws SSOAgentException { + doBootstrap(); XMLObjectBuilder builder = org.opensaml.xml.Configuration.getBuilderFactory() .getBuilder(objectQName); @@ -244,4 +268,31 @@ public static void sendPostResponse(HttpServletRequest request, HttpServletRespo } } } + + public static XMLObject unmarshall(String saml2SSOString) throws SSOAgentException { + + doBootstrap(); + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setExpandEntityReferences(false); + documentBuilderFactory.setNamespaceAware(true); + try { + DocumentBuilder docBuilder = documentBuilderFactory.newDocumentBuilder(); + docBuilder.setEntityResolver(new CarbonEntityResolver()); + ByteArrayInputStream is = new ByteArrayInputStream(saml2SSOString.getBytes()); + Document document = docBuilder.parse(is); + Element element = document.getDocumentElement(); + UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory(); + Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(element); + return unmarshaller.unmarshall(element); + } catch (ParserConfigurationException e) { + throw new SSOAgentException("Error in unmarshalling SAML2SSO Request from the encoded String", e); + } catch (UnmarshallingException e) { + throw new SSOAgentException("Error in unmarshalling SAML2SSO Request from the encoded String", e); + } catch (SAXException e) { + throw new SSOAgentException("Error in unmarshalling SAML2SSO Request from the encoded String", e); + } catch (IOException e) { + throw new SSOAgentException("Error in unmarshalling SAML2SSO Request from the encoded String", e); + } + + } }