package com.rackspace.saml; import java.io.ByteArrayOutputStream; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.joda.time.DateTime; import org.opensaml.DefaultBootstrap; import org.opensaml.common.SAMLVersion; import org.opensaml.saml2.core.Assertion; import org.opensaml.saml2.core.Attribute; import org.opensaml.saml2.core.AttributeStatement; import org.opensaml.saml2.core.AttributeValue; import org.opensaml.saml2.core.AuthnContext; import org.opensaml.saml2.core.AuthnContextClassRef; import org.opensaml.saml2.core.AuthnRequest; import org.opensaml.saml2.core.AuthnStatement; import org.opensaml.saml2.core.Issuer; import org.opensaml.saml2.core.NameID; import org.opensaml.saml2.core.Response; import org.opensaml.saml2.core.Status; import org.opensaml.saml2.core.StatusCode; import org.opensaml.saml2.core.Subject; import org.opensaml.saml2.core.SubjectConfirmation; import org.opensaml.saml2.core.SubjectConfirmationData; import org.opensaml.saml2.core.impl.AssertionBuilder; import org.opensaml.saml2.core.impl.AttributeBuilder; import org.opensaml.saml2.core.impl.AttributeStatementBuilder; import org.opensaml.saml2.core.impl.AuthnContextBuilder; import org.opensaml.saml2.core.impl.AuthnContextClassRefBuilder; import org.opensaml.saml2.core.impl.AuthnStatementBuilder; import org.opensaml.saml2.core.impl.IssuerBuilder; import org.opensaml.saml2.core.impl.NameIDBuilder; import org.opensaml.saml2.core.impl.ResponseBuilder; import org.opensaml.saml2.core.impl.ResponseMarshaller; import org.opensaml.saml2.core.impl.StatusBuilder; import org.opensaml.saml2.core.impl.StatusCodeBuilder; import org.opensaml.saml2.core.impl.SubjectBuilder; import org.opensaml.saml2.core.impl.SubjectConfirmationBuilder; import org.opensaml.saml2.core.impl.SubjectConfirmationDataBuilder; import org.opensaml.xml.schema.XSString; import org.opensaml.xml.schema.impl.XSStringBuilder; import org.opensaml.xml.signature.Signature; import org.opensaml.xml.signature.SignatureConstants; import org.opensaml.xml.signature.Signer; import org.opensaml.xml.signature.impl.SignatureBuilder; import org.opensaml.xml.util.XMLHelper; import org.w3c.dom.Element; public class SamlAssertionProducer { private String privateKeyLocation; private String publicKeyLocation; private CertManager certManager = new CertManager(); public Response createSAMLResponse(final String subjectId, final DateTime authenticationTime, final String credentialType, final HashMap<String, List<String>> attributes, String issuer, Integer samlAssertionDays) { try { DefaultBootstrap.bootstrap(); Signature signature = createSignature(); Status status = createStatus(); Issuer responseIssuer = null; Issuer assertionIssuer = null; Subject subject = null; AttributeStatement attributeStatement = null; if (issuer != null) { responseIssuer = createIssuer(issuer); assertionIssuer = createIssuer(issuer); } if (subjectId != null) { subject = createSubject(subjectId, samlAssertionDays); } if (attributes != null && attributes.size() != 0) { attributeStatement = createAttributeStatement(attributes); } AuthnStatement authnStatement = createAuthnStatement(authenticationTime); Assertion assertion = createAssertion(new DateTime(), subject, assertionIssuer, authnStatement, attributeStatement); Response response = createResponse(new DateTime(), responseIssuer, status, assertion); response.setSignature(signature); ResponseMarshaller marshaller = new ResponseMarshaller(); Element element = marshaller.marshall(response); if (signature != null) { Signer.signObject(signature); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); XMLHelper.writeNode(element, baos); return response; } catch (Throwable t) { t.printStackTrace(); return null; } } public String getPrivateKeyLocation() { return privateKeyLocation; } public void setPrivateKeyLocation(String privateKeyLocation) { this.privateKeyLocation = privateKeyLocation; } public String getPublicKeyLocation() { return publicKeyLocation; } public void setPublicKeyLocation(String publicKeyLocation) { this.publicKeyLocation = publicKeyLocation; } private Response createResponse(final DateTime issueDate, Issuer issuer, Status status, Assertion assertion) { ResponseBuilder responseBuilder = new ResponseBuilder(); Response response = responseBuilder.buildObject(); response.setID(UUID.randomUUID().toString()); response.setIssueInstant(issueDate); response.setVersion(SAMLVersion.VERSION_20); response.setIssuer(issuer); response.setStatus(status); response.getAssertions().add(assertion); return response; } private Assertion createAssertion(final DateTime issueDate, Subject subject, Issuer issuer, AuthnStatement authnStatement, AttributeStatement attributeStatement) { AssertionBuilder assertionBuilder = new AssertionBuilder(); Assertion assertion = assertionBuilder.buildObject(); assertion.setID(UUID.randomUUID().toString()); assertion.setIssueInstant(issueDate); assertion.setSubject(subject); assertion.setIssuer(issuer); if (authnStatement != null) assertion.getAuthnStatements().add(authnStatement); if (attributeStatement != null) assertion.getAttributeStatements().add(attributeStatement); return assertion; } private Issuer createIssuer(final String issuerName) { // create Issuer object IssuerBuilder issuerBuilder = new IssuerBuilder(); Issuer issuer = issuerBuilder.buildObject(); issuer.setValue(issuerName); return issuer; } private Subject createSubject(final String subjectId, final Integer samlAssertionDays) { DateTime currentDate = new DateTime(); if (samlAssertionDays != null) currentDate = currentDate.plusDays(samlAssertionDays); // create name element NameIDBuilder nameIdBuilder = new NameIDBuilder(); NameID nameId = nameIdBuilder.buildObject(); nameId.setValue(subjectId); nameId.setFormat("urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"); SubjectConfirmationDataBuilder dataBuilder = new SubjectConfirmationDataBuilder(); SubjectConfirmationData subjectConfirmationData = dataBuilder.buildObject(); subjectConfirmationData.setNotOnOrAfter(currentDate); SubjectConfirmationBuilder subjectConfirmationBuilder = new SubjectConfirmationBuilder(); SubjectConfirmation subjectConfirmation = subjectConfirmationBuilder.buildObject(); subjectConfirmation.setMethod("urn:oasis:names:tc:SAML:2.0:cm:bearer"); subjectConfirmation.setSubjectConfirmationData(subjectConfirmationData); // create subject element SubjectBuilder subjectBuilder = new SubjectBuilder(); Subject subject = subjectBuilder.buildObject(); subject.setNameID(nameId); subject.getSubjectConfirmations().add(subjectConfirmation); return subject; } private AuthnStatement createAuthnStatement(final DateTime issueDate) { // create authcontextclassref object AuthnContextClassRefBuilder classRefBuilder = new AuthnContextClassRefBuilder(); AuthnContextClassRef classRef = classRefBuilder.buildObject(); classRef.setAuthnContextClassRef("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"); // create authcontext object AuthnContextBuilder authContextBuilder = new AuthnContextBuilder(); AuthnContext authnContext = authContextBuilder.buildObject(); authnContext.setAuthnContextClassRef(classRef); // create authenticationstatement object AuthnStatementBuilder authStatementBuilder = new AuthnStatementBuilder(); AuthnStatement authnStatement = authStatementBuilder.buildObject(); authnStatement.setAuthnInstant(issueDate); authnStatement.setAuthnContext(authnContext); return authnStatement; } private AttributeStatement createAttributeStatement(HashMap<String, List<String>> attributes) { // create authenticationstatement object AttributeStatementBuilder attributeStatementBuilder = new AttributeStatementBuilder(); AttributeStatement attributeStatement = attributeStatementBuilder.buildObject(); AttributeBuilder attributeBuilder = new AttributeBuilder(); if (attributes != null) { for (Map.Entry<String, List<String>> entry : attributes.entrySet()) { Attribute attribute = attributeBuilder.buildObject(); attribute.setName(entry.getKey()); for (String value : entry.getValue()) { XSStringBuilder stringBuilder = new XSStringBuilder(); XSString attributeValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME); attributeValue.setValue(value); attribute.getAttributeValues().add(attributeValue); } attributeStatement.getAttributes().add(attribute); } } return attributeStatement; } private Status createStatus() { StatusCodeBuilder statusCodeBuilder = new StatusCodeBuilder(); StatusCode statusCode = statusCodeBuilder.buildObject(); statusCode.setValue(StatusCode.SUCCESS_URI); StatusBuilder statusBuilder = new StatusBuilder(); Status status = statusBuilder.buildObject(); status.setStatusCode(statusCode); return status; } private Signature createSignature() throws Throwable { if (publicKeyLocation != null && privateKeyLocation != null) { SignatureBuilder builder = new SignatureBuilder(); Signature signature = builder.buildObject(); signature.setSigningCredential(certManager.getSigningCredential(publicKeyLocation, privateKeyLocation)); signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1); signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); return signature; } return null; } }