Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ivy.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<ivy-module version="2.0">
<info organisation="com.lastpass" module="saml-sdk-java"/>
<dependencies>
<dependency org="org.opensaml" name="opensaml" rev="2.6.1"/>
<dependency org="org.opensaml" name="opensaml-saml-impl" rev="3.1.1"/>
</dependencies>
</ivy-module>
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
<dependencies>
<dependency>
<groupId>org.opensaml</groupId>
<artifactId>opensaml</artifactId>
<version>2.6.4</version>
<artifactId>opensaml-saml-impl</artifactId>
<version>3.1.1</version>
</dependency>
</dependencies>
</project>
51 changes: 24 additions & 27 deletions src/main/java/com/lastpass/saml/IdPConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@
import java.io.FileInputStream;
import java.io.InputStream;

import org.opensaml.Configuration;
import org.opensaml.xml.parse.BasicParserPool;
import org.opensaml.xml.io.UnmarshallerFactory;
import org.opensaml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml2.metadata.IDPSSODescriptor;
import org.opensaml.saml2.metadata.SingleSignOnService;
import org.opensaml.saml2.metadata.KeyDescriptor;
import org.opensaml.xml.signature.KeyInfo;
import org.opensaml.xml.signature.X509Data;
import org.opensaml.xml.signature.X509Certificate;
import org.opensaml.xml.security.credential.UsageType;
import org.opensaml.common.xml.SAMLConstants;

import javax.xml.bind.DatatypeConverter;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.xml.BasicParserPool;
import net.shibboleth.utilities.java.support.xml.XMLParserException;
import org.opensaml.core.xml.io.UnmarshallingException;
import org.opensaml.core.xml.util.XMLObjectSupport;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.config.SAMLConfiguration;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml.saml2.metadata.IDPSSODescriptor;
import org.opensaml.saml.saml2.metadata.KeyDescriptor;
import org.opensaml.saml.saml2.metadata.SingleSignOnService;
import org.opensaml.security.credential.UsageType;
import org.opensaml.xmlsec.signature.KeyInfo;
import org.opensaml.xmlsec.signature.X509Certificate;
import org.opensaml.xmlsec.signature.X509Data;

import org.w3c.dom.Document;
import org.w3c.dom.Element;


/**
Expand Down Expand Up @@ -110,30 +110,27 @@ private void init(InputStream inputStream)
{
BasicParserPool parsers = new BasicParserPool();
parsers.setNamespaceAware(true);
try {
parsers.initialize();
} catch (ComponentInitializationException e) {
throw new SAMLException("Failed to initialize BasicParserPool", e);
}

EntityDescriptor edesc;

try {
Document doc = parsers.parse(inputStream);
Element root = doc.getDocumentElement();

UnmarshallerFactory unmarshallerFactory =
Configuration.getUnmarshallerFactory();

edesc = (EntityDescriptor) unmarshallerFactory
.getUnmarshaller(root)
.unmarshall(root);
edesc = (EntityDescriptor) XMLObjectSupport.unmarshallFromInputStream(parsers, inputStream);
}
catch (org.opensaml.xml.parse.XMLParserException e) {
catch (XMLParserException e) {
throw new SAMLException(e);
}
catch (org.opensaml.xml.io.UnmarshallingException e) {
catch (UnmarshallingException e) {
throw new SAMLException(e);
}

// fetch idp information
IDPSSODescriptor idpDesc = edesc.getIDPSSODescriptor(
"urn:oasis:names:tc:SAML:2.0:protocol");
SAMLConstants.SAML20P_NS);

if (idpDesc == null)
throw new SAMLException("No IDP SSO descriptor found");
Expand Down
139 changes: 65 additions & 74 deletions src/main/java/com/lastpass/saml/SAMLClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,11 @@
*/
package com.lastpass.saml;

