/* * JBoss, Home of Professional Open Source. Copyright 2008, Red Hat Middleware LLC, and individual contributors as * indicated by the @author tags. See the copyright.txt file in the distribution for a full listing of individual * contributors. * * This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any * later version. * * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License along with this software; if not, write to * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site: * http://www.fsf.org. */ package org.picketlink.identity.federation.core.parsers.wst; import org.picketlink.common.PicketLinkLogger; import org.picketlink.common.PicketLinkLoggerFactory; import org.picketlink.common.constants.WSTrustConstants; import org.picketlink.common.exceptions.ParsingException; import org.picketlink.common.parsers.ParserNamespaceSupport; import org.picketlink.common.util.StaxParserUtil; import org.picketlink.identity.federation.core.parsers.ParserController; import org.picketlink.identity.federation.core.parsers.wsse.WSSecurityParser; import org.picketlink.identity.federation.core.wstrust.WSTrustUtil; import org.picketlink.identity.federation.core.wstrust.wrappers.Lifetime; import org.picketlink.identity.federation.core.wstrust.wrappers.RequestSecurityTokenResponse; import org.picketlink.identity.federation.ws.policy.AppliesTo; import org.picketlink.identity.federation.ws.trust.BinarySecretType; import org.picketlink.identity.federation.ws.trust.ComputedKeyType; import org.picketlink.identity.federation.ws.trust.EntropyType; import org.picketlink.identity.federation.ws.trust.LifetimeType; import org.picketlink.identity.federation.ws.trust.OnBehalfOfType; import org.picketlink.identity.federation.ws.trust.RequestedProofTokenType; import org.picketlink.identity.federation.ws.trust.RequestedReferenceType; import org.picketlink.identity.federation.ws.trust.RequestedSecurityTokenType; import org.picketlink.identity.federation.ws.trust.RequestedTokenCancelledType; import org.picketlink.identity.federation.ws.trust.StatusType; import org.picketlink.identity.federation.ws.trust.UseKeyType; import org.picketlink.identity.federation.ws.wss.secext.SecurityTokenReferenceType; import org.picketlink.identity.federation.ws.wss.utility.AttributedDateTime; import org.w3c.dom.Element; import javax.xml.namespace.QName; import javax.xml.stream.XMLEventReader; import javax.xml.stream.events.Attribute; import javax.xml.stream.events.EndElement; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import java.net.URI; import java.net.URISyntaxException; /** * Parse the WS-Trust RequestSecurityTokenResponse * * @author Anil.Saldhana@redhat.com * @since Oct 11, 2010 */ public class WSTRequestSecurityTokenResponseParser implements ParserNamespaceSupport { private static final PicketLinkLogger logger = PicketLinkLoggerFactory.getLogger(); public static final String X509CERTIFICATE = "X509Certificate"; public static final String KEYVALUE = "KeyValue"; public static final String JDK_TRANSFORMER_PROPERTY = "picketlink.jdk.transformer"; /** * @see {@link ParserNamespaceSupport#parse(XMLEventReader)} */ public Object parse(XMLEventReader xmlEventReader) throws ParsingException { StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader); RequestSecurityTokenResponse responseToken = new RequestSecurityTokenResponse(); QName contextQName = new QName("", WSTrustConstants.RST_CONTEXT); Attribute contextAttribute = startElement.getAttributeByName(contextQName); String contextValue = StaxParserUtil.getAttributeValue(contextAttribute); responseToken.setContext(contextValue); while (xmlEventReader.hasNext()) { XMLEvent xmlEvent = StaxParserUtil.peek(xmlEventReader); if (xmlEvent == null) break; if (xmlEvent instanceof EndElement) { xmlEvent = StaxParserUtil.getNextEvent(xmlEventReader); EndElement endElement = (EndElement) xmlEvent; String endElementTag = StaxParserUtil.getEndElementName(endElement); if (endElementTag.equals(WSTrustConstants.RSTR)) break; else throw logger.parserUnknownEndElement(endElementTag); } try { StartElement subEvent = StaxParserUtil.peekNextStartElement(xmlEventReader); if (subEvent == null) break; String tag = StaxParserUtil.getStartElementName(subEvent); if (tag.equals(WSTrustConstants.REQUEST_TYPE)) { subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); if (!StaxParserUtil.hasTextAhead(xmlEventReader)) throw logger.parserExpectedTextValue("request type"); String value = StaxParserUtil.getElementText(xmlEventReader); responseToken.setRequestType(new URI(value)); } else if (tag.equals(WSTrustConstants.LIFETIME)) { subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); StaxParserUtil.validate(subEvent, WSTrustConstants.LIFETIME); LifetimeType lifeTime = new LifetimeType(); // Get the Created subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); String subTag = StaxParserUtil.getStartElementName(subEvent); if (subTag.equals(WSTrustConstants.CREATED)) { AttributedDateTime created = new AttributedDateTime(); created.setValue(StaxParserUtil.getElementText(xmlEventReader)); lifeTime.setCreated(created); } subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); subTag = StaxParserUtil.getStartElementName(subEvent); if (subTag.equals(WSTrustConstants.EXPIRES)) { AttributedDateTime expires = new AttributedDateTime(); expires.setValue(StaxParserUtil.getElementText(xmlEventReader)); lifeTime.setExpires(expires); } else throw logger.parserUnknownTag(subTag, subEvent.getLocation()); responseToken.setLifetime(new Lifetime(lifeTime)); EndElement lifeTimeElement = StaxParserUtil.getNextEndElement(xmlEventReader); StaxParserUtil.validate(lifeTimeElement, WSTrustConstants.LIFETIME); } else if (tag.equals(WSTrustConstants.TOKEN_TYPE)) { subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); if (!StaxParserUtil.hasTextAhead(xmlEventReader)) throw logger.parserExpectedTextValue("token type"); String value = StaxParserUtil.getElementText(xmlEventReader); responseToken.setTokenType(new URI(value)); } else if (tag.equals(WSTrustConstants.ON_BEHALF_OF)) { subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); WSTrustOnBehalfOfParser wstOnBehalfOfParser = new WSTrustOnBehalfOfParser(); OnBehalfOfType onBehalfOf = (OnBehalfOfType) wstOnBehalfOfParser.parse(xmlEventReader); responseToken.setOnBehalfOf(onBehalfOf); EndElement onBehalfOfEndElement = StaxParserUtil.getNextEndElement(xmlEventReader); StaxParserUtil.validate(onBehalfOfEndElement, WSTrustConstants.ON_BEHALF_OF); } else if (tag.equals(WSTrustConstants.KEY_TYPE)) { subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); if (!StaxParserUtil.hasTextAhead(xmlEventReader)) throw logger.parserExpectedTextValue("key type"); String keyType = StaxParserUtil.getElementText(xmlEventReader); try { URI keyTypeURI = new URI(keyType); responseToken.setKeyType(keyTypeURI); } catch (URISyntaxException e) { throw new ParsingException(e); } } else if (tag.equals(WSTrustConstants.KEY_SIZE)) { subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); if (!StaxParserUtil.hasTextAhead(xmlEventReader)) throw logger.parserExpectedTextValue("key size"); String keySize = StaxParserUtil.getElementText(xmlEventReader); try { responseToken.setKeySize(Long.parseLong(keySize)); } catch (NumberFormatException e) { throw logger.parserException(e); } } else if (tag.equals(WSTrustConstants.ENTROPY)) { subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); EntropyType entropy = new EntropyType(); subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); if (StaxParserUtil.matches(subEvent, WSTrustConstants.BINARY_SECRET)) { BinarySecretType binarySecret = new BinarySecretType(); Attribute typeAttribute = subEvent.getAttributeByName(new QName("", "Type")); if (typeAttribute != null) { binarySecret.setType(StaxParserUtil.getAttributeValue(typeAttribute)); } if (!StaxParserUtil.hasTextAhead(xmlEventReader)) throw logger.parserExpectedTextValue("binary secret value"); binarySecret.setValue(StaxParserUtil.getElementText(xmlEventReader).getBytes()); entropy.addAny(binarySecret); } responseToken.setEntropy(entropy); EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader); StaxParserUtil.validate(endElement, WSTrustConstants.ENTROPY); } else if (tag.equals(WSTrustConstants.USE_KEY)) { subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); UseKeyType useKeyType = new UseKeyType(); StaxParserUtil.validate(subEvent, WSTrustConstants.USE_KEY); // We peek at the next start element as the stax source has to be in the START_ELEMENT mode subEvent = StaxParserUtil.peekNextStartElement(xmlEventReader); if (StaxParserUtil.matches(subEvent, X509CERTIFICATE)) { Element domElement = StaxParserUtil.getDOMElement(xmlEventReader); // Element domElement = getX509CertificateAsDomElement( subEvent, xmlEventReader ); useKeyType.add(domElement); responseToken.setUseKey(useKeyType); } else if (StaxParserUtil.matches(subEvent, KEYVALUE)) { Element domElement = StaxParserUtil.getDOMElement(xmlEventReader); useKeyType.add(domElement); responseToken.setUseKey(useKeyType); } else throw logger.parserUnknownStartElement(StaxParserUtil.getStartElementName(subEvent), subEvent.getLocation()); } else if (tag.equals(WSTrustConstants.REQUESTED_TOKEN_CANCELLED)) { StaxParserUtil.getNextEndElement(xmlEventReader); responseToken.setRequestedTokenCancelled(new RequestedTokenCancelledType()); } else if (tag.equals(WSTrustConstants.REQUESTED_PROOF_TOKEN)) { subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); RequestedProofTokenType requestedProofToken = new RequestedProofTokenType(); subEvent = StaxParserUtil.getNextStartElement(xmlEventReader); if (StaxParserUtil.matches(subEvent, WSTrustConstants.BINARY_SECRET)) { BinarySecretType binarySecret = new BinarySecretType(); Attribute typeAttribute = subEvent.getAttributeByName(new QName("", "Type")); binarySecret.setType(StaxParserUtil.getAttributeValue(typeAttribute)); if (!StaxParserUtil.hasTextAhead(xmlEventReader)) throw logger.parserExpectedTextValue("binary secret value"); binarySecret.setValue(StaxParserUtil.getElementText(xmlEventReader).getBytes()); requestedProofToken.add(binarySecret); } else if (StaxParserUtil.matches(subEvent, WSTrustConstants.COMPUTED_KEY)) { ComputedKeyType computedKey = new ComputedKeyType(); if (!StaxParserUtil.hasTextAhead(xmlEventReader)) throw logger.parserExpectedTextValue("computed key algorithm"); computedKey.setAlgorithm(StaxParserUtil.getElementText(xmlEventReader)); requestedProofToken.add(computedKey); } responseToken.setRequestedProofToken(requestedProofToken); EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader); StaxParserUtil.validate(endElement, WSTrustConstants.REQUESTED_PROOF_TOKEN); } else if (tag.equals(WSTrustConstants.REQUESTED_TOKEN)) { responseToken.setRequestedSecurityToken(parseRequestedSecurityTokenType(xmlEventReader)); } else if (tag.equals(WSTrustConstants.REQUESTED_ATTACHED_REFERENCE)) { responseToken.setRequestedAttachedReference(parseRequestedReference(xmlEventReader, WSTrustConstants.REQUESTED_ATTACHED_REFERENCE)); } else if (tag.equals(WSTrustConstants.REQUESTED_UNATTACHED_REFERENCE)) { responseToken.setRequestedUnattachedReference(parseRequestedReference(xmlEventReader, WSTrustConstants.REQUESTED_UNATTACHED_REFERENCE)); } else if (tag.equals(WSTrustConstants.STATUS)) { responseToken.setStatus(this.parseStatusType(xmlEventReader)); } else if (tag.equals(WSTrustConstants.RENEWING)) { responseToken.setRenewing(WSTrustUtil.parseRenewingType(xmlEventReader)); } else { QName qname = subEvent.getName(); logger.trace("Looking for parser for element: " + qname); ParserNamespaceSupport parser = ParserController.get(qname); if (parser == null) throw logger.parserUnknownTag(qname.getLocalPart(), subEvent.getLocation()); Object parsedObject = parser.parse(xmlEventReader); if (parsedObject instanceof AppliesTo) { responseToken.setAppliesTo((AppliesTo) parsedObject); } } } catch (URISyntaxException e) { throw logger.parserException(e); } } return responseToken; } /** * @see {@link ParserNamespaceSupport#supports(QName)} */ public boolean supports(QName qname) { String nsURI = qname.getNamespaceURI(); String localPart = qname.getLocalPart(); return WSTrustConstants.BASE_NAMESPACE.equals(nsURI) && WSTrustConstants.RST.equals(localPart); } private StatusType parseStatusType(XMLEventReader xmlEventReader) throws ParsingException { StatusType status = new StatusType(); StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader); StaxParserUtil.validate(startElement, WSTrustConstants.STATUS); XMLEvent xmlEvent = null; while (xmlEventReader.hasNext()) { xmlEvent = StaxParserUtil.peek(xmlEventReader); if (xmlEvent instanceof EndElement) { String endElementTag = StaxParserUtil.getEndElementName((EndElement) xmlEvent); if (endElementTag.equals(WSTrustConstants.STATUS)) { xmlEvent = StaxParserUtil.getNextEndElement(xmlEventReader); break; } else throw logger.parserUnknownEndElement(endElementTag); } startElement = (StartElement) xmlEvent; String tag = StaxParserUtil.getStartElementName(startElement); if (tag.equals(WSTrustConstants.CODE)) { startElement = StaxParserUtil.getNextStartElement(xmlEventReader); StaxParserUtil.validate(startElement, WSTrustConstants.CODE); if (!StaxParserUtil.hasTextAhead(xmlEventReader)) throw logger.parserExpectedTextValue("Validation code"); status.setCode(StaxParserUtil.getElementText(xmlEventReader)); } else if (tag.equals(WSTrustConstants.REASON)) { startElement = StaxParserUtil.getNextStartElement(xmlEventReader); StaxParserUtil.validate(startElement, WSTrustConstants.REASON); if (!StaxParserUtil.hasTextAhead(xmlEventReader)) throw logger.parserExpectedTextValue("Validation reason"); status.setReason(StaxParserUtil.getElementText(xmlEventReader)); } } return status; } private RequestedSecurityTokenType parseRequestedSecurityTokenType(XMLEventReader xmlEventReader) throws ParsingException { RequestedSecurityTokenType requestedSecurityTokenType = new RequestedSecurityTokenType(); StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader); StaxParserUtil.validate(startElement, WSTrustConstants.REQUESTED_TOKEN); XMLEvent xmlEvent = null; while (xmlEventReader.hasNext()) { xmlEvent = StaxParserUtil.peek(xmlEventReader); if (xmlEvent instanceof EndElement) { String endElementTag = StaxParserUtil.getEndElementName((EndElement) xmlEvent); if (endElementTag.equals(WSTrustConstants.REQUESTED_TOKEN)) { xmlEvent = StaxParserUtil.getNextEndElement(xmlEventReader); break; } else throw logger.parserUnknownEndElement(endElementTag); } Element tokenElement = StaxParserUtil.getDOMElement(xmlEventReader); requestedSecurityTokenType.add(tokenElement); } return requestedSecurityTokenType; } private RequestedReferenceType parseRequestedReference(XMLEventReader xmlEventReader, String requestedReferenceTag) throws ParsingException { StartElement startElement = StaxParserUtil.getNextStartElement(xmlEventReader); StaxParserUtil.validate(startElement, requestedReferenceTag); RequestedReferenceType ref = new RequestedReferenceType(); WSSecurityParser wsseParser = new WSSecurityParser(); SecurityTokenReferenceType secref = (SecurityTokenReferenceType) wsseParser.parse(xmlEventReader); ref.setSecurityTokenReference(secref); EndElement endElement = StaxParserUtil.getNextEndElement(xmlEventReader); StaxParserUtil.validate(endElement, requestedReferenceTag); return ref; } }