/*
* Copyright [2007] [University Corporation for Advanced Internet Development, Inc.]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.opensaml.common.binding.artifact;
import java.io.StringReader;
import java.io.StringWriter;
import org.joda.time.DateTime;
import org.opensaml.Configuration;
import org.opensaml.common.SAMLObject;
import org.opensaml.util.storage.StorageService;
import org.opensaml.xml.io.Marshaller;
import org.opensaml.xml.io.MarshallingException;
import org.opensaml.xml.io.Unmarshaller;
import org.opensaml.xml.parse.ParserPool;
import org.opensaml.xml.util.DatatypeHelper;
import org.opensaml.xml.util.XMLHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
/**
* Basic artifact map implementation that uses a {@link StorageService} to store and retrieve artifacts.
*/
public class BasicSAMLArtifactMap implements SAMLArtifactMap {
/** Class Logger. */
private final Logger log = LoggerFactory.getLogger(BasicSAMLArtifactMap.class);
/** Pool used to parse serialized messages. */
private ParserPool parserPool;
/** Artifact mapping storage. */
private StorageService<String, SAMLArtifactMapEntry> artifactStore;
/** Storage service partition used by this cache. default: artifact */
private String partition;
/** Lifetime of an artifact in milliseconds. */
private long artifactLifetime;
/**
* Constructor.
*
* @param parser parser pool used to parse serialized messages
* @param storage artifact mapping storage
* @param lifetime lifetime of an artifact in milliseconds
*/
public BasicSAMLArtifactMap(ParserPool parser, StorageService<String, SAMLArtifactMapEntry> storage, long lifetime) {
parserPool = parser;
artifactStore = storage;
partition = "artifact";
artifactLifetime = lifetime;
}
/**
* Constructor.
*
* @param storage artifact mapping storage
* @param storageParition name of storage service partition to use
* @param lifetime lifetime of an artifact in milliseconds
*/
public BasicSAMLArtifactMap(StorageService<String, SAMLArtifactMapEntry> storage, String storageParition,
long lifetime) {
artifactStore = storage;
if (!DatatypeHelper.isEmpty(storageParition)) {
partition = DatatypeHelper.safeTrim(storageParition);
} else {
partition = "artifact";
}
artifactLifetime = lifetime;
}
/** {@inheritDoc} */
public boolean contains(String artifact) {
return artifactStore.contains(partition, artifact);
}
/** {@inheritDoc} */
public SAMLArtifactMapEntry get(String artifact) {
SAMLArtifactMapEntry entry = artifactStore.get(partition, artifact);
if (entry.isExpired()) {
remove(artifact);
return null;
}
return entry;
}
/** {@inheritDoc} */
public void put(String artifact, String relyingPartyId, String issuerId, SAMLObject samlMessage)
throws MarshallingException {
BasicSAMLArtifactMapEntry artifactEntry = new BasicSAMLArtifactMapEntry(artifact, issuerId, relyingPartyId,
samlMessage, artifactLifetime);
artifactStore.put(partition, artifact, artifactEntry);
}
/** {@inheritDoc} */
public void remove(String artifact) {
artifactStore.remove(partition, artifact);
}
/** Basic implementation of {@link SAMLArtifactMapEntry}. */
public class BasicSAMLArtifactMapEntry implements SAMLArtifactMapEntry {
/** SAML artifact being mapped. */
private String artifact;
/** Entity ID of the issuer of the artifact. */
private String issuer;
/** Entity ID of the receiver of the artifact. */
private String relyingParty;
/** Serialized SAML object mapped to the artifact. */
private String serializedMessage;
/** Time this artifact entry expires. */
private DateTime expirationTime;
/**
* Constructor.
*
* @param artifact artifact associated with the message
* @param issuer issuer of the artifact
* @param relyingParty receiver of the artifact
* @param saml SAML message mapped to the artifact
* @param lifetime lifetime of the artifact
*
* @throws MarshallingException thrown if the SAML message can not be serialzed to a string
*/
public BasicSAMLArtifactMapEntry(String artifact, String issuer, String relyingParty, SAMLObject saml,
long lifetime) throws MarshallingException {
this.artifact = artifact;
this.issuer = issuer;
this.relyingParty = relyingParty;
expirationTime = new DateTime().plus(lifetime);
StringWriter writer = new StringWriter();
Marshaller marshaller = Configuration.getMarshallerFactory().getMarshaller(saml);
XMLHelper.writeNode(marshaller.marshall(saml), writer);
serializedMessage = writer.toString();
}
/** {@inheritDoc} */
public String getArtifact() {
return artifact;
}
/** {@inheritDoc} */
public String getIssuerId() {
return issuer;
}
/** {@inheritDoc} */
public String getRelyingPartyId() {
return relyingParty;
}
/** {@inheritDoc} */
public SAMLObject getSamlMessage() {
try {
Element messageElem = parserPool.parse(new StringReader(serializedMessage)).getDocumentElement();
Unmarshaller unmarshaller = Configuration.getUnmarshallerFactory().getUnmarshaller(messageElem);
return (SAMLObject) unmarshaller.unmarshall(messageElem);
} catch (Exception e) {
log.error("Unable to deserialize and unmarshall SAML message associated with artifact " + artifact, e);
return null;
}
}
/** {@inheritDoc} */
public DateTime getExpirationTime() {
return expirationTime;
}
/** {@inheritDoc} */
public boolean isExpired() {
return expirationTime.isBeforeNow();
}
/** {@inheritDoc} */
public void onExpire() {
}
}
}