First public commit
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,5 +8,7 @@
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# Maven target #
|
||||
target/
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
52
pom.xml
Normal file
52
pom.xml
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>no.steras.opensamlbook</groupId>
|
||||
<artifactId>webprofile-ref-project</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.opensaml</groupId>
|
||||
<artifactId>opensaml</artifactId>
|
||||
<version>2.6.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.xerces</groupId>
|
||||
<artifactId>xercesImpl</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xerces</groupId>
|
||||
<artifactId>xercesImpl</artifactId>
|
||||
<version>2.10.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-core</artifactId>
|
||||
<version>1.0.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<version>1.0.13</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<version>2.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>Shibboleth repo</id>
|
||||
<url>https://build.shibboleth.net/nexus/content/repositories/releases</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
||||
101
src/main/java/no/steras/opensamlbook/OpenSAMLUtils.java
Normal file
101
src/main/java/no/steras/opensamlbook/OpenSAMLUtils.java
Normal file
@@ -0,0 +1,101 @@
|
||||
package no.steras.opensamlbook;
|
||||
|
||||
import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
|
||||
import org.opensaml.ws.soap.soap11.Body;
|
||||
import org.opensaml.ws.soap.soap11.Envelope;
|
||||
import org.opensaml.xml.Configuration;
|
||||
import org.opensaml.xml.XMLObject;
|
||||
import org.opensaml.xml.XMLObjectBuilderFactory;
|
||||
import org.opensaml.xml.io.Marshaller;
|
||||
import org.opensaml.xml.io.MarshallingException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.StringWriter;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Created by Privat on 4/6/14.
|
||||
*/
|
||||
public class OpenSAMLUtils {
|
||||
private static Logger logger = LoggerFactory.getLogger(OpenSAMLUtils.class);
|
||||
private static SecureRandomIdentifierGenerator secureRandomIdGenerator;
|
||||
|
||||
static {
|
||||
try {
|
||||
secureRandomIdGenerator = new SecureRandomIdentifierGenerator();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T buildSAMLObject(final Class<T> clazz) {
|
||||
T object = null;
|
||||
try {
|
||||
XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory();
|
||||
QName defaultElementName = (QName)clazz.getDeclaredField("DEFAULT_ELEMENT_NAME").get(null);
|
||||
object = (T)builderFactory.getBuilder(defaultElementName).buildObject(defaultElementName);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new IllegalArgumentException("Could not create SAML object");
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new IllegalArgumentException("Could not create SAML object");
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
public static String generateSecureRandomId() {
|
||||
return secureRandomIdGenerator.generateIdentifier();
|
||||
}
|
||||
|
||||
public static void logSAMLObject(final XMLObject object) {
|
||||
try {
|
||||
DocumentBuilder builder;
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
|
||||
builder = factory.newDocumentBuilder();
|
||||
|
||||
Document document = builder.newDocument();
|
||||
Marshaller out = Configuration.getMarshallerFactory().getMarshaller(object);
|
||||
out.marshall(object, document);
|
||||
|
||||
Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
StreamResult result = new StreamResult(new StringWriter());
|
||||
DOMSource source = new DOMSource(document);
|
||||
transformer.transform(source, result);
|
||||
String xmlString = result.getWriter().toString();
|
||||
|
||||
logger.info(xmlString);
|
||||
} catch (ParserConfigurationException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
} catch (MarshallingException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
} catch (TransformerException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Envelope wrapInSOAPEnvelope(final XMLObject xmlObject) throws IllegalAccessException {
|
||||
Envelope envelope = OpenSAMLUtils.buildSAMLObject(Envelope.class);
|
||||
Body body = OpenSAMLUtils.buildSAMLObject(Body.class);
|
||||
|
||||
body.getUnknownXMLObjects().add(xmlObject);
|
||||
|
||||
envelope.setBody(body);
|
||||
|
||||
return envelope;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package no.steras.opensamlbook.app;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This servlet acts as the resource that the access filter is protecting
|
||||
*/
|
||||
public class ApplicationServlet extends HttpServlet {
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
resp.setContentType("text/html");
|
||||
resp.getWriter().append("<h1>You are now at the requested resource</h1>");
|
||||
resp.getWriter().append("This is the protected resource. You are authenticated");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
package no.steras.opensamlbook.idp;
|
||||
|
||||
import no.steras.opensamlbook.OpenSAMLUtils;
|
||||
import no.steras.opensamlbook.sp.SPConstants;
|
||||
import no.steras.opensamlbook.sp.SPCredentials;
|
||||
import org.apache.xml.security.utils.EncryptionConstants;
|
||||
import org.joda.time.DateTime;
|
||||
import org.opensaml.common.SAMLObject;
|
||||
import org.opensaml.common.impl.SecureRandomIdentifierGenerator;
|
||||
import org.opensaml.saml2.core.*;
|
||||
import org.opensaml.saml2.encryption.Encrypter;
|
||||
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
|
||||
import org.opensaml.security.SAMLSignatureProfileValidator;
|
||||
import org.opensaml.ws.soap.soap11.Body;
|
||||
import org.opensaml.ws.soap.soap11.Envelope;
|
||||
import org.opensaml.xml.Configuration;
|
||||
import org.opensaml.xml.XMLObject;
|
||||
import org.opensaml.xml.encryption.EncryptionException;
|
||||
import org.opensaml.xml.encryption.EncryptionParameters;
|
||||
import org.opensaml.xml.encryption.KeyEncryptionParameters;
|
||||
import org.opensaml.xml.io.*;
|
||||
import org.opensaml.xml.parse.BasicParserPool;
|
||||
import org.opensaml.xml.parse.XMLParserException;
|
||||
import org.opensaml.xml.schema.XSString;
|
||||
import org.opensaml.xml.schema.impl.XSStringBuilder;
|
||||
import org.opensaml.xml.security.keyinfo.KeyInfoGeneratorFactory;
|
||||
import org.opensaml.xml.signature.*;
|
||||
import org.opensaml.xml.validation.ValidationException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.spec.ECField;
|
||||
|
||||
/**
|
||||
* Created by Privat on 4/6/14.
|
||||
*/
|
||||
public class ArtifactResolutionServlet extends HttpServlet {
|
||||
private static Logger logger = LoggerFactory.getLogger(ArtifactResolutionServlet.class);
|
||||
|
||||
@Override
|
||||
protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
|
||||
ArtifactResponse artifactResponse = buildArtifactResponse();
|
||||
artifactResponse.setInResponseTo("Made up ID");
|
||||
|
||||
printSAMLObject(wrapInSOAPEnvelope(artifactResponse), resp.getWriter());
|
||||
}
|
||||
|
||||
public static ArtifactResolve unmarshallArtifactResolve(final InputStream input) {
|
||||
try {
|
||||
BasicParserPool ppMgr = new BasicParserPool();
|
||||
ppMgr.setNamespaceAware(true);
|
||||
|
||||
Document soap = ppMgr.parse(input);
|
||||
|
||||
Element soapRoot = soap.getDocumentElement();
|
||||
|
||||
UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory();
|
||||
Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(soapRoot);
|
||||
|
||||
Envelope soapEnvelope = (Envelope)unmarshaller.unmarshall(soapRoot);
|
||||
|
||||
return (ArtifactResolve)soapEnvelope.getBody().getUnknownXMLObjects().get(0);
|
||||
} catch (XMLParserException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (UnmarshallingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static org.w3c.dom.Element marshallSAMLObject(final SAMLObject object) {
|
||||
org.w3c.dom.Element element = null;
|
||||
try {
|
||||
MarshallerFactory unMarshallerFactory = Configuration.getMarshallerFactory();
|
||||
|
||||
Marshaller marshaller = unMarshallerFactory.getMarshaller(object);
|
||||
|
||||
element = marshaller.marshall(object);
|
||||
} catch (ClassCastException e) {
|
||||
throw new IllegalArgumentException("The class does not implement the interface XMLObject", e);
|
||||
} catch (MarshallingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
private ArtifactResponse buildArtifactResponse() {
|
||||
|
||||
ArtifactResponse artifactResponse = OpenSAMLUtils.buildSAMLObject(ArtifactResponse.class);
|
||||
|
||||
Issuer issuer = OpenSAMLUtils.buildSAMLObject(Issuer.class);
|
||||
issuer.setValue(IDPConstants.IDP_ENTITY_ID);
|
||||
artifactResponse.setIssuer(issuer);
|
||||
artifactResponse.setIssueInstant(new DateTime());
|
||||
artifactResponse.setDestination(SPConstants.ASSERTION_CONSUMER_SERVICE);
|
||||
|
||||
artifactResponse.setID(OpenSAMLUtils.generateSecureRandomId());
|
||||
|
||||
Status status = OpenSAMLUtils.buildSAMLObject(Status.class);
|
||||
StatusCode statusCode = OpenSAMLUtils.buildSAMLObject(StatusCode.class);
|
||||
statusCode.setValue(StatusCode.SUCCESS_URI);
|
||||
status.setStatusCode(statusCode);
|
||||
artifactResponse.setStatus(status);
|
||||
|
||||
Response response = OpenSAMLUtils.buildSAMLObject(Response.class);
|
||||
response.setDestination(SPConstants.ASSERTION_CONSUMER_SERVICE);
|
||||
response.setIssueInstant(new DateTime());
|
||||
response.setID(OpenSAMLUtils.generateSecureRandomId());
|
||||
Issuer issuer2 = OpenSAMLUtils.buildSAMLObject(Issuer.class);
|
||||
issuer2.setValue(IDPConstants.IDP_ENTITY_ID);
|
||||
|
||||
response.setIssuer(issuer2);
|
||||
|
||||
Status status2 = OpenSAMLUtils.buildSAMLObject(Status.class);
|
||||
StatusCode statusCode2 = OpenSAMLUtils.buildSAMLObject(StatusCode.class);
|
||||
statusCode2.setValue(StatusCode.SUCCESS_URI);
|
||||
status2.setStatusCode(statusCode2);
|
||||
|
||||
response.setStatus(status2);
|
||||
|
||||
artifactResponse.setMessage(response);
|
||||
|
||||
Assertion assertion = buildAssertion();
|
||||
|
||||
signAssertion(assertion);
|
||||
EncryptedAssertion encryptedAssertion = encryptAssertion(assertion);
|
||||
|
||||
response.getEncryptedAssertions().add(encryptedAssertion);
|
||||
return artifactResponse;
|
||||
}
|
||||
|
||||
private EncryptedAssertion encryptAssertion(Assertion assertion) {
|
||||
EncryptionParameters encryptionParameters = new EncryptionParameters();
|
||||
encryptionParameters.setAlgorithm(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128);
|
||||
|
||||
KeyEncryptionParameters keyEncryptionParameters = new KeyEncryptionParameters();
|
||||
keyEncryptionParameters.setEncryptionCredential(SPCredentials.getCredential());
|
||||
keyEncryptionParameters.setAlgorithm(EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP);
|
||||
|
||||
Encrypter encrypter = new Encrypter(encryptionParameters, keyEncryptionParameters);
|
||||
encrypter.setKeyPlacement(Encrypter.KeyPlacement.INLINE);
|
||||
|
||||
try {
|
||||
EncryptedAssertion encryptedAssertion = encrypter.encrypt(assertion);
|
||||
return encryptedAssertion;
|
||||
} catch (EncryptionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void signAssertion(Assertion assertion) {
|
||||
Signature signature = OpenSAMLUtils.buildSAMLObject(Signature.class);
|
||||
signature.setSigningCredential(IDPCredentials.getCredential());
|
||||
signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
|
||||
signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
|
||||
|
||||
assertion.setSignature(signature);
|
||||
|
||||
try {
|
||||
Configuration.getMarshallerFactory().getMarshaller(assertion).marshall(assertion);
|
||||
} catch (MarshallingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
try {
|
||||
Signer.signObject(signature);
|
||||
} catch (SignatureException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Assertion buildAssertion() {
|
||||
|
||||
Assertion assertion = OpenSAMLUtils.buildSAMLObject(Assertion.class);
|
||||
|
||||
Issuer issuer = OpenSAMLUtils.buildSAMLObject(Issuer.class);
|
||||
issuer.setValue(IDPConstants.IDP_ENTITY_ID);
|
||||
assertion.setIssuer(issuer);
|
||||
assertion.setIssueInstant(new DateTime());
|
||||
|
||||
assertion.setID(OpenSAMLUtils.generateSecureRandomId());
|
||||
|
||||
Subject subject = OpenSAMLUtils.buildSAMLObject(Subject.class);
|
||||
assertion.setSubject(subject);
|
||||
|
||||
NameID nameID = OpenSAMLUtils.buildSAMLObject(NameID.class);
|
||||
nameID.setFormat(NameIDType.TRANSIENT);
|
||||
nameID.setValue("Some NameID value");
|
||||
nameID.setSPNameQualifier("SP name qualifier");
|
||||
nameID.setNameQualifier("Name qualifier");
|
||||
|
||||
subject.setNameID(nameID);
|
||||
|
||||
subject.getSubjectConfirmations().add(buildSubjectConfirmation());
|
||||
|
||||
assertion.setConditions(buildConditions());
|
||||
|
||||
assertion.getAttributeStatements().add(buildAttributeStatement());
|
||||
|
||||
assertion.getAuthnStatements().add(buildAuthnStatement());
|
||||
|
||||
return assertion;
|
||||
}
|
||||
|
||||
private SubjectConfirmation buildSubjectConfirmation() {
|
||||
SubjectConfirmation subjectConfirmation = OpenSAMLUtils.buildSAMLObject(SubjectConfirmation.class);
|
||||
subjectConfirmation.setMethod(SubjectConfirmation.METHOD_BEARER);
|
||||
|
||||
SubjectConfirmationData subjectConfirmationData = OpenSAMLUtils.buildSAMLObject(SubjectConfirmationData.class);
|
||||
subjectConfirmationData.setInResponseTo("Made up ID");
|
||||
subjectConfirmationData.setNotBefore(new DateTime().minusDays(2));
|
||||
subjectConfirmationData.setNotOnOrAfter(new DateTime().plusDays(2));
|
||||
subjectConfirmationData.setRecipient(SPConstants.ASSERTION_CONSUMER_SERVICE);
|
||||
|
||||
subjectConfirmation.setSubjectConfirmationData(subjectConfirmationData);
|
||||
|
||||
return subjectConfirmation;
|
||||
}
|
||||
|
||||
private AuthnStatement buildAuthnStatement() {
|
||||
AuthnStatement authnStatement = OpenSAMLUtils.buildSAMLObject(AuthnStatement.class);
|
||||
AuthnContext authnContext = OpenSAMLUtils.buildSAMLObject(AuthnContext.class);
|
||||
AuthnContextClassRef authnContextClassRef = OpenSAMLUtils.buildSAMLObject(AuthnContextClassRef.class);
|
||||
authnContextClassRef.setAuthnContextClassRef(AuthnContext.SMARTCARD_AUTHN_CTX);
|
||||
authnContext.setAuthnContextClassRef(authnContextClassRef);
|
||||
authnStatement.setAuthnContext(authnContext);
|
||||
|
||||
authnStatement.setAuthnInstant(new DateTime());
|
||||
|
||||
return authnStatement;
|
||||
}
|
||||
|
||||
private Conditions buildConditions() {
|
||||
Conditions conditions = OpenSAMLUtils.buildSAMLObject(Conditions.class);
|
||||
conditions.setNotBefore(new DateTime().minusDays(2));
|
||||
conditions.setNotOnOrAfter(new DateTime().plusDays(2));
|
||||
AudienceRestriction audienceRestriction = OpenSAMLUtils.buildSAMLObject(AudienceRestriction.class);
|
||||
Audience audience = OpenSAMLUtils.buildSAMLObject(Audience.class);
|
||||
audience.setAudienceURI(SPConstants.ASSERTION_CONSUMER_SERVICE);
|
||||
audienceRestriction.getAudiences().add(audience);
|
||||
conditions.getAudienceRestrictions().add(audienceRestriction);
|
||||
return conditions;
|
||||
}
|
||||
|
||||
private AttributeStatement buildAttributeStatement() {
|
||||
AttributeStatement attributeStatement = OpenSAMLUtils.buildSAMLObject(AttributeStatement.class);
|
||||
|
||||
Attribute attributeUserName = OpenSAMLUtils.buildSAMLObject(Attribute.class);
|
||||
|
||||
XSStringBuilder stringBuilder = (XSStringBuilder)Configuration.getBuilderFactory().getBuilder(XSString.TYPE_NAME);
|
||||
XSString userNameValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME);
|
||||
userNameValue.setValue("bob");
|
||||
|
||||
attributeUserName.getAttributeValues().add(userNameValue);
|
||||
attributeUserName.setName("username");
|
||||
attributeStatement.getAttributes().add(attributeUserName);
|
||||
|
||||
Attribute attributeLevel = OpenSAMLUtils.buildSAMLObject(Attribute.class);
|
||||
XSString levelValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME);
|
||||
levelValue.setValue("999999999");
|
||||
|
||||
attributeLevel.getAttributeValues().add(levelValue);
|
||||
attributeLevel.setName("telephone");
|
||||
attributeStatement.getAttributes().add(attributeLevel);
|
||||
|
||||
return attributeStatement;
|
||||
|
||||
}
|
||||
|
||||
public static Envelope wrapInSOAPEnvelope(final XMLObject xmlObject) {
|
||||
Envelope envelope = OpenSAMLUtils.buildSAMLObject(Envelope.class);
|
||||
Body body = OpenSAMLUtils.buildSAMLObject(Body.class);
|
||||
|
||||
body.getUnknownXMLObjects().add(xmlObject);
|
||||
|
||||
envelope.setBody(body);
|
||||
|
||||
return envelope;
|
||||
}
|
||||
|
||||
|
||||
public static void printSAMLObject(final XMLObject object, final PrintWriter writer) {
|
||||
try {
|
||||
DocumentBuilder builder;
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
|
||||
builder = factory.newDocumentBuilder();
|
||||
|
||||
org.w3c.dom.Document document = builder.newDocument();
|
||||
Marshaller out = Configuration.getMarshallerFactory().getMarshaller(object);
|
||||
out.marshall(object, document);
|
||||
|
||||
Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
StreamResult result = new StreamResult(writer);
|
||||
DOMSource source = new DOMSource(document);
|
||||
transformer.transform(source, result);
|
||||
} catch (ParserConfigurationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (MarshallingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (TransformerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
10
src/main/java/no/steras/opensamlbook/idp/IDPConstants.java
Normal file
10
src/main/java/no/steras/opensamlbook/idp/IDPConstants.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package no.steras.opensamlbook.idp;
|
||||
|
||||
/**
|
||||
* Created by Privat on 4/7/14.
|
||||
*/
|
||||
public class IDPConstants {
|
||||
public static final String IDP_ENTITY_ID = "TestIDP";
|
||||
public static final String SSO_SERVICE = "http://localhost:8080/webprofile-ref-project/idp/singleSignOnService";
|
||||
public static final String ARTIFACT_RESOLUTION_SERVICE = "http://localhost:8080/webprofile-ref-project/idp/artifactResolutionService";
|
||||
}
|
||||
45
src/main/java/no/steras/opensamlbook/idp/IDPCredentials.java
Normal file
45
src/main/java/no/steras/opensamlbook/idp/IDPCredentials.java
Normal file
@@ -0,0 +1,45 @@
|
||||
package no.steras.opensamlbook.idp;
|
||||
|
||||
import org.opensaml.xml.security.*;
|
||||
import org.opensaml.xml.security.credential.BasicCredential;
|
||||
import org.opensaml.xml.security.credential.Credential;
|
||||
import org.opensaml.xml.security.credential.KeyStoreCredentialResolver;
|
||||
import org.opensaml.xml.security.credential.UsageType;
|
||||
import org.opensaml.xml.security.criteria.EntityIDCriteria;
|
||||
import org.opensaml.xml.security.x509.X509Credential;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.security.*;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Privat on 13/05/14.
|
||||
*/
|
||||
public class IDPCredentials {
|
||||
private static final Credential credential;
|
||||
|
||||
static {
|
||||
credential = generateCredential();
|
||||
}
|
||||
|
||||
private static Credential generateCredential() {
|
||||
try {
|
||||
KeyPair keyPair = SecurityHelper.generateKeyPair("RSA", 1024, null);
|
||||
return SecurityHelper.getSimpleCredential(keyPair.getPublic(), keyPair.getPrivate());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NoSuchProviderException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Credential getCredential() {
|
||||
return credential;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package no.steras.opensamlbook.idp;
|
||||
|
||||
import no.steras.opensamlbook.OpenSAMLUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* Created by Privat on 4/6/14.
|
||||
*/
|
||||
public class SingleSignOnServlet extends HttpServlet {
|
||||
private static Logger logger = LoggerFactory.getLogger(SingleSignOnServlet.class);
|
||||
private static final String ASSERTION_CONSUMER_SERVICE = "http://localhost:8080/webprofile-ref-project/sp/consumer";
|
||||
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
logger.info("AuthnRequest recieved");
|
||||
Writer w = resp.getWriter();
|
||||
resp.setContentType("text/html");
|
||||
w.append("<html>" + "<head></head>" + "<body><h1>You are now at IDP, click the button to authenticate</h1> <form method=\"POST\">"
|
||||
+ "<input type=\"submit\" value=\"Authenticate\"/>" + "</form>" + "</body>" + "</html>");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
|
||||
resp.sendRedirect(ASSERTION_CONSUMER_SERVICE + "?SAMLart=AAQAAMFbLinlXaCM%2BFIxiDwGOLAy2T71gbpO7ZhNzAgEANlB90ECfpNEVLg%3D");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
165
src/main/java/no/steras/opensamlbook/sp/AccessFilter.java
Normal file
165
src/main/java/no/steras/opensamlbook/sp/AccessFilter.java
Normal file
@@ -0,0 +1,165 @@
|
||||
package no.steras.opensamlbook.sp;
|
||||
|
||||
import no.steras.opensamlbook.OpenSAMLUtils;
|
||||
import no.steras.opensamlbook.idp.IDPConstants;
|
||||
import org.joda.time.DateTime;
|
||||
import org.opensaml.Configuration;
|
||||
import org.opensaml.DefaultBootstrap;
|
||||
import org.opensaml.common.SAMLObject;
|
||||
import org.opensaml.common.binding.BasicSAMLMessageContext;
|
||||
import org.opensaml.common.xml.SAMLConstants;
|
||||
import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder;
|
||||
import org.opensaml.saml2.core.*;
|
||||
import org.opensaml.saml2.metadata.Endpoint;
|
||||
import org.opensaml.saml2.metadata.SingleSignOnService;
|
||||
import org.opensaml.ws.message.encoder.MessageEncodingException;
|
||||
import org.opensaml.ws.transport.http.HttpServletResponseAdapter;
|
||||
import org.opensaml.xml.ConfigurationException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
|
||||
/**
|
||||
* The filter intercepts the user and start the SAML authentication if it is not authenticated
|
||||
*/
|
||||
public class AccessFilter implements Filter {
|
||||
private static Logger logger = LoggerFactory.getLogger(AccessFilter.class);
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
Configuration.validateJCEProviders();
|
||||
Configuration.validateNonSunJAXP();
|
||||
|
||||
for (Provider jceProvider : Security.getProviders()) {
|
||||
logger.info(jceProvider.getInfo());
|
||||
}
|
||||
|
||||
try {
|
||||
logger.info("Bootstrapping");
|
||||
DefaultBootstrap.bootstrap();
|
||||
} catch (ConfigurationException e) {
|
||||
throw new RuntimeException("Bootstrapping failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
|
||||
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
|
||||
|
||||
if (httpServletRequest.getSession().getAttribute(SPConstants.AUTHENTICATED_SESSION_ATTRIBUTE) != null) {
|
||||
chain.doFilter(request, response);
|
||||
} else {
|
||||
setGotoURLOnSession(httpServletRequest);
|
||||
redirectUserForAuthentication(httpServletResponse);
|
||||
}
|
||||
}
|
||||
|
||||
private void setGotoURLOnSession(HttpServletRequest request) {
|
||||
request.getSession().setAttribute(SPConstants.GOTO_URL_SESSION_ATTRIBUTE, request.getRequestURL().toString());
|
||||
}
|
||||
|
||||
private void redirectUserForAuthentication(HttpServletResponse httpServletResponse) {
|
||||
AuthnRequest authnRequest = buildAuthnRequest();
|
||||
redirectUserWithRequest(httpServletResponse, authnRequest);
|
||||
|
||||
}
|
||||
|
||||
private void redirectUserWithRequest(HttpServletResponse httpServletResponse, AuthnRequest authnRequest) {
|
||||
HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(httpServletResponse, true);
|
||||
BasicSAMLMessageContext<SAMLObject, AuthnRequest, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, AuthnRequest, SAMLObject>();
|
||||
context.setPeerEntityEndpoint(getIPDEndpoint());
|
||||
context.setOutboundSAMLMessage(authnRequest);
|
||||
context.setOutboundMessageTransport(responseAdapter);
|
||||
context.setOutboundSAMLMessageSigningCredential(SPCredentials.getCredential());
|
||||
|
||||
HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder();
|
||||
logger.info("AuthnRequest: ");
|
||||
OpenSAMLUtils.logSAMLObject(authnRequest);
|
||||
|
||||
logger.info("Redirecting to IDP");
|
||||
try {
|
||||
encoder.encode(context);
|
||||
} catch (MessageEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private AuthnRequest buildAuthnRequest() {
|
||||
AuthnRequest authnRequest = OpenSAMLUtils.buildSAMLObject(AuthnRequest.class);
|
||||
authnRequest.setIssueInstant(new DateTime());
|
||||
authnRequest.setDestination(getIPDSSODestination());
|
||||
authnRequest.setProtocolBinding(SAMLConstants.SAML2_ARTIFACT_BINDING_URI);
|
||||
authnRequest.setAssertionConsumerServiceURL(getAssertionConsumerEndpoint());
|
||||
authnRequest.setID(OpenSAMLUtils.generateSecureRandomId());
|
||||
authnRequest.setIssuer(buildIssuer());
|
||||
authnRequest.setNameIDPolicy(buildNameIdPolicy());
|
||||
authnRequest.setRequestedAuthnContext(buildRequestedAuthnContext());
|
||||
|
||||
return authnRequest;
|
||||
}
|
||||
private RequestedAuthnContext buildRequestedAuthnContext() {
|
||||
RequestedAuthnContext requestedAuthnContext = OpenSAMLUtils.buildSAMLObject(RequestedAuthnContext.class);
|
||||
requestedAuthnContext.setComparison(AuthnContextComparisonTypeEnumeration.MINIMUM);
|
||||
|
||||
AuthnContextClassRef passwordAuthnContextClassRef = OpenSAMLUtils.buildSAMLObject(AuthnContextClassRef.class);
|
||||
passwordAuthnContextClassRef.setAuthnContextClassRef(AuthnContext.PASSWORD_AUTHN_CTX);
|
||||
|
||||
requestedAuthnContext.getAuthnContextClassRefs().add(passwordAuthnContextClassRef);
|
||||
|
||||
return requestedAuthnContext;
|
||||
|
||||
}
|
||||
|
||||
private NameIDPolicy buildNameIdPolicy() {
|
||||
NameIDPolicy nameIDPolicy = OpenSAMLUtils.buildSAMLObject(NameIDPolicy.class);
|
||||
nameIDPolicy.setAllowCreate(true);
|
||||
|
||||
nameIDPolicy.setFormat(NameIDType.TRANSIENT);
|
||||
|
||||
return nameIDPolicy;
|
||||
}
|
||||
|
||||
private Issuer buildIssuer() {
|
||||
Issuer issuer = OpenSAMLUtils.buildSAMLObject(Issuer.class);
|
||||
issuer.setValue(getSPIssuerValue());
|
||||
|
||||
return issuer;
|
||||
}
|
||||
|
||||
private String getSPIssuerValue() {
|
||||
return SPConstants.SP_ENTITY_ID;
|
||||
}
|
||||
|
||||
private String getSPNameQualifier() {
|
||||
return SPConstants.SP_ENTITY_ID;
|
||||
}
|
||||
|
||||
private String getAssertionConsumerEndpoint() {
|
||||
return SPConstants.ASSERTION_CONSUMER_SERVICE;
|
||||
}
|
||||
|
||||
private String getIPDSSODestination() {
|
||||
return IDPConstants.SSO_SERVICE;
|
||||
}
|
||||
|
||||
private Endpoint getIPDEndpoint() {
|
||||
SingleSignOnService endpoint = OpenSAMLUtils.buildSAMLObject(SingleSignOnService.class);
|
||||
endpoint.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
|
||||
endpoint.setLocation(getIPDSSODestination());
|
||||
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
}
|
||||
}
|
||||
210
src/main/java/no/steras/opensamlbook/sp/ConsumerServlet.java
Normal file
210
src/main/java/no/steras/opensamlbook/sp/ConsumerServlet.java
Normal file
@@ -0,0 +1,210 @@
|
||||
package no.steras.opensamlbook.sp;
|
||||
|
||||
import no.steras.opensamlbook.OpenSAMLUtils;
|
||||
import no.steras.opensamlbook.idp.IDPConstants;
|
||||
import no.steras.opensamlbook.idp.IDPCredentials;
|
||||
import org.joda.time.DateTime;
|
||||
import org.opensaml.saml2.core.*;
|
||||
import org.opensaml.saml2.encryption.Decrypter;
|
||||
import org.opensaml.security.SAMLSignatureProfileValidator;
|
||||
import org.opensaml.ws.soap.client.BasicSOAPMessageContext;
|
||||
import org.opensaml.ws.soap.client.http.HttpClientBuilder;
|
||||
import org.opensaml.ws.soap.client.http.HttpSOAPClient;
|
||||
import org.opensaml.ws.soap.common.SOAPException;
|
||||
import org.opensaml.ws.soap.soap11.Envelope;
|
||||
import org.opensaml.xml.Configuration;
|
||||
import org.opensaml.xml.XMLObject;
|
||||
import org.opensaml.xml.encryption.DecryptionException;
|
||||
import org.opensaml.xml.encryption.InlineEncryptedKeyResolver;
|
||||
import org.opensaml.xml.io.MarshallingException;
|
||||
import org.opensaml.xml.parse.BasicParserPool;
|
||||
import org.opensaml.xml.schema.XSString;
|
||||
import org.opensaml.xml.security.SecurityException;
|
||||
import org.opensaml.xml.security.keyinfo.StaticKeyInfoCredentialResolver;
|
||||
import org.opensaml.xml.signature.*;
|
||||
import org.opensaml.xml.validation.ValidationException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Created by Privat on 4/6/14.
|
||||
*/
|
||||
public class ConsumerServlet extends HttpServlet {
|
||||
private static Logger logger = LoggerFactory.getLogger(ConsumerServlet.class);
|
||||
|
||||
@Override
|
||||
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
|
||||
logger.info("Artifact received");
|
||||
Artifact artifact = buildArtifactFromRequest(req);
|
||||
logger.info("Artifact: " + artifact.getArtifact());
|
||||
|
||||
ArtifactResolve artifactResolve = buildArtifactResolve(artifact);
|
||||
signArtifactResolve(artifactResolve);
|
||||
logger.info("Sending ArtifactResolve");
|
||||
logger.info("ArtifactResolve: ");
|
||||
OpenSAMLUtils.logSAMLObject(artifactResolve);
|
||||
|
||||
ArtifactResponse artifactResponse = sendAndReceiveArtifactResolve(artifactResolve);
|
||||
logger.info("ArtifactResponse received");
|
||||
logger.info("ArtifactResponse: ");
|
||||
OpenSAMLUtils.logSAMLObject(artifactResponse);
|
||||
|
||||
EncryptedAssertion encryptedAssertion = getEncryptedAssertion(artifactResponse);
|
||||
Assertion assertion = decryptAssertion(encryptedAssertion);
|
||||
verifyAssertionSignature(assertion);
|
||||
logger.info("Decrypted Assertion: ");
|
||||
OpenSAMLUtils.logSAMLObject(assertion);
|
||||
|
||||
logAssertionAttributes(assertion);
|
||||
logAuthenticationInstant(assertion);
|
||||
logAuthenticationMethod(assertion);
|
||||
|
||||
setAuthenticatedSession(req);
|
||||
redirectToGotoURL(req, resp);
|
||||
}
|
||||
|
||||
private Assertion decryptAssertion(EncryptedAssertion encryptedAssertion) {
|
||||
StaticKeyInfoCredentialResolver keyInfoCredentialResolver = new StaticKeyInfoCredentialResolver(SPCredentials.getCredential());
|
||||
|
||||
Decrypter decrypter = new Decrypter(null, keyInfoCredentialResolver, new InlineEncryptedKeyResolver());
|
||||
decrypter.setRootInNewDocument(true);
|
||||
|
||||
try {
|
||||
return decrypter.decrypt(encryptedAssertion);
|
||||
} catch (DecryptionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyAssertionSignature(Assertion assertion) {
|
||||
if (!assertion.isSigned()) {
|
||||
throw new RuntimeException("The SAML Assertion was not signed");
|
||||
}
|
||||
|
||||
try {
|
||||
SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
|
||||
profileValidator.validate(assertion.getSignature());
|
||||
|
||||
SignatureValidator sigValidator = new SignatureValidator(IDPCredentials.getCredential());
|
||||
|
||||
sigValidator.validate(assertion.getSignature());
|
||||
|
||||
logger.info("SAML Assertion signature verified");
|
||||
} catch (ValidationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void signArtifactResolve(ArtifactResolve artifactResolve) {
|
||||
Signature signature = OpenSAMLUtils.buildSAMLObject(Signature.class);
|
||||
signature.setSigningCredential(SPCredentials.getCredential());
|
||||
signature.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
|
||||
signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
|
||||
|
||||
artifactResolve.setSignature(signature);
|
||||
|
||||
try {
|
||||
Configuration.getMarshallerFactory().getMarshaller(artifactResolve).marshall(artifactResolve);
|
||||
} catch (MarshallingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
try {
|
||||
Signer.signObject(signature);
|
||||
} catch (SignatureException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setAuthenticatedSession(HttpServletRequest req) {
|
||||
req.getSession().setAttribute(SPConstants.AUTHENTICATED_SESSION_ATTRIBUTE, true);
|
||||
}
|
||||
|
||||
private void redirectToGotoURL(HttpServletRequest req, HttpServletResponse resp) {
|
||||
String gotoURL = (String)req.getSession().getAttribute(SPConstants.GOTO_URL_SESSION_ATTRIBUTE);
|
||||
logger.info("Redirecting to requested URL: " + gotoURL);
|
||||
try {
|
||||
resp.sendRedirect(gotoURL);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void logAuthenticationMethod(Assertion assertion) {
|
||||
logger.info("Authentication method: " + assertion.getAuthnStatements().get(0)
|
||||
.getAuthnContext().getAuthnContextClassRef().getAuthnContextClassRef());
|
||||
}
|
||||
|
||||
private void logAuthenticationInstant(Assertion assertion) {
|
||||
logger.info("Authentication instant: " + assertion.getAuthnStatements().get(0).getAuthnInstant());
|
||||
}
|
||||
|
||||
private void logAssertionAttributes(Assertion assertion) {
|
||||
for (Attribute attribute : assertion.getAttributeStatements().get(0).getAttributes()) {
|
||||
logger.info("Attribute name: " + attribute.getName());
|
||||
for (XMLObject attributeValue : attribute.getAttributeValues()) {
|
||||
logger.info("Attribute value: " + ((XSString) attributeValue).getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private EncryptedAssertion getEncryptedAssertion(ArtifactResponse artifactResponse) {
|
||||
Response response = (Response)artifactResponse.getMessage();
|
||||
return response.getEncryptedAssertions().get(0);
|
||||
}
|
||||
|
||||
private ArtifactResponse sendAndReceiveArtifactResolve(final ArtifactResolve artifactResolve) {
|
||||
try {
|
||||
Envelope envelope = OpenSAMLUtils.wrapInSOAPEnvelope(artifactResolve);
|
||||
|
||||
HttpClientBuilder clientBuilder = new HttpClientBuilder();
|
||||
HttpSOAPClient soapClient = new HttpSOAPClient(clientBuilder.buildClient(), new BasicParserPool());
|
||||
|
||||
BasicSOAPMessageContext soapContext = new BasicSOAPMessageContext();
|
||||
soapContext.setOutboundMessage(envelope);
|
||||
|
||||
soapClient.send(IDPConstants.ARTIFACT_RESOLUTION_SERVICE, soapContext);
|
||||
|
||||
Envelope soapResponse = (Envelope)soapContext.getInboundMessage();
|
||||
return (ArtifactResponse)soapResponse.getBody().getUnknownXMLObjects().get(0);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (SecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (SOAPException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Artifact buildArtifactFromRequest(final HttpServletRequest req) {
|
||||
Artifact artifact = OpenSAMLUtils.buildSAMLObject(Artifact.class);
|
||||
artifact.setArtifact(req.getParameter("SAMLart"));
|
||||
return artifact;
|
||||
}
|
||||
|
||||
private ArtifactResolve buildArtifactResolve(final Artifact artifact) {
|
||||
ArtifactResolve artifactResolve = OpenSAMLUtils.buildSAMLObject(ArtifactResolve.class);
|
||||
|
||||
Issuer issuer = OpenSAMLUtils.buildSAMLObject(Issuer.class);
|
||||
issuer.setValue(SPConstants.SP_ENTITY_ID);
|
||||
artifactResolve.setIssuer(issuer);
|
||||
|
||||
artifactResolve.setIssueInstant(new DateTime());
|
||||
|
||||
artifactResolve.setID(OpenSAMLUtils.generateSecureRandomId());
|
||||
|
||||
artifactResolve.setDestination(IDPConstants.ARTIFACT_RESOLUTION_SERVICE);
|
||||
|
||||
artifactResolve.setArtifact(artifact);
|
||||
|
||||
return artifactResolve;
|
||||
}
|
||||
|
||||
}
|
||||
15
src/main/java/no/steras/opensamlbook/sp/SPConstants.java
Normal file
15
src/main/java/no/steras/opensamlbook/sp/SPConstants.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package no.steras.opensamlbook.sp;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Created by Privat on 4/7/14.
|
||||
*/
|
||||
public class SPConstants {
|
||||
public static final String SP_ENTITY_ID = "TestSP";
|
||||
public static final String AUTHENTICATED_SESSION_ATTRIBUTE = "authenticated";
|
||||
public static final String GOTO_URL_SESSION_ATTRIBUTE = "gotoURL";
|
||||
public static final String ASSERTION_CONSUMER_SERVICE = "http://localhost:8080/webprofile-ref-project/sp/consumer";
|
||||
|
||||
}
|
||||
63
src/main/java/no/steras/opensamlbook/sp/SPCredentials.java
Normal file
63
src/main/java/no/steras/opensamlbook/sp/SPCredentials.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package no.steras.opensamlbook.sp;
|
||||
|
||||
import org.opensaml.xml.security.*;
|
||||
import org.opensaml.xml.security.credential.BasicCredential;
|
||||
import org.opensaml.xml.security.credential.Credential;
|
||||
import org.opensaml.xml.security.credential.KeyStoreCredentialResolver;
|
||||
import org.opensaml.xml.security.credential.UsageType;
|
||||
import org.opensaml.xml.security.criteria.EntityIDCriteria;
|
||||
import org.opensaml.xml.security.x509.X509Credential;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.security.*;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Privat on 13/05/14.
|
||||
*/
|
||||
public class SPCredentials {
|
||||
private static final String KEY_STORE_PASSWORD = "password";
|
||||
private static final String KEY_STORE_ENTRY_PASSWORD = "password";
|
||||
private static final String KEY_STORE_PATH = "/SPKeystore.jks";
|
||||
private static final String KEY_ENTRY_ID = "SPKey";
|
||||
|
||||
private static final Credential credential;
|
||||
|
||||
static {
|
||||
try {
|
||||
KeyStore keystore = readKeystoreFromFile(KEY_STORE_PATH, KEY_STORE_PASSWORD);
|
||||
Map<String, String> passwordMap = new HashMap<String, String>();
|
||||
passwordMap.put(KEY_ENTRY_ID, KEY_STORE_ENTRY_PASSWORD);
|
||||
KeyStoreCredentialResolver resolver = new KeyStoreCredentialResolver(keystore, passwordMap);
|
||||
|
||||
Criteria criteria = new EntityIDCriteria(KEY_ENTRY_ID);
|
||||
CriteriaSet criteriaSet = new CriteriaSet(criteria);
|
||||
|
||||
credential = resolver.resolveSingle(criteriaSet);
|
||||
} catch (org.opensaml.xml.security.SecurityException e) {
|
||||
throw new RuntimeException("Something went wrong reading credentials", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static KeyStore readKeystoreFromFile(String pathToKeyStore, String keyStorePassword) {
|
||||
try {
|
||||
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
InputStream inputStream = SPCredentials.class.getResourceAsStream(pathToKeyStore);
|
||||
keystore.load(inputStream, keyStorePassword.toCharArray());
|
||||
inputStream.close();
|
||||
return keystore;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Something went wrong reading keystore", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Credential getCredential() {
|
||||
return credential;
|
||||
}
|
||||
}
|
||||
BIN
src/main/resources/SPKeystore.jks
Normal file
BIN
src/main/resources/SPKeystore.jks
Normal file
Binary file not shown.
15
src/main/resources/logback.xml
Normal file
15
src/main/resources/logback.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{5} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
52
src/main/webapp/WEB-INF/web.xml
Normal file
52
src/main/webapp/WEB-INF/web.xml
Normal file
@@ -0,0 +1,52 @@
|
||||
<!DOCTYPE web-app PUBLIC
|
||||
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
|
||||
"http://java.sun.com/dtd/web-app_2_3.dtd" >
|
||||
|
||||
<web-app>
|
||||
<display-name>Archetype Created Web Application</display-name>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>ApplicationServlet</servlet-name>
|
||||
<servlet-class>no.steras.opensamlbook.app.ApplicationServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>SingleSignOnService</servlet-name>
|
||||
<servlet-class>no.steras.opensamlbook.idp.SingleSignOnServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>ConsumerServlet</servlet-name>
|
||||
<servlet-class>no.steras.opensamlbook.sp.ConsumerServlet</servlet-class>
|
||||
</servlet>
|
||||
<servlet>
|
||||
<servlet-name>ArtifactResolutionServlet</servlet-name>
|
||||
<servlet-class>no.steras.opensamlbook.idp.ArtifactResolutionServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>ApplicationServlet</servlet-name>
|
||||
<url-pattern>/app/appservlet</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>SingleSignOnService</servlet-name>
|
||||
<url-pattern>/idp/singleSignOnService</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ConsumerServlet</servlet-name>
|
||||
<url-pattern>/sp/consumer</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>ArtifactResolutionServlet</servlet-name>
|
||||
<url-pattern>/idp/artifactResolutionService</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<filter>
|
||||
<filter-name>AccessFilter</filter-name>
|
||||
<filter-class>no.steras.opensamlbook.sp.AccessFilter</filter-class>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>AccessFilter</filter-name>
|
||||
<url-pattern>/app/*</url-pattern>
|
||||
<dispatcher>REQUEST</dispatcher>
|
||||
</filter-mapping>
|
||||
</web-app>
|
||||
58
webprofile-ref-project.iml
Normal file
58
webprofile-ref-project.iml
Normal file
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="web" name="Web">
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<deploymentDescriptor name="web.xml" url="file://$MODULE_DIR$/src/main/webapp/WEB-INF/web.xml" />
|
||||
</descriptors>
|
||||
<webroots>
|
||||
<root url="file://$MODULE_DIR$/src/main/webapp" relative="/" />
|
||||
</webroots>
|
||||
<sourceRoots>
|
||||
<root url="file://$MODULE_DIR$/src/main/java" />
|
||||
<root url="file://$MODULE_DIR$/src/main/resources" />
|
||||
</sourceRoots>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Maven: org.opensaml:opensaml:2.6.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.opensaml:openws:1.5.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.opensaml:xmltooling:1.4.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.bouncycastle:bcprov-jdk15:1.46" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-codec:commons-codec:1.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: joda-time:joda-time:2.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: ca.juliusdavies:not-yet-commons-ssl:0.3.9" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-httpclient:commons-httpclient:3.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.santuario:xmlsec:1.5.4" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.xerces:xml-apis:2.10.0" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.xerces:serializer:2.10.0" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: xml-resolver:xml-resolver:1.2" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: xalan:xalan:2.7.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:jcl-over-slf4j:1.7.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:log4j-over-slf4j:1.7.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-collections:commons-collections:3.2.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: commons-lang:commons-lang:2.6" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.velocity:velocity:1.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.owasp.esapi:esapi:2.0.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: xerces:xercesImpl:2.10.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: xml-apis:xml-apis:1.4.01" level="project" />
|
||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.0.13" level="project" />
|
||||
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.0.13" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: javax.servlet:servlet-api:2.5" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
Reference in New Issue
Block a user