package edu.internet2.middleware.shibboleth.artifact;
import org.opensaml.SAMLAssertion;
+import org.opensaml.artifact.Artifact;
import edu.internet2.middleware.shibboleth.common.RelyingParty;
* the relying party on behalf of which the artifact is being created
* @return the artifact
*/
- public String generateArtifact(SAMLAssertion assertion, RelyingParty relyingParty);
+ public Artifact generateArtifact(SAMLAssertion assertion, RelyingParty relyingParty);
/**
+ * Recover an assertion that was previosly generated for a given artifact.
+ *
* @param artifact
- * @return
+ * the artifact in question
+ * @return a mapping to the assertion
*/
- public ArtifactMapping recoverAssertion(String artifact);
+ public ArtifactMapping recoverAssertion(Artifact artifact);
}
\ No newline at end of file
package edu.internet2.middleware.shibboleth.artifact;
import org.opensaml.SAMLAssertion;
+import org.opensaml.artifact.Artifact;
import edu.internet2.middleware.shibboleth.common.ServiceProvider;
*/
public class ArtifactMapping {
- private String assertionHandle;
- private long expirationTime;
- private SAMLAssertion assertion;
- private String serviceProviderId;
+ private Artifact artifact;
+ private long expirationTime;
+ private SAMLAssertion assertion;
+ private String serviceProviderId;
- public ArtifactMapping(String assertionHandle, SAMLAssertion assertion, ServiceProvider sp) {
- this.assertionHandle = assertionHandle;
+ public ArtifactMapping(Artifact artifact, SAMLAssertion assertion, ServiceProvider sp) {
+
+ this.artifact = artifact;
this.assertion = assertion;
- expirationTime = System.currentTimeMillis() + (1000 * 60 * 5); //in 5 minutes
+ expirationTime = System.currentTimeMillis() + (1000 * 60 * 5); // in 5 minutes
serviceProviderId = sp.getProviderId();
}
* Boolean indication of whether the artifact is expired.
*/
public boolean isExpired() {
+
if (System.currentTimeMillis() > expirationTime) { return true; }
return false;
}
* Boolean indication of whether the artifact was created on behalf of a specified SP.
*/
public boolean isCorrectProvider(ServiceProvider sp) {
+
if (sp.getProviderId().equals(serviceProviderId)) { return true; }
return false;
}
* Retrieves the SAML assertion associated with the artifact.
*/
public SAMLAssertion getAssertion() {
+
return assertion;
}
* Retrieves the SP on behalf of which the artifact was originally created.
*/
public String getServiceProviderId() {
+
return serviceProviderId;
}
package edu.internet2.middleware.shibboleth.artifact.provider;
-import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
import org.apache.log4j.Logger;
import org.opensaml.SAMLAssertion;
+import org.opensaml.artifact.Artifact;
+import org.opensaml.artifact.SAMLArtifactType0001;
+import org.opensaml.artifact.Util;
-import sun.misc.BASE64Decoder;
-import sun.misc.BASE64Encoder;
import edu.internet2.middleware.shibboleth.artifact.ArtifactMapper;
import edu.internet2.middleware.shibboleth.artifact.ArtifactMapping;
import edu.internet2.middleware.shibboleth.common.RelyingParty;
*/
public abstract class BaseArtifactMapper implements ArtifactMapper {
- private static Logger log = Logger.getLogger(BaseArtifactMapper.class.getName());
- private static byte[] typeCode = {0, 1};
+ private static Logger log = Logger.getLogger(BaseArtifactMapper.class.getName());
- private SecureRandom random = new SecureRandom();
- private MessageDigest md;
+ private MessageDigest md;
public BaseArtifactMapper() throws ShibbolethConfigurationException {
+
try {
md = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {
}
- public ArtifactMapping recoverAssertion(String artifact) {
-
- try {
- //Decode the artifact
- byte[] decoded = new BASE64Decoder().decodeBuffer(artifact);
- if (decoded.length != 42) {
- log.error("Invalid artifact length.");
- return null;
- }
-
- //Check the type
- if (decoded[0] != typeCode[0] || decoded[1] != typeCode[1]) {
- log.error("Incorrect artifact type code.");
- return null;
- }
-
- //Grab the assertion handle
- byte[] assertionHandle = new byte[20];
- for (int assertionHandleCount = 0, decodedCount = 22; assertionHandleCount < assertionHandle.length; assertionHandleCount++, decodedCount++) {
- assertionHandle[assertionHandleCount] = decoded[decodedCount];
- }
- String stringHandle = new String(assertionHandle);
-
- //delegate recovery to extenders
- return recoverAssertionImpl(stringHandle);
-
- } catch (IOException e) {
- log.error("Artifact not properly Base64 encoded.");
- return null;
- }
- }
-
- public String generateArtifact(SAMLAssertion assertion, RelyingParty relyingParty) {
-
- byte[] allArtifactComponents = new byte[42];
+ public Artifact generateArtifact(SAMLAssertion assertion, RelyingParty relyingParty) {
- // Add typecode
- allArtifactComponents[0] = typeCode[0];
- allArtifactComponents[1] = typeCode[1];
+ // TODO should the artifact type be configurable?
- // Add SourceID
- byte[] sourceID = new byte[20];
+ // Generate the artifact
+ Artifact artifact;
synchronized (md) {
- sourceID = md.digest(relyingParty.getIdentityProvider().getProviderId().getBytes());
+ artifact = new SAMLArtifactType0001(Util.generateSourceId(md, relyingParty.getIdentityProvider()
+ .getProviderId()));
}
- for (int sourceIdCount = 0, allComponentCount = 2; sourceIdCount < sourceID.length; sourceIdCount++, allComponentCount++) {
- allArtifactComponents[allComponentCount] = sourceID[sourceIdCount];
- }
-
- // Add Asserton Handle
- byte[] buffer = new byte[20];
- random.nextBytes(buffer);
- for (int assertionHandleCount = 0, allComponentCount = 22; assertionHandleCount < buffer.length; assertionHandleCount++, allComponentCount++) {
- allArtifactComponents[allComponentCount] = buffer[assertionHandleCount];
- }
-
- // Cache the assertion handle
- String assertionHandle = new String(buffer);
// Delegate adding to extenders
- addAssertionImpl(assertionHandle, new ArtifactMapping(assertionHandle, assertion, relyingParty));
+ addAssertionImpl(artifact, new ArtifactMapping(artifact, assertion, relyingParty));
// Return the encoded artifact
- return new BASE64Encoder().encode(allArtifactComponents);
+ return artifact;
}
/**
* Subclasses should implement artifact storage with this method.
*/
- protected abstract void addAssertionImpl(String assertionHandle, ArtifactMapping mapping);
-
- /**
- * Subclasses should implement artifact lookup with this method.
- *
- * @param stringHandle
- * the artifact string
- */
- protected abstract ArtifactMapping recoverAssertionImpl(String artifact);
+ protected abstract void addAssertionImpl(Artifact artifact, ArtifactMapping mapping);
}
\ No newline at end of file
import java.util.Map;
import org.apache.log4j.Logger;
+import org.opensaml.artifact.Artifact;
import edu.internet2.middleware.shibboleth.artifact.ArtifactMapper;
import edu.internet2.middleware.shibboleth.artifact.ArtifactMapping;
public class MemoryArtifactMapper extends BaseArtifactMapper implements ArtifactMapper {
public MemoryArtifactMapper() throws ShibbolethConfigurationException {
+
super();
}
- //TODO need to cleanup stale artifacts
- private static Logger log = Logger.getLogger(MemoryArtifactMapper.class.getName());
- private static Map mappings = Collections.synchronizedMap(new HashMap());
+ // TODO need to cleanup stale artifacts
+ private static Logger log = Logger.getLogger(MemoryArtifactMapper.class.getName());
+ private static Map mappings = Collections.synchronizedMap(new HashMap());
- /*
- * (non-Javadoc)
- *
- * @see edu.internet2.middleware.shibboleth.artifact.provider.BaseArtifactMapper#recoverAssertionImpl(java.lang.String)
- */
- protected ArtifactMapping recoverAssertionImpl(String stringHandle) {
+ public ArtifactMapping recoverAssertion(Artifact artifact) {
- //Load the assertion from memory
- ArtifactMapping mapping = (ArtifactMapping) mappings.get(stringHandle);
- mappings.remove(stringHandle);
+ ArtifactMapping mapping = (ArtifactMapping) mappings.get(artifact);
+ mappings.remove(artifact);
if (mapping == null || mapping.isExpired()) { return null; }
return mapping;
}
- /*
- * (non-Javadoc)
- *
- * @see edu.internet2.middleware.shibboleth.artifact.provider.BaseArtifactMapper#addAssertionImpl(java.lang.String,
- * edu.internet2.middleware.shibboleth.artifact.ArtifactMapping)
- */
- protected void addAssertionImpl(String assertionHandle, ArtifactMapping mapping) {
- mappings.put(assertionHandle, mapping);
+ public void addAssertionImpl(Artifact artifact, ArtifactMapping mapping) {
+
+ mappings.put(artifact, mapping);
}
}
\ No newline at end of file
import edu.internet2.middleware.shibboleth.aa.arp.ArpEngine;
import edu.internet2.middleware.shibboleth.aa.arp.ArpProcessingException;
import edu.internet2.middleware.shibboleth.aa.attrresolv.AttributeResolver;
+import edu.internet2.middleware.shibboleth.artifact.ArtifactMapper;
+import edu.internet2.middleware.shibboleth.artifact.provider.MemoryArtifactMapper;
import edu.internet2.middleware.shibboleth.common.Credential;
import edu.internet2.middleware.shibboleth.common.NameMapper;
import edu.internet2.middleware.shibboleth.common.RelyingParty;
import edu.internet2.middleware.shibboleth.common.ServiceProviderMapper;
+import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
import edu.internet2.middleware.shibboleth.metadata.EntityDescriptor;
import edu.internet2.middleware.shibboleth.metadata.Metadata;
import edu.internet2.middleware.shibboleth.metadata.MetadataException;
private ServiceProviderMapper spMapper;
private ArpEngine arpEngine;
private AttributeResolver resolver;
+ private ArtifactMapper artifactMapper;
IdPProtocolSupport(IdPConfig config, Logger transactionLog, NameMapper nameMapper, ServiceProviderMapper spMapper,
- ArpEngine arpEngine, AttributeResolver resolver) {
+ ArpEngine arpEngine, AttributeResolver resolver) throws ShibbolethConfigurationException {
this.transactionLog = transactionLog;
this.config = config;
spMapper.setMetadata(this);
this.arpEngine = arpEngine;
this.resolver = resolver;
+ // TODO make this pluggable... and clean up memory impl
+ artifactMapper = new MemoryArtifactMapper();
}
public static void validateEngineData(HttpServletRequest req) throws InvalidClientDataException {
- //TODO this should be pulled out into handlers
+ // TODO this should be pulled out into handlers
if ((req.getRemoteAddr() == null) || (req.getRemoteAddr().equals(""))) { throw new InvalidClientDataException(
"Unable to obtain client address."); }
resolver.destroy();
arpEngine.destroy();
}
+
+ public ArtifactMapper getArtifactMapper() {
+
+ return artifactMapper;
+ }
}
\ No newline at end of file
import org.opensaml.SAMLException;
import org.opensaml.SAMLRequest;
import org.opensaml.SAMLResponse;
+import org.opensaml.artifact.Artifact;
import org.w3c.dom.Element;
import sun.misc.BASE64Decoder;
-import edu.internet2.middleware.shibboleth.artifact.ArtifactMapper;
import edu.internet2.middleware.shibboleth.artifact.ArtifactMapping;
-import edu.internet2.middleware.shibboleth.artifact.provider.MemoryArtifactMapper;
import edu.internet2.middleware.shibboleth.common.ShibbolethConfigurationException;
import edu.internet2.middleware.shibboleth.idp.IdPProtocolHandler;
import edu.internet2.middleware.shibboleth.idp.IdPProtocolSupport;
*/
public class SAMLv1_1ArtifactQueryHandler extends BaseServiceHandler implements IdPProtocolHandler {
- // TODO figure out how to refactor this
- private ArtifactMapper artifactMapper;
-
private static Logger log = Logger.getLogger(SAMLv1_1ArtifactQueryHandler.class.getName());
public SAMLv1_1ArtifactQueryHandler(Element config) throws ShibbolethConfigurationException {
super(config);
- // TODO move the mapper out into protocol support
- artifactMapper = new MemoryArtifactMapper();
}
/*
- * (non-Javadoc)
- *
* @see edu.internet2.middleware.shibboleth.idp.ProtocolHandler#getHandlerName()
*/
public String getHandlerName() {
public SAMLResponse processRequest(HttpServletRequest request, HttpServletResponse response,
SAMLRequest samlRequest, IdPProtocolSupport support) throws SAMLException, IOException, ServletException {
- log.info("Recieved a request to dereference an assertion artifact.");
+ log.info("Recieved a request to dereference assertion artifacts.");
- // TODO how about signatures on artifact dereferencing
// Pull credential from request
X509Certificate credential = getCredentialFromProvider(request);
if (credential == null || credential.getSubjectX500Principal().getName(X500Principal.RFC2253).equals("")) {
ArrayList assertions = new ArrayList();
Iterator artifacts = samlRequest.getArtifacts();
- // TODO error if not artifacts
+ if (!artifacts.hasNext()) {
+ log.error("Protocol Handler received a SAML Request, but is unable to handle it. No "
+ + "artifacts were included in the request.");
+ throw new SAMLException(SAMLException.REQUESTER, "General error processing request.");
+ }
int queriedArtifacts = 0;
+ // for transaction log
StringBuffer dereferencedArtifacts = new StringBuffer();
- // for // transaction // log
+
while (artifacts.hasNext()) {
queriedArtifacts++;
- String artifact = (String) artifacts.next();
- log.debug("Attempting to dereference artifact: (" + artifact + ").");
- ArtifactMapping mapping = artifactMapper.recoverAssertion(artifact);
+ Artifact artifact = (Artifact) artifacts.next();
+ log.debug("Attempting to dereference artifact: (" + artifact.toString() + ").");
+ ArtifactMapping mapping = support.getArtifactMapper().recoverAssertion(artifact);
if (mapping != null) {
- SAMLAssertion assertion = mapping.getAssertion(); // See if we have metadata for this provider
+ SAMLAssertion assertion = mapping.getAssertion();
+ // See if we have metadata for this provider
EntityDescriptor provider = support.lookup(mapping.getServiceProviderId());
if (provider == null) {
log.info("No metadata found for provider: (" + mapping.getServiceProviderId() + ").");
throw new SAMLException(SAMLException.REQUESTER, "Invalid service provider.");
}
- // Make sure that the suppplied credential is valid for the // provider to which theartifact was issued
+
+ // Make sure that the suppplied credential is valid for the provider to which the artifact was issued
if (!isValidCredential(provider, credential)) {
log.error("Supplied credential ("
+ credential.getSubjectX500Principal().getName(X500Principal.RFC2253)
assertions.add(assertion);
dereferencedArtifacts.append("(" + artifact + ")");
}
- } // The spec requires that if any artifacts are dereferenced, they must
+ }
+
+ // The spec requires that if any artifacts are dereferenced, they must
// all be dereferenced
if (assertions.size() > 0 && assertions.size() != queriedArtifacts) { throw new SAMLException(
SAMLException.REQUESTER, "Unable to successfully dereference all artifacts."); }
+
// Create and send response
- // The spec says that we should send "success" in the case where no // artifacts match
+ // The spec says that we should send "success" in the case where no artifacts match
SAMLResponse samlResponse = new SAMLResponse(samlRequest.getId(), null, assertions, null);
if (log.isDebugEnabled()) {
try {
// Create artifacts for each assertion
ArrayList artifacts = new ArrayList();
for (int i = 0; i < assertions.length; i++) {
- // TODO replace the artifact stuff here!!!
- // artifacts.add(artifactMapper.generateArtifact(assertions[i], relyingParty));
+ artifacts.add(support.getArtifactMapper().generateArtifact(assertions[i], relyingParty));
}
// Assemble the query string