Author: sguilhen(a)redhat.com
Date: 2009-11-18 14:24:06 -0500 (Wed, 18 Nov 2009)
New Revision: 1018
Modified:
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/StandardRequestHandler.java
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/plugins/saml/SAML20TokenProvider.java
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/wrappers/RequestSecurityToken.java
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/wrappers/RequestSecurityTokenResponse.java
identity-federation/trunk/jboss-identity-fed-core/src/test/java/org/jboss/test/identity/federation/core/wstrust/JBossSTSUnitTestCase.java
identity-federation/trunk/jboss-identity-fed-core/src/test/java/org/jboss/test/identity/federation/core/wstrust/SAML20TokenProviderUnitTestCase.java
identity-federation/trunk/jboss-identity-fed-core/src/test/java/org/jboss/test/identity/federation/core/wstrust/WSTrustServiceFactoryUnitTestCase.java
Log:
JBID-213: implemented cancel logic in the request handler and SAML20TokenProvider
Modified:
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/StandardRequestHandler.java
===================================================================
---
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/StandardRequestHandler.java 2009-11-18
18:29:50 UTC (rev 1017)
+++
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/StandardRequestHandler.java 2009-11-18
19:24:06 UTC (rev 1018)
@@ -47,6 +47,7 @@
import org.jboss.identity.federation.ws.trust.ObjectFactory;
import org.jboss.identity.federation.ws.trust.RequestedProofTokenType;
import org.jboss.identity.federation.ws.trust.RequestedSecurityTokenType;
+import org.jboss.identity.federation.ws.trust.RequestedTokenCancelledType;
import org.jboss.identity.federation.ws.trust.StatusType;
import org.jboss.identity.federation.ws.trust.UseKeyType;
import org.jboss.identity.xmlsec.w3.xmldsig.KeyInfoType;
@@ -290,9 +291,9 @@
// first validate the provided token signature to make sure it has been issued by
this STS and hasn't been tempered.
if (trace)
log.trace("Validating token for renew request " +
request.getContext());
- if (request.getRenewTarget() == null)
+ if (request.getRenewTargetElement() == null)
throw new WSTrustException("Unable to renew token: renew target is
null");
-
+
Node securityToken = request.getRenewTargetElement().getFirstChild();
if (this.configuration.signIssuedToken() &&
this.configuration.getSTSKeyPair() != null)
{
@@ -305,7 +306,7 @@
if (!XMLSignatureUtil.validate(tokenDocument, keyPair.getPublic()))
throw new WSTrustException("Validation failure during renewal:
digital signature is invalid");
}
- catch (Exception e)
+ catch (Exception e)
{
throw new WSTrustException("Validation failure during renewal: unable to
verify digital signature", e);
}
@@ -316,7 +317,7 @@
log.trace("Security Token digital signature has NOT been verified.
Either the STS has been configured"
+ "not to sign tokens or the STS key pair has not been properly
specified.");
}
-
+
// set default values where needed.
if (request.getLifetime() == null &&
this.configuration.getIssuedTokenTimeout() != 0)
{
@@ -334,7 +335,7 @@
throw new WSTrustException("No SecurityTokenProvider configured for "
+ securityToken.getNamespaceURI() + ":"
+ securityToken.getLocalName());
provider.renewToken(context);
-
+
// create the WS-Trust response with the renewed token.
RequestedSecurityTokenType requestedSecurityToken = new
RequestedSecurityTokenType();
requestedSecurityToken.setAny(context.getSecurityToken().getTokenValue());
@@ -366,7 +367,7 @@
if (rstDocument == null)
throw new IllegalArgumentException("Request does not contain the DOM
Document");
- if (request.getValidateTarget() == null)
+ if (request.getValidateTargetElement() == null)
throw new WSTrustException("Unable to validate token: validate target is
null");
if (request.getTokenType() == null)
@@ -449,12 +450,31 @@
public RequestSecurityTokenResponse cancel(RequestSecurityToken request, Principal
callerPrincipal)
throws WSTrustException
{
+ // check if request contains all required elements.
Document rstDocument = request.getRSTDocument();
if (rstDocument == null)
throw new IllegalArgumentException("Request does not contain the DOM
Document");
+ if (request.getCancelTargetElement() == null)
+ throw new WSTrustException("Illegal cancel request: cancel target is
null");
- // TODO: implement cancel logic.
- throw new UnsupportedOperationException();
+ // obtain the token provider that will handle the request.
+ Node securityToken = request.getCancelTargetElement().getFirstChild();
+ SecurityTokenProvider provider =
this.configuration.getProviderForTokenElementNS(securityToken.getLocalName(),
+ securityToken.getNamespaceURI());
+ if (provider == null)
+ throw new WSTrustException("No SecurityTokenProvider configured for "
+ securityToken.getNamespaceURI() + ":"
+ + securityToken.getLocalName());
+
+ // create a request context and dispatch to the provider.
+ WSTrustRequestContext context = new WSTrustRequestContext(request,
callerPrincipal);
+ provider.cancelToken(context);
+
+ // if no exception has been raised, the token has been successfully canceled.
+ RequestSecurityTokenResponse response = new RequestSecurityTokenResponse();
+ if (request.getContext() != null)
+ response.setContext(request.getContext());
+ response.setRequestedTokenCancelled(new RequestedTokenCancelledType());
+ return response;
}
public Document postProcess(Document rstrDocument, RequestSecurityToken request)
throws WSTrustException
Modified:
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/plugins/saml/SAML20TokenProvider.java
===================================================================
---
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/plugins/saml/SAML20TokenProvider.java 2009-11-18
18:29:50 UTC (rev 1017)
+++
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/plugins/saml/SAML20TokenProvider.java 2009-11-18
19:24:06 UTC (rev 1018)
@@ -21,13 +21,20 @@
*/
package org.jboss.identity.federation.core.wstrust.plugins.saml;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
-import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
@@ -55,7 +62,6 @@
import org.jboss.identity.federation.ws.policy.AppliesTo;
import org.jboss.identity.federation.ws.trust.RequestedReferenceType;
import org.jboss.identity.federation.ws.trust.StatusType;
-import org.jboss.identity.federation.ws.trust.ValidateTargetType;
import org.jboss.identity.federation.ws.wss.secext.KeyIdentifierType;
import org.w3c.dom.Element;
@@ -71,7 +77,14 @@
private static Logger logger = Logger.getLogger(SAML20TokenProvider.class);
- @SuppressWarnings("unused")
+ private static final String CANCELED_IDS_FILE = "CanceledIdsFile";
+
+ // this set contains the ids of the assertions that have been canceled.
+ private Set<String> cancelledIds;
+
+ // file used to store the ids of the canceled assertions.
+ private File canceledIdsFile;
+
private Map<String, String> properties;
/*
@@ -82,6 +95,17 @@
public void initialize(Map<String, String> properties)
{
this.properties = properties;
+ this.cancelledIds = new HashSet<String>();
+
+ // set up the canceled ids cache if the file that contains the canceled assertions
has been specified.
+ String file = this.properties.get(CANCELED_IDS_FILE);
+ if (file == null && logger.isDebugEnabled())
+ logger.debug("File to store canceled ids has not been specified: ids will
not be persisted!");
+ else
+ {
+ this.canceledIdsFile = new File(file);
+ this.loadCanceledIds();
+ }
}
/*
@@ -91,7 +115,17 @@
*/
public void cancelToken(WSTrustRequestContext context) throws WSTrustException
{
- // TODO: implement cancel logic.
+ // get the assertion that must be canceled.
+ Element token = (Element)
context.getRequestSecurityToken().getCancelTargetElement();
+ if (token == null)
+ throw new WSTrustException("Invalid cancel request: missing required
CancelTarget");
+ Element assertionElement = (Element) token.getFirstChild();
+ if (!this.isAssertion(assertionElement))
+ throw new WSTrustException("CancelTarget doesn't not contain a SAMLV2.0
assertion");
+
+ // get the assertion ID and add it to the canceled assertions set.
+ String assertionId = assertionElement.getAttribute("ID");
+ this.storeCanceledId(assertionId);
}
/*
@@ -103,7 +137,72 @@
{
// generate an id for the new assertion.
String assertionID = IDGenerator.create("ID_");
- issueToken(context, assertionID);
+
+ // lifetime and audience restrictions.
+ Lifetime lifetime = context.getRequestSecurityToken().getLifetime();
+ AudienceRestrictionType restriction = null;
+ AppliesTo appliesTo = context.getRequestSecurityToken().getAppliesTo();
+ if (appliesTo != null)
+ restriction =
SAMLAssertionFactory.createAudienceRestriction(WSTrustUtil.parseAppliesTo(appliesTo));
+ ConditionsType conditions =
SAMLAssertionFactory.createConditions(lifetime.getCreated(), lifetime.getExpires(),
+ restriction);
+
+ String confirmationMethod = null;
+ KeyInfoConfirmationDataType keyInfoDataType = null;
+ // if there is a proof-of-possession token in the context, we have the holder of
key confirmation method.
+ if (context.getProofTokenInfo() != null)
+ {
+ confirmationMethod = SAMLUtil.SAML2_HOLDER_OF_KEY_URI;
+ keyInfoDataType =
SAMLAssertionFactory.createKeyInfoConfirmation(context.getProofTokenInfo());
+ }
+ else
+ confirmationMethod = SAMLUtil.SAML2_BEARER_URI;
+ // TODO: implement the SENDER_VOUCHES scenario.
+
+ SubjectConfirmationType subjectConfirmation =
SAMLAssertionFactory.createSubjectConfirmation(null,
+ confirmationMethod, keyInfoDataType);
+
+ // create a subject using the caller principal.
+ Principal principal = context.getCallerPrincipal();
+ String subjectName = principal == null ? "ANONYMOUS" :
principal.getName();
+ NameIDType nameID = SAMLAssertionFactory.createNameID(null,
"urn:jboss:identity-federation", subjectName);
+ SubjectType subject = SAMLAssertionFactory.createSubject(nameID,
subjectConfirmation);
+
+ // create the attribute statements if necessary.
+ List<StatementAbstractType> statements = null;
+ Map<String, Object> claimedAttributes = context.getClaimedAttributes();
+ if (claimedAttributes != null)
+ {
+ statements = new ArrayList<StatementAbstractType>();
+ statements.add(StatementUtil.createAttributeStatement(claimedAttributes));
+ }
+
+ // create the SAML assertion.
+ NameIDType issuerID = SAMLAssertionFactory.createNameID(null, null,
context.getTokenIssuer());
+ AssertionType assertion = SAMLAssertionFactory.createAssertion(assertionID,
issuerID, lifetime.getCreated(),
+ conditions, subject, statements);
+
+ // convert the constructed assertion to element.
+ Element assertionElement = null;
+ try
+ {
+ assertionElement = SAMLUtil.toElement(assertion);
+ }
+ catch (Exception e)
+ {
+ throw new WSTrustException("Failed to marshall SAMLV2 assertion", e);
+ }
+
+ SecurityToken token = new
StandardSecurityToken(context.getRequestSecurityToken().getTokenType().toString(),
+ assertionElement, assertionID);
+ context.setSecurityToken(token);
+
+ // set the SAML assertion attached reference.
+ KeyIdentifierType keyIdentifier =
WSTrustUtil.createKeyIdentifier(SAMLUtil.SAML2_VALUE_TYPE, "#" + assertionID);
+ Map<QName, String> attributes = new HashMap<QName, String>();
+ attributes.put(new QName(WSTrustConstants.WSSE11_NS, "TokenType"),
SAMLUtil.SAML2_TOKEN_TYPE);
+ RequestedReferenceType attachedReference =
WSTrustUtil.createRequestedReference(keyIdentifier, attributes);
+ context.setAttachedReference(attachedReference);
}
/*
@@ -132,6 +231,10 @@
throw new WSTrustException("Error unmarshalling assertion", je);
}
+ // canceled assertions cannot be renewed.
+ if (this.cancelledIds.contains(oldAssertion.getID()))
+ throw new WSTrustException("Assertion with id " + oldAssertion.getID()
+ " is canceled and cannot be renewed");
+
// adjust the lifetime for the renewed assertion.
ConditionsType conditions = oldAssertion.getConditions();
conditions.setNotBefore(context.getRequestSecurityToken().getLifetime().getCreated());
@@ -155,8 +258,8 @@
{
throw new WSTrustException("Failed to marshall SAMLV2 assertion", e);
}
- SecurityToken securityToken = new
StandardSecurityToken(context.getRequestSecurityToken().getTokenType().toString(),
- assertionElement, assertionID);
+ SecurityToken securityToken = new
StandardSecurityToken(context.getRequestSecurityToken().getTokenType()
+ .toString(), assertionElement, assertionID);
context.setSecurityToken(securityToken);
// set the SAML assertion attached reference.
@@ -172,50 +275,45 @@
*
* @see
org.jboss.identity.federation.core.wstrust.SecurityTokenProvider#validateToken(org.jboss.identity.federation.core.wstrust.WSTrustRequestContext)
*/
- @SuppressWarnings("unchecked")
public void validateToken(WSTrustRequestContext context) throws WSTrustException
{
if (logger.isTraceEnabled())
logger.trace("SAML V2.0 token validation started");
// get the SAML assertion that must be validated.
- ValidateTargetType validateTarget =
context.getRequestSecurityToken().getValidateTarget();
- if (validateTarget == null)
+ Element token = context.getRequestSecurityToken().getValidateTargetElement();
+ if (token == null)
throw new WSTrustException("Bad validate request: missing required
ValidateTarget");
String code = WSTrustConstants.STATUS_CODE_VALID;
String reason = "SAMLV2.0 Assertion successfuly validated";
AssertionType assertion = null;
-
- Object assertionObj = validateTarget.getAny();
- if (assertionObj instanceof JAXBElement)
+ Element assertionElement = (Element) token.getFirstChild();
+ if (!this.isAssertion(assertionElement))
{
- JAXBElement<AssertionType> assertionType =
(JAXBElement<AssertionType>) validateTarget.getAny();
- assertion = assertionType.getValue();
+ code = WSTrustConstants.STATUS_CODE_INVALID;
+ reason = "Validation failure: supplied token is not a SAMLV2.0
Assertion";
}
- else if (assertionObj instanceof Element)
+ else
{
- Element assertionElement = (Element) assertionObj;
-
- if (!this.isAssertion(assertionElement))
+ try
{
- code = WSTrustConstants.STATUS_CODE_INVALID;
- reason = "Validation failure: supplied token is not a SAMLV2.0
Assertion";
+ assertion = SAMLUtil.fromElement(assertionElement);
}
- else
+ catch (JAXBException e)
{
- try
- {
- assertion = SAMLUtil.fromElement((Element) assertionObj);
- }
- catch (JAXBException e)
- {
- throw new WSTrustException("Unmarshalling error:", e);
- }
+ throw new WSTrustException("Unmarshalling error:", e);
}
}
+ // check if the assertion has been canceled before.
+ if (this.cancelledIds.contains(assertion.getID()))
+ {
+ code = WSTrustConstants.STATUS_CODE_INVALID;
+ reason = "Validation failure: assertion with id " + assertion.getID()
+ " is canceled";
+ }
+
// check the assertion lifetime.
try
{
@@ -253,77 +351,64 @@
}
/**
- * Issue a SAML assertion token with the provided ID
- * @param context
- * @param assertionID
- * @throws WSTrustException
+ * <p>
+ * This method loads the ids of the canceled assertions from the file that has been
configured for this provider.
+ * All retrieved ids are set in the local cache of canceled ids.
+ * </p>
*/
- private void issueToken(WSTrustRequestContext context, String assertionID) throws
WSTrustException
+ private void loadCanceledIds()
{
- // lifetime and audience restrictions.
- Lifetime lifetime = context.getRequestSecurityToken().getLifetime();
- AudienceRestrictionType restriction = null;
- AppliesTo appliesTo = context.getRequestSecurityToken().getAppliesTo();
- if (appliesTo != null)
- restriction =
SAMLAssertionFactory.createAudienceRestriction(WSTrustUtil.parseAppliesTo(appliesTo));
- ConditionsType conditions =
SAMLAssertionFactory.createConditions(lifetime.getCreated(), lifetime.getExpires(),
- restriction);
-
- String confirmationMethod = null;
- KeyInfoConfirmationDataType keyInfoDataType = null;
- // if there is a proof-of-possession token in the context, we have the holder of
key confirmation method.
- if (context.getProofTokenInfo() != null)
+ try
{
- confirmationMethod = SAMLUtil.SAML2_HOLDER_OF_KEY_URI;
- keyInfoDataType =
SAMLAssertionFactory.createKeyInfoConfirmation(context.getProofTokenInfo());
+ if (!this.canceledIdsFile.exists())
+ {
+ if (logger.isDebugEnabled())
+ logger.debug("File " + this.canceledIdsFile.getCanonicalPath() +
" doesn't exist and will be created");
+ this.canceledIdsFile.createNewFile();
+ }
+ // read the file contents and populate the local cache.
+ BufferedReader reader = new BufferedReader(new
FileReader(this.canceledIdsFile));
+ String id = reader.readLine();
+ while(id != null)
+ {
+ this.cancelledIds.add(id);
+ id = reader.readLine();
+ }
+ reader.close();
}
- else
- confirmationMethod = SAMLUtil.SAML2_BEARER_URI;
- // TODO: implement the SENDER_VOUCHES scenario.
-
- SubjectConfirmationType subjectConfirmation =
SAMLAssertionFactory.createSubjectConfirmation(null,
- confirmationMethod, keyInfoDataType);
-
- // create a subject using the caller principal.
- Principal principal = context.getCallerPrincipal();
- String subjectName = principal == null ? "ANONYMOUS" :
principal.getName();
- NameIDType nameID = SAMLAssertionFactory.createNameID(null,
"urn:jboss:identity-federation", subjectName);
- SubjectType subject = SAMLAssertionFactory.createSubject(nameID,
subjectConfirmation);
-
- // create the attribute statements if necessary.
- List<StatementAbstractType> statements = null;
- Map<String, Object> claimedAttributes = context.getClaimedAttributes();
- if (claimedAttributes != null)
+ catch (IOException ioe)
{
- statements = new ArrayList<StatementAbstractType>();
- statements.add(StatementUtil.createAttributeStatement(claimedAttributes));
+ if (logger.isDebugEnabled())
+ logger.debug("Error opening canceled ids file: " +
ioe.getMessage());
+ ioe.printStackTrace();
}
-
- // create the SAML assertion.
- NameIDType issuerID = SAMLAssertionFactory.createNameID(null, null,
context.getTokenIssuer());
- AssertionType assertion = SAMLAssertionFactory.createAssertion(assertionID,
issuerID, lifetime.getCreated(),
- conditions, subject, statements);
-
- // convert the constructed assertion to element.
- Element assertionElement = null;
- try
+ }
+
+ /**
+ * <p>
+ * Stores the specified id in the cache of canceled ids. If a canceled ids file has
been configured for this
+ * provider, the id will also be written to the end of the file.
+ * </p>
+ *
+ * @param id a {@code String} representing the canceled id that must be stored.
+ */
+ public synchronized void storeCanceledId(String id)
+ {
+ if (this.canceledIdsFile != null)
{
- assertionElement = SAMLUtil.toElement(assertion);
+ try
+ {
+ // write a new line with the canceled id at the end of the file.
+ BufferedWriter writer = new BufferedWriter(new
FileWriter(this.canceledIdsFile, true));
+ writer.write(id + "\n");
+ writer.close();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
}
- catch (Exception e)
- {
- throw new WSTrustException("Failed to marshall SAMLV2 assertion", e);
- }
-
- SecurityToken token = new
StandardSecurityToken(context.getRequestSecurityToken().getTokenType().toString(),
- assertionElement, assertionID);
- context.setSecurityToken(token);
-
- // set the SAML assertion attached reference.
- KeyIdentifierType keyIdentifier =
WSTrustUtil.createKeyIdentifier(SAMLUtil.SAML2_VALUE_TYPE, "#" + assertionID);
- Map<QName, String> attributes = new HashMap<QName, String>();
- attributes.put(new QName(WSTrustConstants.WSSE11_NS, "TokenType"),
SAMLUtil.SAML2_TOKEN_TYPE);
- RequestedReferenceType attachedReference =
WSTrustUtil.createRequestedReference(keyIdentifier, attributes);
- context.setAttachedReference(attachedReference);
+ // add the canceled id to the local cache.
+ this.cancelledIds.add(id);
}
}
\ No newline at end of file
Modified:
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/wrappers/RequestSecurityToken.java
===================================================================
---
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/wrappers/RequestSecurityToken.java 2009-11-18
18:29:50 UTC (rev 1017)
+++
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/wrappers/RequestSecurityToken.java 2009-11-18
19:24:06 UTC (rev 1018)
@@ -136,7 +136,7 @@
private URI canonicalizationAlgorithm;
private URI keyWrapAlgorithm;
-
+
private ProofEncryptionType proofEncryption;
private UseKeyType useKey;
@@ -270,7 +270,7 @@
}
}
}
-
+
/**
* Creates an instance of {@code RequestSecurityTokenType} and {@code Document}
* @param delegate
@@ -279,7 +279,7 @@
public RequestSecurityToken(RequestSecurityTokenType delegate, Document rstDocument)
{
this(delegate);
- this.rstDocument = rstDocument;
+ this.rstDocument = rstDocument;
}
/**
@@ -730,7 +730,7 @@
{
return this.keyWrapAlgorithm;
}
-
+
/**
* <p>
* Sets the key wrap algorithm in the request.
@@ -742,7 +742,7 @@
{
this.keyWrapAlgorithm = keyWrapAlgorithm;
}
-
+
/**
* <p>
* Obtains the {@code ProofEncryption} section of the request. The {@code
ProofEncryption} indicates that the
@@ -1079,7 +1079,7 @@
{
return this.validateTarget;
}
-
+
/**
* Return the element in the document that represents
* the validate type
@@ -1087,14 +1087,14 @@
*/
public Element getValidateTargetElement()
{
- if(rstDocument == null)
+ if (rstDocument == null)
throw new IllegalStateException("RST Document is null");
-
+
String ns = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/";
String localPart = "ValidateTarget";
-
- NodeList nodeList = rstDocument.getElementsByTagNameNS(ns,localPart);
- if(nodeList != null && nodeList.getLength() > 0)
+
+ NodeList nodeList = rstDocument.getElementsByTagNameNS(ns, localPart);
+ if (nodeList != null && nodeList.getLength() > 0)
return (Element) nodeList.item(0);
else
return null;
@@ -1110,21 +1110,43 @@
*/
public Element getRenewTargetElement()
{
- if(this.rstDocument == null)
+ if (this.rstDocument == null)
throw new IllegalStateException("RST Document is null");
String ns = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/";
String localName = "RenewTarget";
- NodeList nodeList = rstDocument.getElementsByTagNameNS(ns,localName);
- if(nodeList != null && nodeList.getLength() > 0)
+ NodeList nodeList = rstDocument.getElementsByTagNameNS(ns, localName);
+ if (nodeList != null && nodeList.getLength() > 0)
return (Element) nodeList.item(0);
else
return null;
}
-
+
/**
* <p>
- * Sets the {@code ValidateTarged} section of the request. This elements identifies
the token that is to be
+ * Returns the element in the document that represents the cancel target type.
+ * </p>
+ *
+ * @return the {@code Element} that represents the renew target type, or {@code null}
if no renew target is found in
+ * the document.
+ */
+ public Element getCancelTargetElement()
+ {
+ if (this.rstDocument == null)
+ throw new IllegalStateException("RST Document is null");
+ String ns = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/";
+ String localName = "CancelTarget";
+
+ NodeList nodeList = rstDocument.getElementsByTagNameNS(ns, localName);
+ if (nodeList != null && nodeList.getLength() > 0)
+ return (Element) nodeList.item(0);
+ else
+ return null;
+ }
+
+ /**
+ * <p>
+ * Sets the {@code ValidateTarget} section of the request. This elements identifies
the token that is to be
* validated.
* </p>
*
@@ -1173,7 +1195,7 @@
{
return this.delegate;
}
-
+
/**
* Get the {@code Document} document representing the request
* @return
@@ -1182,7 +1204,7 @@
{
return this.rstDocument;
}
-
+
public void setRSTDocument(Document rstDocument)
{
this.rstDocument = rstDocument;
Modified:
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/wrappers/RequestSecurityTokenResponse.java
===================================================================
---
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/wrappers/RequestSecurityTokenResponse.java 2009-11-18
18:29:50 UTC (rev 1017)
+++
identity-federation/trunk/jboss-identity-fed-core/src/main/java/org/jboss/identity/federation/core/wstrust/wrappers/RequestSecurityTokenResponse.java 2009-11-18
19:24:06 UTC (rev 1018)
@@ -49,6 +49,7 @@
import org.jboss.identity.federation.ws.trust.RequestedProofTokenType;
import org.jboss.identity.federation.ws.trust.RequestedReferenceType;
import org.jboss.identity.federation.ws.trust.RequestedSecurityTokenType;
+import org.jboss.identity.federation.ws.trust.RequestedTokenCancelledType;
import org.jboss.identity.federation.ws.trust.StatusType;
import org.jboss.identity.federation.ws.trust.UseKeyType;
@@ -125,6 +126,8 @@
private RequestedProofTokenType requestedProofToken;
+ private RequestedTokenCancelledType requestedTokenCancelled;
+
private EntropyType entropy;
private Lifetime lifetime;
@@ -231,6 +234,8 @@
this.requestedUnattachedReference = (RequestedReferenceType)
element.getValue();
else if (localName.equalsIgnoreCase("RequestedProofToken"))
this.requestedProofToken = (RequestedProofTokenType)
element.getValue();
+ else if (localName.equalsIgnoreCase("RequestedTokenCancelled"))
+ this.requestedTokenCancelled = (RequestedTokenCancelledType)
element.getValue();
else if (localName.equalsIgnoreCase("Entropy"))
this.entropy = (EntropyType) element.getValue();
else if (localName.equalsIgnoreCase("Lifetime"))
@@ -472,6 +477,35 @@
/**
* <p>
+ * Obtains the {@code RequestedTokenCancelled} section of the response, if it has been
set. The presence of this
+ * element indicates that the security token specified in the cancel request has been
successfully canceled by
+ * the STS.
+ * </p>
+ *
+ * @return a reference to the {@code RequestedTokenCancelledType}, or {@code null} if
the response doesn't have
+ * a {@code RequestedTokenCancelled} section.
+ */
+ public RequestedTokenCancelledType getRequestedTokenCancelled()
+ {
+ return this.requestedTokenCancelled;
+ }
+
+ /**
+ * <p>
+ * Sets the {@code RequestedTokenCancelled} section of the response. This element is
used to inform the client that
+ * the token specified in a cancel request has been successfully canceled by the STS.
+ * </p>
+ *
+ * @param requestedTokenCancelled a reference to the {@code
RequestedTokenCancelledType}.
+ */
+ public void setRequestedTokenCancelled(RequestedTokenCancelledType
requestedTokenCancelled)
+ {
+ this.requestedTokenCancelled = requestedTokenCancelled;
+
this.delegate.getAny().add(this.factory.createRequestedTokenCancelled(requestedTokenCancelled));
+ }
+
+ /**
+ * <p>
* Obtains the entropy that has been used in creating the key.
* </p>
*
@@ -1145,7 +1179,7 @@
{
return this.delegate.getAny();
}
-
+
/**
* <p>
* Obtains a reference to the {@code RequestSecurityTokenResponseType} delegate.
Modified:
identity-federation/trunk/jboss-identity-fed-core/src/test/java/org/jboss/test/identity/federation/core/wstrust/JBossSTSUnitTestCase.java
===================================================================
---
identity-federation/trunk/jboss-identity-fed-core/src/test/java/org/jboss/test/identity/federation/core/wstrust/JBossSTSUnitTestCase.java 2009-11-18
18:29:50 UTC (rev 1017)
+++
identity-federation/trunk/jboss-identity-fed-core/src/test/java/org/jboss/test/identity/federation/core/wstrust/JBossSTSUnitTestCase.java 2009-11-18
19:24:06 UTC (rev 1018)
@@ -66,6 +66,7 @@
import org.jboss.identity.federation.ws.addressing.ObjectFactory;
import org.jboss.identity.federation.ws.policy.AppliesTo;
import org.jboss.identity.federation.ws.trust.BinarySecretType;
+import org.jboss.identity.federation.ws.trust.CancelTargetType;
import org.jboss.identity.federation.ws.trust.EntropyType;
import org.jboss.identity.federation.ws.trust.RenewTargetType;
import org.jboss.identity.federation.ws.trust.RequestedProofTokenType;
@@ -606,6 +607,94 @@
/**
* <p>
+ * This test case first generates a SAMLV2.0 assertion and then sends a WS-Trust
cancel message to the STS to cancel
+ * the assertion. A canceled assertion cannot be renewed or considered valid anymore.
+ * </p>
+ *
+ * @throws Exception
+ * if an error occurs while running the test.
+ */
+ public void testInvokeSAML20Cancel() throws Exception
+ {
+ // create a simple token request.
+ RequestSecurityToken request = this.createRequest("testcontext",
WSTrustConstants.ISSUE_REQUEST,
+ SAMLUtil.SAML2_TOKEN_TYPE, null);
+
+ // use the factory to marshall the request.
+ WSTrustJAXBFactory factory = WSTrustJAXBFactory.getInstance();
+ Source requestMessage = factory.marshallRequestSecurityToken(request);
+
+ // invoke the token service.
+ Source responseMessage = this.tokenService.invoke(requestMessage);
+ BaseRequestSecurityTokenResponse baseResponse =
factory.parseRequestSecurityTokenResponse(responseMessage);
+
+ // validate the response and get the SAML assertion from the request.
+ this.validateSAMLAssertionResponse(baseResponse, "testcontext",
SAMLUtil.SAML2_BEARER_URI);
+ RequestSecurityTokenResponseCollection collection =
(RequestSecurityTokenResponseCollection) baseResponse;
+ Element assertion = (Element)
collection.getRequestSecurityTokenResponses().get(0).getRequestedSecurityToken()
+ .getAny();
+
+ // now construct a WS-Trust cancel request with the generated assertion.
+ request = this.createRequest("cancelcontext",
WSTrustConstants.CANCEL_REQUEST, null, null);
+ CancelTargetType cancelTarget = new CancelTargetType();
+ cancelTarget.setAny(assertion);
+ request.setCancelTarget(cancelTarget);
+
+ // invoke the token service.
+ responseMessage =
this.tokenService.invoke(factory.marshallRequestSecurityToken(request));
+ baseResponse = factory.parseRequestSecurityTokenResponse(responseMessage);
+
+ // validate the response contents.
+ assertNotNull("Unexpected null response", baseResponse);
+ assertTrue("Unexpected response type", baseResponse instanceof
RequestSecurityTokenResponseCollection);
+ collection = (RequestSecurityTokenResponseCollection) baseResponse;
+ assertEquals("Unexpected number of responses", 1,
collection.getRequestSecurityTokenResponses().size());
+ RequestSecurityTokenResponse response =
collection.getRequestSecurityTokenResponses().get(0);
+ assertEquals("Unexpected response context", "cancelcontext",
response.getContext());
+ assertNotNull("Cancel response should contain a RequestedTokenCancelled
element", response
+ .getRequestedTokenCancelled());
+
+ // try to validate the canceled assertion.
+ request = this.createRequest("validatecontext",
WSTrustConstants.VALIDATE_REQUEST, null, null);
+ ValidateTargetType validateTarget = new ValidateTargetType();
+ validateTarget.setAny(assertion);
+ request.setValidateTarget(validateTarget);
+
+ // the response should contain a status indicating that the token is not valid.
+ responseMessage =
this.tokenService.invoke(factory.marshallRequestSecurityToken(request));
+ collection = (RequestSecurityTokenResponseCollection)
factory.parseRequestSecurityTokenResponse(responseMessage);
+ assertEquals("Unexpected number of responses", 1,
collection.getRequestSecurityTokenResponses().size());
+ response = collection.getRequestSecurityTokenResponses().get(0);
+ assertEquals("Unexpected response context", "validatecontext",
response.getContext());
+ assertEquals("Unexpected token type", WSTrustConstants.STATUS_TYPE,
response.getTokenType().toString());
+ StatusType status = response.getStatus();
+ assertNotNull("Unexpected null status", status);
+ assertEquals("Unexpected status code",
WSTrustConstants.STATUS_CODE_INVALID, status.getCode());
+ assertEquals("Unexpected status reason", "Validation failure:
assertion with id " + assertion.getAttribute("ID")
+ + " is canceled", status.getReason());
+
+ // now try to renew the canceled assertion.
+ request = this.createRequest("renewcontext",
WSTrustConstants.RENEW_REQUEST, null, null);
+ RenewTargetType renewTarget = new RenewTargetType();
+ renewTarget.setAny(assertion);
+ request.setRenewTarget(renewTarget);
+
+ // we should receive an exception when renewing the token.
+ try
+ {
+ this.tokenService.invoke(factory.marshallRequestSecurityToken(request));
+ fail("Renewing a canceled token should result in an exception being
thrown");
+ }
+ catch (WebServiceException we)
+ {
+ assertTrue("Unexpected cause type", we.getCause() instanceof
WSTrustException);
+ assertEquals("Unexpected exception message", "Assertion with id
" + assertion.getAttribute("ID")
+ + " is canceled and cannot be renewed",
we.getCause().getMessage());
+ }
+ }
+
+ /**
+ * <p>
* This test tries to request a token of an unknown type, checking if an exception is
correctly thrown by the
* security token service.
* </p>
Modified:
identity-federation/trunk/jboss-identity-fed-core/src/test/java/org/jboss/test/identity/federation/core/wstrust/SAML20TokenProviderUnitTestCase.java
===================================================================
---
identity-federation/trunk/jboss-identity-fed-core/src/test/java/org/jboss/test/identity/federation/core/wstrust/SAML20TokenProviderUnitTestCase.java 2009-11-18
18:29:50 UTC (rev 1017)
+++
identity-federation/trunk/jboss-identity-fed-core/src/test/java/org/jboss/test/identity/federation/core/wstrust/SAML20TokenProviderUnitTestCase.java 2009-11-18
19:24:06 UTC (rev 1018)
@@ -28,17 +28,20 @@
import java.security.cert.Certificate;
import java.util.Arrays;
import java.util.GregorianCalendar;
+import java.util.HashMap;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
+import javax.xml.transform.dom.DOMSource;
import junit.framework.TestCase;
import org.jboss.identity.federation.core.wstrust.StandardSecurityToken;
import org.jboss.identity.federation.core.wstrust.WSTrustConstants;
+import org.jboss.identity.federation.core.wstrust.WSTrustJAXBFactory;
import org.jboss.identity.federation.core.wstrust.WSTrustRequestContext;
import org.jboss.identity.federation.core.wstrust.WSTrustUtil;
import org.jboss.identity.federation.core.wstrust.plugins.saml.SAML20TokenProvider;
@@ -59,6 +62,7 @@
import org.jboss.identity.xmlsec.w3.xmldsig.KeyInfoType;
import org.jboss.identity.xmlsec.w3.xmldsig.X509DataType;
import org.jboss.identity.xmlsec.w3.xmlenc.EncryptedKeyType;
+import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
@@ -71,6 +75,16 @@
public class SAML20TokenProviderUnitTestCase extends TestCase
{
+ private SAML20TokenProvider provider;
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ this.provider = new SAML20TokenProvider();
+ provider.initialize(new HashMap<String, String>());
+ }
+
/**
* <p>
* Tests the issuance of a SAMLV2.0 Assertion.
@@ -90,7 +104,7 @@
context.setTokenIssuer("JBossSTS");
// call the SAML token provider and check the generated token.
- new SAML20TokenProvider().issueToken(context);
+ this.provider.issueToken(context);
assertNotNull("Unexpected null security token",
context.getSecurityToken());
JAXBContext jaxbContext =
JAXBContext.newInstance("org.jboss.identity.federation.saml.v2.assertion");
@@ -168,16 +182,16 @@
WSTrustRequestContext context = new WSTrustRequestContext(request, new
TestPrincipal("sguilhen"));
context.setTokenIssuer("JBossSTS");
-
+
// let's set a symmetric key proof-of-possession token in the context.
byte[] secret = WSTrustUtil.createRandomSecret(32);
PublicKey serviceKey = this.getCertificate("keystore/sts_keystore.jks",
"testpass", "service2").getPublicKey();
context.setProofTokenInfo(WSTrustUtil.createKeyInfo(secret, serviceKey, null));
// call the SAML token provider and check the generated token.
- new SAML20TokenProvider().issueToken(context);
+ this.provider.issueToken(context);
assertNotNull("Unexpected null security token",
context.getSecurityToken());
-
+
// check if the assertion has a subject confirmation that contains the encrypted
symmetric key.
AssertionType assertion = SAMLUtil.fromElement((Element)
context.getSecurityToken().getTokenValue());
SubjectType subject = assertion.getSubject();
@@ -200,13 +214,13 @@
assertEquals("Unexpected key info content size", 1,
keyInfo.getContent().size());
JAXBElement<?> encKeyElement = (JAXBElement<?>)
keyInfo.getContent().get(0);
assertEquals("Unexpected key info content type", EncryptedKeyType.class,
encKeyElement.getDeclaredType());
-
+
// Now let's set an asymmetric proof of possession token in the context.
Certificate certificate =
this.getCertificate("keystore/sts_keystore.jks", "testpass",
"service1");
context.setProofTokenInfo(WSTrustUtil.createKeyInfo(certificate));
-
+
// call the SAML token provider and check the generated token.
- new SAML20TokenProvider().issueToken(context);
+ this.provider.issueToken(context);
assertNotNull("Unexpected null security token",
context.getSecurityToken());
// check if the assertion has a subject confirmation that contains the encoded
certificate.
@@ -232,14 +246,14 @@
JAXBElement<?> x509DataElement = (JAXBElement<?>)
keyInfo.getContent().get(0);
assertEquals("Unexpected key info content type", X509DataType.class,
x509DataElement.getDeclaredType());
X509DataType x509Data = (X509DataType) x509DataElement.getValue();
- assertEquals("Unexpected X509 data content size", 1,
x509Data.getX509IssuerSerialOrX509SKIOrX509SubjectName().
- size());
+ assertEquals("Unexpected X509 data content size", 1,
x509Data.getX509IssuerSerialOrX509SKIOrX509SubjectName()
+ .size());
JAXBElement<?> x509CertElement = (JAXBElement<?>)
x509Data.getX509IssuerSerialOrX509SKIOrX509SubjectName().get(0);
assertEquals("Unexpected X509 data content type", byte[].class,
x509CertElement.getDeclaredType());
byte[] encodedCert = (byte[]) x509CertElement.getValue();
assertTrue("Invalid encoded certificate found",
Arrays.equals(certificate.getEncoded(), encodedCert));
}
-
+
/**
* <p>
* Tests the validation of a SAMLV2.0 Assertion.
@@ -252,17 +266,16 @@
// issue a SAMLV2.0 assertion.
WSTrustRequestContext context =
this.createIssuingContext(WSTrustUtil.createDefaultLifetime(3600000));
- SAML20TokenProvider provider = new SAML20TokenProvider();
- provider.issueToken(context);
+ this.provider.issueToken(context);
// get the issued SAMLV2.0 assertion.
Element assertion = (Element) context.getSecurityToken().getTokenValue();
// now create a WS-Trust validate context.
context = this.createValidatingContext(assertion);
-
+
// validate the SAMLV2.0 assertion.
- provider.validateToken(context);
+ this.provider.validateToken(context);
StatusType status = context.getStatus();
assertNotNull("Unexpected null status type", status);
assertEquals("Unexpected status code",
WSTrustConstants.STATUS_CODE_VALID, status.getCode());
@@ -275,10 +288,10 @@
GregorianCalendar expires = new GregorianCalendar();
expires.setTimeInMillis(currentTimeMillis - 1800000);
context = this.createIssuingContext(new Lifetime(created, expires));
-
+
provider.issueToken(context);
assertion = (Element) context.getSecurityToken().getTokenValue();
-
+
// try to validate the expired token.
context = this.createValidatingContext(assertion);
provider.validateToken(context);
@@ -310,7 +323,7 @@
WSTrustRequestContext context = new WSTrustRequestContext(request, new
TestPrincipal("sguilhen"));
context.setTokenIssuer("JBossSTS");
-
+
return context;
}
@@ -331,12 +344,14 @@
ValidateTargetType validateTarget = new ValidateTargetType();
validateTarget.setAny(assertion);
request.setValidateTarget(validateTarget);
+ // we need to set the request document in the request object for the test.
+ DOMSource requestSource = (DOMSource)
WSTrustJAXBFactory.getInstance().marshallRequestSecurityToken(request);
+ request.setRSTDocument((Document) requestSource.getNode());
WSTrustRequestContext context = new WSTrustRequestContext(request, new
TestPrincipal("sguilhen"));
-
return context;
}
-
+
/**
* <p>
* Obtains the {@code Certificate} stored under the specified alias in the specified
keystore.
@@ -353,7 +368,7 @@
InputStream stream =
Thread.currentThread().getContextClassLoader().getResourceAsStream(keyStoreFile);
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(stream, passwd.toCharArray());
-
+
Certificate certificate = keyStore.getCertificate(certificateAlias);
return certificate;
}
Modified:
identity-federation/trunk/jboss-identity-fed-core/src/test/java/org/jboss/test/identity/federation/core/wstrust/WSTrustServiceFactoryUnitTestCase.java
===================================================================
---
identity-federation/trunk/jboss-identity-fed-core/src/test/java/org/jboss/test/identity/federation/core/wstrust/WSTrustServiceFactoryUnitTestCase.java 2009-11-18
18:29:50 UTC (rev 1017)
+++
identity-federation/trunk/jboss-identity-fed-core/src/test/java/org/jboss/test/identity/federation/core/wstrust/WSTrustServiceFactoryUnitTestCase.java 2009-11-18
19:24:06 UTC (rev 1018)
@@ -22,6 +22,7 @@
package org.jboss.test.identity.federation.core.wstrust;
import java.security.PrivilegedActionException;
+import java.util.HashMap;
import junit.framework.TestCase;
@@ -83,12 +84,13 @@
public void testCreateTokenProvider() throws Exception
{
WSTrustServiceFactory factory = WSTrustServiceFactory.getInstance();
- SecurityTokenProvider provider = factory
-
.createTokenProvider("org.jboss.test.identity.federation.core.wstrust.SpecialTokenProvider",
null);
+ SecurityTokenProvider provider = factory.createTokenProvider(
+
"org.jboss.test.identity.federation.core.wstrust.SpecialTokenProvider", null);
assertNotNull("Unexpected null token provider", provider);
assertTrue("Unexpected token provider type", provider instanceof
SpecialTokenProvider);
- provider = factory
-
.createTokenProvider("org.jboss.identity.federation.core.wstrust.plugins.saml.SAML20TokenProvider",
null);
+ provider = factory.createTokenProvider(
+
"org.jboss.identity.federation.core.wstrust.plugins.saml.SAML20TokenProvider",
+ new HashMap<String, String>());
assertNotNull("Unexpected null token provider", provider);
assertTrue("Unexpected token provider type", provider instanceof
SAML20TokenProvider);