import org.opensaml.Configuration;
import org.opensaml.saml2.core.Response;
import org.opensaml.saml2.core.Subject;
import org.opensaml.saml2.core.Conditions;
import org.opensaml.saml2.core.AuthnStatement;
import org.opensaml.saml2.core.AuthnRequest;
import org.opensaml.saml2.core.Assertion;
import org.opensaml.saml2.core.Issuer;
import org.opensaml.saml2.core.Audience;
import org.opensaml.saml2.core.AudienceRestriction;
import org.opensaml.saml2.core.StatusCode;
import org.opensaml.saml2.core.SubjectConfirmation;
import org.opensaml.saml2.core.SubjectConfirmationData;

import org.opensaml.saml2.core.AttributeStatement;
import org.opensaml.saml2.core.Attribute;

import org.opensaml.common.SAMLObjectBuilder;

import org.opensaml.xml.parse.BasicParserPool;
import org.opensaml.xml.io.MarshallingException;
import org.opensaml.xml.security.credential.BasicCredential;
import org.opensaml.xml.signature.SignatureValidator;
import org.opensaml.xml.signature.Signature;
import org.opensaml.xml.validation.ValidationException;
import org.opensaml.xml.XMLObjectBuilderFactory;
import org.opensaml.xml.XMLObject;


import org.joda.time.DateTime;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;
import java.io.StringReader;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
Expand All @@ -63,6 +33,34 @@
import java.util.zip.Deflater;

import javax.xml.bind.DatatypeConverter;
import javax.xml.bind.ValidationException;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.xml.BasicParserPool;
import net.shibboleth.utilities.java.support.xml.SerializeSupport;
import net.shibboleth.utilities.java.support.xml.XMLParserException;
import org.opensaml.core.xml.XMLObject;
import org.opensaml.core.xml.io.MarshallingException;
import org.opensaml.core.xml.io.UnmarshallingException;
import org.opensaml.core.xml.util.XMLObjectSupport;
import org.opensaml.saml.common.SAMLObjectBuilder;
import org.opensaml.saml.saml2.core.Assertion;
import org.opensaml.saml.saml2.core.Attribute;
import org.opensaml.saml.saml2.core.AttributeStatement;
import org.opensaml.saml.saml2.core.Audience;
import org.opensaml.saml.saml2.core.AudienceRestriction;
import org.opensaml.saml.saml2.core.AuthnRequest;
import org.opensaml.saml.saml2.core.AuthnStatement;
import org.opensaml.saml.saml2.core.Conditions;
import org.opensaml.saml.saml2.core.Issuer;
import org.opensaml.saml.saml2.core.Response;
import org.opensaml.saml.saml2.core.StatusCode;
import org.opensaml.saml.saml2.core.Subject;
import org.opensaml.saml.saml2.core.SubjectConfirmation;
import org.opensaml.saml.saml2.core.SubjectConfirmationData;
import org.opensaml.security.credential.BasicCredential;
import org.opensaml.xmlsec.signature.Signature;
import org.opensaml.xmlsec.signature.support.SignatureException;
import org.opensaml.xmlsec.signature.support.SignatureValidator;


/**
Expand Down Expand Up @@ -90,12 +88,13 @@ public class SAMLClient
{
private SPConfig spConfig;
private IdPConfig idpConfig;
private SignatureValidator sigValidator;
private BasicParserPool parsers;
private final BasicCredential cred;

/* do date comparisons +/- this many seconds */
private static final int slack = 300;


