| /* |
| * Copyright 2004,2005 The Apache Software Foundation. |
| * |
| * 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.apache.rahas; |
| |
| import java.io.Externalizable; |
| import java.io.IOException; |
| import java.io.ObjectInput; |
| import java.io.ObjectOutput; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.text.DateFormat; |
| import java.util.Date; |
| import java.util.Properties; |
| import java.time.LocalDate; |
| import java.time.LocalDateTime; |
| import java.time.Instant; |
| import java.time.ZoneOffset; |
| import java.time.ZonedDateTime; |
| |
| import javax.xml.namespace.QName; |
| import javax.xml.stream.XMLInputFactory; |
| import javax.xml.stream.XMLStreamException; |
| import javax.xml.stream.XMLStreamReader; |
| |
| import org.apache.axiom.om.OMAbstractFactory; |
| import org.apache.axiom.om.OMElement; |
| import org.apache.axiom.om.OMException; |
| import org.apache.axiom.om.OMFactory; |
| import org.apache.axiom.om.OMMetaFactory; |
| import org.apache.axiom.om.OMXMLBuilderFactory; |
| import org.apache.axiom.om.OMXMLParserWrapper; |
| import org.apache.axiom.om.OMXMLStreamReaderConfiguration; |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.wss4j.common.util.DateUtil; |
| import org.apache.wss4j.dom.WSConstants; |
| |
| /** |
| * This represents a security token which can have either one of 4 states. <ul> <li>ISSUED</li> <li>EXPIRED</li> |
| * <li>CACELLED</li> <li>RENEWED</li> </ul> Also this holds the <code>OMElement</code>s representing the token in its |
| * present state and the previous state. |
| * <p> |
| * These tokens are stored using the storage mechanism provided via the <code>TokenStorage</code> interface. |
| * |
| * @see org.apache.rahas.TokenStorage |
| */ |
| public class Token implements Externalizable { |
| |
| private static Log log = LogFactory.getLog(Token.class); |
| |
| public final static int ISSUED = 1; |
| |
| public final static int EXPIRED = 2; |
| |
| public final static int CANCELLED = 3; |
| |
| public final static int RENEWED = 4; |
| |
| /** |
| * Token identifier |
| */ |
| private String id; |
| |
| /** |
| * Current state of the token |
| */ |
| private int state = -1; |
| |
| /** |
| * The actual token in its current state |
| */ |
| private OMElement token; |
| |
| /** |
| * The token in its previous state |
| */ |
| private OMElement previousToken; |
| |
| /** |
| * 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 OMElement attachedReference; |
| |
| /** |
| * The RequestedUnattachedReference element NOTE : The oasis-200401-wss-soap-message-security-1.0 spec allows an |
| * extensibility mechanism for wsse:SecurityTokenRefence and wsse:Reference. Hence we cannot limit to the |
| * wsse:SecurityTokenReference\wsse:Reference case and only hold the URI and the ValueType values. |
| */ |
| private OMElement unattachedReference; |
| |
| /** |
| * A bag to hold any other properties |
| */ |
| private Properties properties; |
| |
| /** |
| * A flag to assist the TokenStorage |
| */ |
| private boolean changed; |
| |
| /** |
| * The secret associated with the Token |
| */ |
| private byte[] secret; |
| |
| /** |
| * Created time |
| */ |
| private Date created; |
| |
| /** |
| * Expiration time |
| */ |
| private Date expires; |
| |
| /** |
| * Issuer end point address |
| */ |
| private String issuerAddress; |
| |
| private String encrKeySha1Value; |
| |
| public Token() { |
| } |
| |
| public Token(String id, Date created, Date expires) { |
| this.id = id; |
| this.created = created; |
| this.expires = expires; |
| } |
| |
| public Token(String id, OMElement tokenElem, Date created, Date expires) |
| throws TrustException { |
| this.id = id; |
| OMMetaFactory metaFactory = OMAbstractFactory.getMetaFactory(OMAbstractFactory.FEATURE_DOM); |
| OMXMLStreamReaderConfiguration configuration = new OMXMLStreamReaderConfiguration(); |
| configuration.setNamespaceURIInterning(true); |
| this.token = OMXMLBuilderFactory.createStAXOMBuilder(metaFactory.getOMFactory(), |
| tokenElem.getXMLStreamReader(true, configuration)).getDocumentElement(); |
| this.created = created; |
| this.expires = expires; |
| } |
| |
| public Token(String id, OMElement tokenElem, OMElement lifetimeElem) |
| throws TrustException { |
| this.id = id; |
| OMMetaFactory metaFactory = OMAbstractFactory.getMetaFactory(OMAbstractFactory.FEATURE_DOM); |
| OMXMLStreamReaderConfiguration configuration = new OMXMLStreamReaderConfiguration(); |
| configuration.setNamespaceURIInterning(true); |
| this.token = OMXMLBuilderFactory.createStAXOMBuilder(metaFactory.getOMFactory(), |
| tokenElem.getXMLStreamReader(true, configuration)).getDocumentElement(); |
| this.processLifeTime(lifetimeElem); |
| } |
| |
| /** |
| * @param lifetimeElem |
| * @throws TrustException |
| */ |
| private void processLifeTime(OMElement lifetimeElem) |
| throws TrustException { |
| try { |
| OMElement createdElem = |
| lifetimeElem.getFirstChildWithName(new QName(WSConstants.WSU_NS, WSConstants.CREATED_LN)); |
| |
| LocalDateTime localDateCreated = LocalDateTime.parse(createdElem.getText(), DateUtil.getDateTimeFormatter(true)); |
| this.created = Date.from(localDateCreated.atZone(ZoneOffset.UTC).toInstant()); |
| |
| OMElement expiresElem = |
| lifetimeElem.getFirstChildWithName(new QName(WSConstants.WSU_NS, WSConstants.EXPIRES_LN)); |
| |
| LocalDateTime localDateExpires = LocalDateTime.parse(expiresElem.getText(), DateUtil.getDateTimeFormatter(true)); |
| this.expires = Date.from(localDateExpires.atZone(ZoneOffset.UTC).toInstant()); |
| |
| } catch (OMException e) { |
| throw new TrustException("lifeTimeProcessingError", new String[]{lifetimeElem.toString()}, e); |
| } catch (Exception e) { |
| throw new TrustException("lifeTimeProcessingError", new String[]{lifetimeElem.toString()}, e); |
| } |
| } |
| |
| /** |
| * @return Returns the changed. |
| */ |
| public boolean isChanged() { |
| return changed; |
| } |
| |
| /** |
| * @param chnaged The changed to set. |
| */ |
| public void setChanged(boolean chnaged) { |
| this.changed = chnaged; |
| } |
| |
| /** |
| * @return Returns the properties. |
| */ |
| public Properties getProperties() { |
| return properties; |
| } |
| |
| /** |
| * @param properties The properties to set. |
| */ |
| public void setProperties(Properties properties) { |
| this.properties = properties; |
| } |
| |
| /** |
| * @return Returns the state. |
| */ |
| public int getState() { |
| return state; |
| } |
| |
| /** |
| * @param state The state to set. |
| */ |
| public void setState(int state) { |
| this.state = state; |
| } |
| |
| /** |
| * @return Returns the token. |
| */ |
| public OMElement getToken() { |
| return token; |
| } |
| |
| /** |
| * @param token The token to set. |
| */ |
| public void setToken(OMElement token) { |
| this.token = token; |
| } |
| |
| /** |
| * @return Returns the id. |
| */ |
| public String getId() { |
| return id; |
| } |
| |
| /** |
| * @return Returns the presivousToken. |
| */ |
| public OMElement getPreviousToken() { |
| return previousToken; |
| } |
| |
| /** |
| * @param presivousToken The presivousToken to set. |
| */ |
| public void setPreviousToken(OMElement presivousToken) { |
| OMMetaFactory metaFactory = OMAbstractFactory.getMetaFactory(OMAbstractFactory.FEATURE_DOM); |
| this.previousToken = OMXMLBuilderFactory.createStAXOMBuilder(metaFactory.getOMFactory(), |
| presivousToken.getXMLStreamReader()).getDocumentElement(); |
| } |
| |
| /** |
| * @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 OMElement getAttachedReference() { |
| return attachedReference; |
| } |
| |
| /** |
| * @param attachedReference The attachedReference to set. |
| */ |
| public void setAttachedReference(OMElement attachedReference) { |
| if (attachedReference != null) { |
| OMMetaFactory metaFactory = OMAbstractFactory.getMetaFactory(OMAbstractFactory.FEATURE_DOM); |
| this.attachedReference = |
| OMXMLBuilderFactory.createStAXOMBuilder(metaFactory.getOMFactory(), |
| attachedReference.getXMLStreamReader()).getDocumentElement(); |
| } |
| } |
| |
| /** |
| * @return Returns the unattachedReference. |
| */ |
| public OMElement getUnattachedReference() { |
| return unattachedReference; |
| } |
| |
| /** |
| * @param unattachedReference The unattachedReference to set. |
| */ |
| public void setUnattachedReference(OMElement unattachedReference) { |
| if (unattachedReference != null) { |
| OMMetaFactory metaFactory = OMAbstractFactory.getMetaFactory(OMAbstractFactory.FEATURE_DOM); |
| this.unattachedReference = |
| OMXMLBuilderFactory.createStAXOMBuilder(metaFactory.getOMFactory(), |
| unattachedReference.getXMLStreamReader()).getDocumentElement(); |
| } |
| } |
| |
| /** |
| * @return Returns the created. |
| */ |
| public Date getCreated() { |
| return created; |
| } |
| |
| /** |
| * @return Returns the expires. |
| */ |
| public Date getExpires() { |
| return expires; |
| } |
| |
| /** |
| * @param expires The expires to set. |
| */ |
| public void setExpires(Date expires) { |
| this.expires = expires; |
| } |
| |
| public String getIssuerAddress() { |
| return issuerAddress; |
| } |
| |
| public void setIssuerAddress(String issuerAddress) { |
| this.issuerAddress = issuerAddress; |
| } |
| |
| /** |
| * Implementing serialize logic according to our own protocol. We had to follow this, because |
| * OMElement class is not serializable. Making OMElement serializable will have an huge impact |
| * on other components. Therefore implementing serialization logic according to a manual |
| * protocol. |
| * @param out Stream which writes serialized bytes. |
| * @throws IOException If unable to serialize particular member. |
| */ |
| public void writeExternal(ObjectOutput out) |
| throws IOException { |
| |
| out.writeObject(this.id); |
| |
| out.writeInt(this.state); |
| |
| String stringElement = convertOMElementToString(this.token); |
| out.writeObject(stringElement); |
| |
| stringElement = convertOMElementToString(this.previousToken); |
| out.writeObject(stringElement); |
| |
| stringElement = convertOMElementToString(this.attachedReference); |
| out.writeObject(stringElement); |
| |
| stringElement = convertOMElementToString(this.unattachedReference); |
| out.writeObject(stringElement); |
| |
| out.writeObject(this.properties); |
| |
| out.writeBoolean(this.changed); |
| |
| int secretLength = 0; |
| if (null != this.secret) { |
| secretLength = this.secret.length; |
| } |
| |
| // First write the length of secret |
| out.writeInt(secretLength); |
| if (0 != secretLength) { |
| out.write(this.secret); |
| } |
| |
| out.writeObject(this.created); |
| |
| out.writeObject(this.expires); |
| |
| out.writeObject(this.issuerAddress); |
| |
| out.writeObject(this.encrKeySha1Value); |
| } |
| |
| /** |
| * Implementing de-serialization logic in accordance with the serialization logic. |
| * @param in Stream which used to read data. |
| * @throws IOException If unable to de-serialize particular data member. |
| * @throws ClassNotFoundException |
| */ |
| public void readExternal(ObjectInput in) |
| throws IOException, ClassNotFoundException { |
| |
| this.id = (String)in.readObject(); |
| |
| this.state = in.readInt(); |
| |
| String stringElement = (String)in.readObject(); |
| this.token = convertStringToOMElement(stringElement); |
| |
| stringElement = (String)in.readObject(); |
| this.previousToken = convertStringToOMElement(stringElement); |
| |
| stringElement = (String)in.readObject(); |
| this.attachedReference = convertStringToOMElement(stringElement); |
| |
| stringElement = (String)in.readObject(); |
| this.unattachedReference = convertStringToOMElement(stringElement); |
| |
| this.properties = (Properties)in.readObject(); |
| |
| this.changed = in.readBoolean(); |
| |
| // Read the length of the secret |
| int secretLength = in.readInt(); |
| |
| if (0 != secretLength) { |
| byte[] buffer = new byte[secretLength]; |
| if (secretLength != in.read(buffer)) { |
| throw new IllegalStateException("Bytes read from the secret key is not equal to serialized length"); |
| } |
| this.secret = buffer; |
| }else{ |
| this.secret = null; |
| } |
| |
| this.created = (Date)in.readObject(); |
| |
| this.expires = (Date)in.readObject(); |
| |
| this.issuerAddress = (String)in.readObject(); |
| |
| this.encrKeySha1Value = (String)in.readObject(); |
| } |
| |
| private String convertOMElementToString(OMElement element) |
| throws IOException { |
| String serializedToken = ""; |
| |
| if (null == element) { |
| return serializedToken; |
| } |
| |
| try { |
| serializedToken = element.toStringWithConsume(); |
| } catch (XMLStreamException e) { |
| throw new IOException("Could not serialize token OM element"); |
| } |
| |
| return serializedToken; |
| } |
| |
| private OMElement convertStringToOMElement(String stringElement) |
| throws IOException { |
| |
| if (null == stringElement || stringElement.trim().equals("")) { |
| return null; |
| } |
| |
| try { |
| Reader in = new StringReader(stringElement); |
| XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(in); |
| OMXMLParserWrapper builder = OMXMLBuilderFactory.createStAXOMBuilder(parser); |
| OMElement documentElement = builder.getDocumentElement(); |
| |
| XMLStreamReader llomReader = documentElement.getXMLStreamReader(); |
| OMMetaFactory metaFactory = OMAbstractFactory.getMetaFactory(OMAbstractFactory.FEATURE_DOM); |
| OMFactory doomFactory = metaFactory.getOMFactory(); |
| OMXMLParserWrapper doomBuilder = OMXMLBuilderFactory.createStAXOMBuilder(doomFactory, llomReader); |
| return doomBuilder.getDocumentElement(); |
| |
| } catch (XMLStreamException e) { |
| log.error("Cannot convert de-serialized string to OMElement. Could not create XML stream.", e); |
| // IOException only has a constructor supporting exception chaining starting with Java 1.6 |
| IOException ex = new IOException("Cannot convert de-serialized string to OMElement. Could not create XML stream."); |
| ex.initCause(e); |
| throw ex; |
| } |
| } |
| } |