/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.cxf.ws.security.tokenstore; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.io.StringReader; import java.security.Key; import java.security.Principal; import java.security.cert.X509Certificate; import java.time.Instant; import java.time.ZonedDateTime; import java.time.format.DateTimeParseException; import java.util.Map; import javax.xml.stream.XMLStreamException; import org.w3c.dom.Element; import org.apache.cxf.helpers.DOMUtils; import org.apache.cxf.security.SecurityContext; import org.apache.cxf.staxutils.StaxUtils; import org.apache.cxf.staxutils.W3CDOMStreamWriter; import org.apache.wss4j.common.crypto.Crypto; import org.apache.wss4j.common.token.Reference; import org.apache.wss4j.common.util.DOM2Writer; import org.apache.wss4j.common.util.XMLUtils; import org.apache.wss4j.dom.WSConstants; /** * */ public class SecurityToken implements Serializable { /** * This tag holds an ID of a Bootstrap SecurityToken stored in the TokenStore */ public static final String BOOTSTRAP_TOKEN_ID = "bootstrap_security_token_id"; /** * */ private static final long serialVersionUID = -8220267049304000696L; /** * Token identifier */ private String id; /** * WSU Identifier of the token */ private String wsuId; /** * The actual token in its current state */ private transient Element token; /** * The String representation of the token (The token can't be serialized as it's a DOM Element) */ private String tokenStr; /** * The RequestedAttachedReference element * NOTE : The oasis-200401-wss-soap-message-security-1.0 spec allows * an extensibility mechanism for wsse:SecurityTokenReference and * wsse:Reference. Hence we cannot limit to the * wsse:SecurityTokenReference\wsse:Reference case and only hold the URI and * the ValueType values. */ private transient Element attachedReference; /** * The RequestedUnattachedReference element * NOTE : The oasis-200401-wss-soap-message-security-1.0 spec allows * an extensibility mechanism for wsse:SecurityTokenReference and * wsse:Reference. Hence we cannot limit to the * wsse:SecurityTokenReference\wsse:Reference case and only hold the URI and * the ValueType values. */ private transient Element unattachedReference; /** * A bag to hold any other properties */ private Map<String, Object> properties; /** * The secret associated with the Token */ private transient byte[] secret; /** * Some binary data associated with the token */ private byte[] data; /** * A key associated with the token */ private transient Key key; /** * Created time */ private Instant created; /** * Expiration time */ private Instant expires; /** * Issuer end point address */ private String issuerAddress; /** * If an encrypted key, this contains the sha1 for the key */ private String encrKeySha1Value; /** * A hash code associated with this token. */ private int tokenHash; /** * This holds the identifier of another SecurityToken which represents a transformed * version of this token. */ private String transformedTokenIdentifier; /** * The tokenType */ private String tokenType; private X509Certificate x509cert; private transient Crypto crypto; /** * The principal of this SecurityToken */ private Principal principal; /** * The SecurityContext originally associated with this token */ private transient SecurityContext securityContext; public SecurityToken() { } public SecurityToken(String id) { this.id = XMLUtils.getIDFromReference(id); } public SecurityToken(String id, Instant created, Instant expires) { this.id = XMLUtils.getIDFromReference(id); this.created = created; this.expires = expires; } public SecurityToken(String id, Element tokenElem, Instant created, Instant expires) { this.id = XMLUtils.getIDFromReference(id); this.token = cloneElement(tokenElem); this.created = created; this.expires = expires; } public SecurityToken(String id, Element tokenElem, Element lifetimeElem) { this.id = XMLUtils.getIDFromReference(id); this.token = cloneElement(tokenElem); if (lifetimeElem != null) { processLifeTime(lifetimeElem); } } private static Element cloneElement(Element el) { try { W3CDOMStreamWriter writer = new W3CDOMStreamWriter(); writer.setNsRepairing(true); StaxUtils.copy(el, writer); return writer.getDocument().getDocumentElement(); } catch (Exception ex) { //ignore } return el; } /** * @param lifetimeElem * @throws TrustException */ private void processLifeTime(Element lifetimeElem) { try { Element createdElem = DOMUtils.getFirstChildWithName(lifetimeElem, WSConstants.WSU_NS, WSConstants.CREATED_LN); this.created = ZonedDateTime.parse(DOMUtils.getContent(createdElem)).toInstant(); Element expiresElem = DOMUtils.getFirstChildWithName(lifetimeElem, WSConstants.WSU_NS, WSConstants.EXPIRES_LN); this.expires = ZonedDateTime.parse(DOMUtils.getContent(expiresElem)).toInstant(); } catch (DateTimeParseException e) { //shouldn't happen } } /** * @return Returns the properties. */ public Map<String, Object> getProperties() { return properties; } /** * @param properties The properties to set. */ public void setProperties(Map<String, Object> properties) { this.properties = properties; } /** * @return Returns the token. */ public Element getToken() { return token; } /** * @param token The token to set. */ public void setToken(Element token) { if (token != null) { this.token = cloneElement(token); } } /** * Get the identifier corresponding to a transformed version of this token */ public String getTransformedTokenIdentifier() { return transformedTokenIdentifier; } /** * Set the identifier corresponding to a transformed version of this token */ public void setTransformedTokenIdentifier(String transformedTokenIdentifier) { this.transformedTokenIdentifier = transformedTokenIdentifier; } /** * Set the id */ public void setId(String id) { this.id = XMLUtils.getIDFromReference(id); } /** * @return Returns the id. */ public String getId() { return id; } /** * @return Returns the secret. */ public byte[] getSecret() { return secret; } /** * @param secret The secret to set. */ public void setSecret(byte[] secret) { this.secret = secret; } /** * @return Returns the attachedReference. */ public Element getAttachedReference() { return attachedReference; } /** * @param attachedReference The attachedReference to set. */ public void setAttachedReference(Element attachedReference) { if (attachedReference != null) { this.attachedReference = cloneElement(attachedReference); } } /** * @return Returns the unattachedReference. */ public Element getUnattachedReference() { return unattachedReference; } /** * @param unattachedReference The unattachedReference to set. */ public void setUnattachedReference(Element unattachedReference) { if (unattachedReference != null) { this.unattachedReference = cloneElement(unattachedReference); } } /** * @return Returns the created. */ public Instant getCreated() { return created; } /** * @return Returns the expires. */ public Instant getExpires() { return expires; } /** * Return whether this SecurityToken is expired or not */ public boolean isExpired() { if (expires != null) { Instant now = Instant.now(); if (expires.isBefore(now)) { return true; } } return false; } /** * Return whether this SecurityToken is about to expire or not */ public boolean isAboutToExpire(long secondsToExpiry) { if (expires != null && secondsToExpiry > 0) { Instant now = Instant.now().plusSeconds(secondsToExpiry); if (expires.isBefore(now)) { return true; } } return false; } /** * @param expires The expires to set. */ public void setExpires(Instant expires) { this.expires = expires; } public String getIssuerAddress() { return issuerAddress; } public void setIssuerAddress(String issuerAddress) { this.issuerAddress = issuerAddress; } /** * @param sha SHA1 of the encrypted key */ public void setSHA1(String sha) { this.encrKeySha1Value = sha; } /** * @return SHA1 value of the encrypted key */ public String getSHA1() { return encrKeySha1Value; } public String getTokenType() { return tokenType; } public void setTokenType(String s) { tokenType = s; } public void setWsuId(String wsuId) { this.wsuId = wsuId; } public String getWsuId() { if (wsuId != null) { return wsuId; } Element elem = getAttachedReference(); if (elem != null) { String t = getIdFromSTR(elem); if (t != null) { return t; } } elem = getUnattachedReference(); if (elem != null) { String t = getIdFromSTR(elem); if (t != null) { return t; } } return null; } public static String getIdFromSTR(Element str) { Element child = DOMUtils.getFirstElement(str); if (child == null) { return null; } if ("KeyInfo".equals(child.getLocalName()) && WSConstants.SIG_NS.equals(child.getNamespaceURI())) { return DOMUtils.getContent(child); } else if (Reference.TOKEN.getLocalPart().equals(child.getLocalName()) && Reference.TOKEN.getNamespaceURI().equals(child.getNamespaceURI())) { return child.getAttributeNS(null, "URI").substring(1); } return null; } public void setX509Certificate(X509Certificate cert, Crypto cpt) { x509cert = cert; crypto = cpt; } public X509Certificate getX509Certificate() { return x509cert; } public Crypto getCrypto() { return crypto; } /** * Set a hash code associated with this token. * @param hash a hash code associated with this token */ public void setTokenHash(int hash) { tokenHash = hash; } /** * Get a hash code associated with this token. * @return a hash code associated with this token. */ public int getTokenHash() { return tokenHash; } /** * Set the principal associated with this SecurityToken * @param principal the principal associated with this SecurityToken */ public void setPrincipal(Principal principal) { this.principal = principal; } /** * Get the principal associated with this SecurityToken * @return the principal associated with this SecurityToken */ public Principal getPrincipal() { return principal; } /** * Set the SecurityContext associated with this SecurityToken * @param securityContext the SecurityContext associated with this SecurityToken */ public void setSecurityContext(SecurityContext securityContext) { this.securityContext = securityContext; } /** * Get the SecurityContext associated with this SecurityToken * @return the SecurityContext associated with this SecurityToken */ public SecurityContext getSecurityContext() { return securityContext; } public Key getKey() { return key; } public void setKey(Key key) { this.key = key; } public byte[] getData() { return data; } public void setData(byte[] data) { this.data = data; } private void writeObject(ObjectOutputStream stream) throws IOException { if (token != null && tokenStr == null) { tokenStr = DOM2Writer.nodeToString(token); } stream.defaultWriteObject(); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException, XMLStreamException { in.defaultReadObject(); if (token == null && tokenStr != null) { token = StaxUtils.read(new StringReader(tokenStr)).getDocumentElement(); } } }