/**
* Create a new SAMLClient, using the IdPConfig for
* endpoints and validation.
Expand All @@ -106,15 +105,17 @@ public SAMLClient(SPConfig spConfig, IdPConfig idpConfig)
this.spConfig = spConfig;
this.idpConfig = idpConfig;

BasicCredential cred = new BasicCredential();
cred.setEntityId(idpConfig.getEntityId());
cred.setPublicKey(idpConfig.getCert().getPublicKey());

sigValidator = new SignatureValidator(cred);
cred = new BasicCredential(idpConfig.getCert().getPublicKey());
cred.setEntityId(idpConfig.getEntityId());

// create xml parsers
parsers = new BasicParserPool();
parsers.setNamespaceAware(true);
try {
parsers.initialize();
} catch (ComponentInitializationException e) {
throw new SAMLException("Failed to initialize BasicParserPool", e);
}
}

/**
Expand All @@ -141,40 +142,38 @@ private Response parseResponse(String authnResponse)
throws SAMLException
{
try {
Document doc = parsers.getBuilder()
.parse(new InputSource(new StringReader(authnResponse)));
XMLObject obj
= XMLObjectSupport.
unmarshallFromReader(parsers, new StringReader(authnResponse));

Element root = doc.getDocumentElement();
return (Response) Configuration.getUnmarshallerFactory()
.getUnmarshaller(root)
.unmarshall(root);
}
catch (org.opensaml.xml.parse.XMLParserException e) {
throw new SAMLException(e);
return (Response) obj;
}
catch (org.opensaml.xml.io.UnmarshallingException e) {
catch (XMLParserException e) {
throw new SAMLException(e);
}
catch (org.xml.sax.SAXException e) {
catch (UnmarshallingException e) {
throw new SAMLException(e);
}
catch (java.io.IOException e) {
throw new SAMLException(e);
}
}
}

private void validate(Response response)
throws ValidationException
{
// response signature must match IdP's key, if present
Signature sig = response.getSignature();
if (sig != null)
sigValidator.validate(sig);
if (sig != null)
{
try {
SignatureValidator.validate(sig, cred);
} catch (SignatureException ex) {
throw new ValidationException("Signature validation failed", ex);
}
}

// response must be successful
if (response.getStatus() == null ||
response.getStatus().getStatusCode() == null ||
!(StatusCode.SUCCESS_URI
!(StatusCode.SUCCESS
.equals(response.getStatus().getStatusCode().getValue()))) {
throw new ValidationException(
"Response has an unsuccessful status code");
Expand Down Expand Up @@ -208,7 +207,11 @@ private void validate(Response response)
"Assertion must be signed");

sig = assertion.getSignature();
sigValidator.validate(sig);
try {
SignatureValidator.validate(sig, cred);
} catch (SignatureException e) {
throw new ValidationException("Assertion signature validation failed", e);
}

// Assertion must contain an authnstatement
// with an unexpired session
Expand Down Expand Up @@ -323,15 +326,12 @@ private void validate(Response response)
private String createAuthnRequest(String requestId)
throws SAMLException
{
XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();

SAMLObjectBuilder<AuthnRequest> builder =
(SAMLObjectBuilder<AuthnRequest>) builderFactory
.getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME);
(SAMLObjectBuilder<AuthnRequest>)
XMLObjectSupport.getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME);

SAMLObjectBuilder<Issuer> issuerBuilder =
(SAMLObjectBuilder<Issuer>) builderFactory
.getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
(SAMLObjectBuilder<Issuer>) XMLObjectSupport.getBuilder(Issuer.DEFAULT_ELEMENT_NAME);

AuthnRequest request = builder.buildObject();
request.setAssertionConsumerServiceURL(spConfig.getAcs().toString());
Expand All @@ -344,18 +344,9 @@ private String createAuthnRequest(String requestId)
request.setIssuer(issuer);

try {
// samlobject to xml dom object
Element elem = Configuration.getMarshallerFactory()
.getMarshaller(request)
.marshall(request);

// and to a string...
Document document = elem.getOwnerDocument();
DOMImplementationLS domImplLS = (DOMImplementationLS) document
.getImplementation();
LSSerializer serializer = domImplLS.createLSSerializer();
serializer.getDomConfig().setParameter("xml-declaration", false);
return serializer.writeToString(elem);
Element element = XMLObjectSupport.marshall(request);

return SerializeSupport.nodeToString(element);
}
catch (MarshallingException e) {
throw new SAMLException(e);
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/lastpass/saml/SAMLInit.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
*/
package com.lastpass.saml;

import org.opensaml.DefaultBootstrap;
import org.opensaml.xml.ConfigurationException;
import org.opensaml.core.config.InitializationException;
import org.opensaml.core.config.InitializationService;

/**
* Library initialization routines.
Expand All @@ -35,8 +35,8 @@ public static void initialize()
throws SAMLException
{
try {
DefaultBootstrap.bootstrap();
} catch (ConfigurationException e) {
InitializationService.initialize();
} catch (InitializationException e) {
throw new SAMLException(e);
}
}
Expand Down
Loading