/**
 * 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.ws.security.message.token;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.WSDocInfo;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.components.crypto.Crypto;
import org.apache.ws.security.kerberos.KrbSession;
import org.apache.ws.security.kerberos.KrbSessionCache;
import org.apache.ws.security.util.DOM2Writer;
import org.apache.ws.security.util.WSSecurityUtil;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.keys.content.x509.XMLX509IssuerSerial;
import org.apache.xml.security.keys.content.X509Data;
import org.apache.ws.security.util.Base64;
import org.apache.xml.security.utils.Constants;
import org.w3c.dom.*;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;

/**
 * Security Token Reference.
 * 
 * @author Davanum Srinivas (dims@yahoo.com).
 */
public class SecurityTokenReference {
	private static final Log log = LogFactory.getLog(SecurityTokenReference.class.getName());
	public static final String SECURITY_TOKEN_REFERENCE = "SecurityTokenReference";
	public static final String KEY_NAME = "KeyName";
	public static final String SKI_URI = WSConstants.X509TOKEN_NS + "#X509SubjectKeyIdentifier";
	public static final String THUMB_URI = WSConstants.SOAPMESSAGE_NS11 + "#"
			+ WSConstants.THUMBPRINT;
	public static final String SAML_ID_URI = WSConstants.SAMLTOKEN_NS + "#"
			+ WSConstants.SAML_ASSERTION_ID;
	public static final String ENC_KEY_SHA1_URI = WSConstants.SOAPMESSAGE_NS11 + "#"
			+ WSConstants.ENC_KEY_SHA1_URI;
	protected Element element = null;
	private XMLX509IssuerSerial issuerSerial = null;
	private byte[] skiBytes = null;
	private static boolean doDebug = false;

	/**
	 * Constructor.
	 * 
	 * @param elem
	 *            TODO
	 * @throws WSSecurityException
	 */
	public SecurityTokenReference(Element elem) throws WSSecurityException {
		doDebug = log.isDebugEnabled();
		this.element = elem;
		boolean goodElement = false;
		if (SECURITY_TOKEN_REFERENCE.equals(element.getLocalName())) {
			goodElement = WSConstants.WSSE_NS.equals(element.getNamespaceURI());
			// } else if (KEY_NAME.equals(element.getLocalName())) {
			// goodElement = WSConstants.SIG_NS.equals(element.getNamespaceURI());
		}
		if (!goodElement) {
			throw new WSSecurityException(WSSecurityException.FAILURE, "badElement", null);
		}
	}

	/**
	 * Constructor.
	 * 
	 * @param doc
	 *            TODO
	 */
	public SecurityTokenReference(Document doc) {
		doDebug = log.isDebugEnabled();
		this.element = doc.createElementNS(WSConstants.WSSE_NS, "wsse:SecurityTokenReference");
		WSSecurityUtil.setNamespace(this.element, WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX);
	}

	/**
	 * set the reference.
	 * 
	 * @param ref
	 */
	public void setReference(Reference ref) {
		Element elem = getFirstElement();
		if (elem != null) {
			this.element.replaceChild(ref.getElement(), elem);
		} else {
			this.element.appendChild(ref.getElement());
		}
	}

	/**
	 * Gets the Reference.
	 * 
	 * @return the <code>Reference</code> element contained in this SecurityTokenReference
	 * @throws WSSecurityException
	 */
	public Reference getReference() throws WSSecurityException {
		Element elem = getFirstElement();
		return new Reference(elem);
	}

	/**
	 * Gets the signing token element, which maybe a <code>BinarySecurityToken
	 * </code> or a SAML token.
	 * 
	 * The method gets the URI attribute of the {@link Reference} contained in the
	 * {@link SecurityTokenReference} and tries to find the referenced Element in the document.
	 * 
	 * @param doc
	 *            the document that contains the binary security token element. This could be
	 *            different from the document that contains the SecurityTokenReference (STR). See
	 *            STRTransform.derefenceBST() method
	 * @return Element containing the signing token, must be a BinarySecurityToken
	 * @throws WSSecurityException
	 *             When either no <code>Reference</code> element, or the found reference contains no
	 *             URI, or the referenced signing not found.
	 */
	public Element getTokenElement(Document doc, WSDocInfo docInfo, CallbackHandler cb)
			throws WSSecurityException {
		Reference ref = getReference();
		String uri = ref.getURI();
		if (doDebug) {
			log.debug("Token reference uri: " + uri);
		}
		if (uri == null) {
			throw new WSSecurityException(WSSecurityException.INVALID_SECURITY, "badReferenceURI");
		}

		Element tokElement = findTokenElement(doc, docInfo, cb, uri, ref.getValueType());

		if (tokElement == null) {
			throw new WSSecurityException(WSSecurityException.SECURITY_TOKEN_UNAVAILABLE,
					"noToken", new Object[] { uri });
		}
		return tokElement;
	}

	/**
	 * Gets the signing token element, which may be a <code>BinarySecurityToken
	 * </code> or a SAML token.
	 * 
	 * The method gets the value of the KeyIdentifier contained in the
	 * {@link SecurityTokenReference} and tries to find the referenced Element in the document.
	 * 
	 * @param doc
	 *            the document that contains the binary security token element. This could be
	 *            different from the document that contains the SecurityTokenReference (STR). See
	 *            STRTransform.derefenceBST() method
	 * @return Element containing the signing token
	 */
	public Element getKeyIdentifierTokenElement(Document doc, WSDocInfo docInfo, CallbackHandler cb)
			throws WSSecurityException {
		String value = getKeyIdentifierValue();
		String type = getKeyIdentifierValueType();
		if (doDebug) {
			log.debug("Token reference uri: " + value);
		}
		if (value == null) {
			throw new WSSecurityException(WSSecurityException.INVALID_SECURITY, "badReferenceURI");
		}

		Element tokElement = findTokenElement(doc, docInfo, cb, value, type);

		if (tokElement == null) {
			throw new WSSecurityException(WSSecurityException.SECURITY_TOKEN_UNAVAILABLE,
					"noToken", new Object[] { value });
		}
		return tokElement;
	}

	private Element findTokenElement(Document doc, WSDocInfo docInfo, CallbackHandler cb,
			String uri, String type) {
		Element tokElement = null;
		String id = uri;
		if (id.charAt(0) == '#') {
			id = id.substring(1);
		}
		//
		// If the type is a SAMLAssertionID then find the SAML assertion - first check
		// if it has been previously processed, else search the header for it
		//
		String assertionStr = WSConstants.WSS_SAML_NS + WSConstants.ASSERTION_LN;
		if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(type) || assertionStr.equals(type)) {
			Element sa = docInfo.getAssertion();
			if(sa == null){
                sa = (Element) WSSecurityUtil.findElement(docInfo.getDocument().getDocumentElement(),
                                                          WSConstants.ASSERTION_LN,
                                                          WSConstants.SAML_NS);
            }
            if (sa != null) {
				String saID = sa.getAttribute("AssertionID");
				if (doDebug) {
					log.debug("SAML token ID: " + saID);
				}
				if (saID.equals(id)) {
					tokElement = sa;
				}
			}
			if (tokElement == null) {
				Node assertion = WSSecurityUtil.findSAMLAssertionElementById(
						doc.getDocumentElement(), id);
				if (assertion != null) {
					tokElement = (Element) assertion;
				}
			}
		} else if (WSConstants.WSS_SAML2_KI_VALUE_TYPE
				.equals(type) || assertionStr.equals(type)) {
			Element sa = docInfo.getAssertion();
			if (sa == null) {
				sa = (Element) WSSecurityUtil.findElement(docInfo.getDocument()
						.getDocumentElement(), "Assertion",WSConstants.SAML2_NS);
			}
			if (sa != null) {
				String saID = sa.getAttribute("ID");
				if (doDebug)
					log.debug((new StringBuilder()).append("SAML token ID: ")
							.append(saID).toString());
				if (saID.equals(id))
					tokElement = sa;
			}
			if (tokElement == null) {
				Node assertion = WSSecurityUtil.findSAMLAssertionElementById(
						doc.getDocumentElement(), id);
				if (assertion != null)
					tokElement = (Element) assertion;
			}
		}

		//
		// Try to find a custom token
		//
		if (tokElement == null
				&& cb != null
				&& (WSConstants.WSC_SCT.equals(type)
						|| WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(type) 
						|| WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(type) 
						|| assertionStr.equals(type))) {
			// try to find a custom token
			WSPasswordCallback pwcb = new WSPasswordCallback(id, WSPasswordCallback.CUSTOM_TOKEN);
			try {
				cb.handle(new Callback[] { pwcb });
				Element assertionElem = pwcb.getCustomToken();
				if (assertionElem != null) {
					tokElement = (Element) doc.importNode(assertionElem, true);
				}
			} catch (Exception e) {
				log.debug(e.getMessage(), e);
				// Consume this failure
			}
		}

		//
		// Finally try to find the element by its Id
		//
		if (tokElement == null) {
			tokElement = WSSecurityUtil.getElementByWsuId(doc, uri);

			// In some scenarios id is used rather than wsu:Id
			if (tokElement == null) {
				tokElement = WSSecurityUtil.getElementByGenId(doc, uri);
			}
		}

		return tokElement;
	}

	/**
	 * Sets the KeyIdentifier Element as a X509 certificate. Takes a X509 certificate, converts its
	 * data into base 64 and inserts it into a <code>wsse:KeyIdentifier</code> element, which is
	 * placed in the <code>wsse:SecurityTokenReference</code> element.
	 * 
	 * @param cert
	 *            is the X509 certificate to be inserted as key identifier
	 */
	public void setKeyIdentifier(X509Certificate cert) throws WSSecurityException {
		Document doc = this.element.getOwnerDocument();
		byte data[] = null;
		try {
			data = cert.getEncoded();
		} catch (CertificateEncodingException e) {
			throw new WSSecurityException(WSSecurityException.SECURITY_TOKEN_UNAVAILABLE,
					"encodeError", null, e);
		}
		Text text = doc.createTextNode(Base64.encode(data));

		createKeyIdentifier(doc, X509Security.X509_V3_TYPE, text, true);
	}

	/**
	 * Sets the KeyIdentifier Element as a X509 Subject-Key-Identifier (SKI). Takes a X509
	 * certificate, gets it SKI data, converts into base 64 and inserts it into a
	 * <code>wsse:KeyIdentifier</code> element, which is placed in the
	 * <code>wsse:SecurityTokenReference</code> element.
	 * 
	 * @param cert
	 *            is the X509 certificate to get the SKI
	 * @param crypto
	 *            is the Crypto implementation. Used to read SKI info bytes from certificate
	 */
	public void setKeyIdentifierSKI(X509Certificate cert, Crypto crypto) throws WSSecurityException {
		//
		// As per the 1.1 specification, SKI can only be used for a V3 certificate
		//
		if (cert.getVersion() != 3) {
			throw new WSSecurityException(WSSecurityException.UNSUPPORTED_SECURITY_TOKEN,
					"invalidCertForSKI", new Object[] { new Integer(cert.getVersion()) });
		}

		Document doc = this.element.getOwnerDocument();
		byte data[] = crypto.getSKIBytesFromCert(cert);

		org.w3c.dom.Text text = doc.createTextNode(Base64.encode(data));
		createKeyIdentifier(doc, SKI_URI, text, true);
	}

	/**
	 * Sets the KeyIdentifier Element as a Thumbprint.
	 * 
	 * Takes a X509 certificate, computes its thumbprint using SHA-1, converts into base 64 and
	 * inserts it into a <code>wsse:KeyIdentifier</code> element, which is placed in the
	 * <code>wsse:SecurityTokenReference</code> element.
	 * 
	 * @param cert
	 *            is the X509 certificate to get the thumbprint
	 */
	public void setKeyIdentifierThumb(X509Certificate cert) throws WSSecurityException {
		Document doc = this.element.getOwnerDocument();
		MessageDigest sha = null;
		try {
			sha = MessageDigest.getInstance("SHA-1");
		} catch (NoSuchAlgorithmException e1) {
			throw new WSSecurityException(WSSecurityException.FAILURE, "noSHA1availabe", null, e1);
		}
		sha.reset();
		try {
			sha.update(cert.getEncoded());
		} catch (CertificateEncodingException e1) {
			throw new WSSecurityException(WSSecurityException.SECURITY_TOKEN_UNAVAILABLE,
					"encodeError", null, e1);
		}
		byte[] data = sha.digest();

		org.w3c.dom.Text text = doc.createTextNode(Base64.encode(data));
		createKeyIdentifier(doc, THUMB_URI, text, true);
	}

	public void setKeyIdentifierEncKeySHA1(String value) throws WSSecurityException {
		Document doc = this.element.getOwnerDocument();
		org.w3c.dom.Text text = doc.createTextNode(value);
		createKeyIdentifier(doc, ENC_KEY_SHA1_URI, text, true);
	}

	public void setSAMLKeyIdentifier(String keyIdVal) throws WSSecurityException {
		Document doc = this.element.getOwnerDocument();
		createKeyIdentifier(doc, SAML_ID_URI, doc.createTextNode(keyIdVal), false);
	}

	public void setKeyIdentifier(String valueType, String keyIdVal) throws WSSecurityException {
		Document doc = this.element.getOwnerDocument();
		createKeyIdentifier(doc, valueType, doc.createTextNode(keyIdVal), false);
	}

	private void createKeyIdentifier(Document doc, String uri, Node node, boolean base64) {
		Element keyId = doc.createElementNS(WSConstants.WSSE_NS, "wsse:KeyIdentifier");
		keyId.setAttributeNS(null, "ValueType", uri);
		if (base64) {
			keyId.setAttributeNS(null, "EncodingType", BinarySecurity.BASE64_ENCODING);
		}

		keyId.appendChild(node);
		Element elem = getFirstElement();
		if (elem != null) {
			this.element.replaceChild(keyId, elem);
		} else {
			this.element.appendChild(keyId);
		}
	}

	/**
	 * get the first child element.
	 * 
	 * @return the first <code>Element</code> child node
	 */
	public Element getFirstElement() {
		for (Node currentChild = this.element.getFirstChild(); currentChild != null; currentChild = currentChild
				.getNextSibling()) {
			if (currentChild instanceof Element) {
				return (Element) currentChild;
			}
		}
		return null;
	}

	/**
	 * Gets the KeyIdentifier.
	 * 
	 * @return the the X509 certificate or zero if a unknown key identifier type was detected.
	 */
	public X509Certificate[] getKeyIdentifier(Crypto crypto) throws WSSecurityException {
		Element elem = getFirstElement();
		String value = elem.getAttribute("ValueType");
		String alias = null;

		if (X509Security.X509_V3_TYPE.equals(value)) {
			X509Security token = new X509Security(elem);
			if (token != null) {
				X509Certificate cert = token.getX509Certificate(crypto);
				X509Certificate[] certs = new X509Certificate[1];
				certs[0] = cert;
				return certs;
			}
		} else if (SKI_URI.equals(value)) {
			alias = getX509SKIAlias(crypto);
		} else if (THUMB_URI.equals(value)) {
			Node node = getFirstElement().getFirstChild();
			if (node == null) {
				return null;
			}
			if (node.getNodeType() == Node.TEXT_NODE) {
				byte[] thumb = Base64.decode(((Text) node).getData());
				alias = crypto.getAliasForX509CertThumb(thumb);
			}
		}

		if (alias != null) {
			return crypto.getCertificates(alias);
		}
		return null;
	}

	public String getKeyIdentifierValue() {
		if (containsKeyIdentifier()) {
			Node node = getFirstElement().getFirstChild();
			if (node == null) {
				return null;
			}
			if (node.getNodeType() == Node.TEXT_NODE) {
				return ((Text) node).getData();
			}
		}
		return null;
	}

	public String getKeyIdentifierValueType() {
		if (containsKeyIdentifier()) {
			Element elem = getFirstElement();
			return elem.getAttribute("ValueType");
		}
		return null;
	}

	public String getX509SKIAlias(Crypto crypto) throws WSSecurityException {
		if (skiBytes == null) {
			skiBytes = getSKIBytes();
			if (skiBytes == null) {
				return null;
			}
		}
		String alias = crypto.getAliasForX509Cert(skiBytes);
		if (doDebug) {
			log.info("X509 SKI alias: " + alias);
		}
		return alias;
	}

	public byte[] getSKIBytes() {
		if (skiBytes != null) {
			return skiBytes;
		}
		Node node = getFirstElement().getFirstChild();
		if (node == null) {
			return null;
		}
		if (node.getNodeType() == Node.TEXT_NODE) {
			try {
				skiBytes = Base64.decode(((Text) node).getData());
			} catch (WSSecurityException e) {
				return null;
			}
		}
		return skiBytes;
	}

	/**
	 * Sets the X509 IssuerSerial data.
	 * 
	 * @param ref
	 *            the {@link XMLX509IssuerSerial} to put into this SecurityTokenReference
	 */
	public void setX509IssuerSerial(X509Data ref) {
		Element elem = getFirstElement();
		if (elem != null) {
			this.element.replaceChild(ref.getElement(), elem);
		} else {
			this.element.appendChild(ref.getElement());
		}
	}

	/**
	 * Gets the certificate identified with X509 issuerSerial data. This method first tries to get
	 * the embedded certificate. If this fails it checks if the certificate is in the keystore.
	 * 
	 * @return a certificate array or null if nothing found
	 */
	public X509Certificate[] getX509IssuerSerial(Crypto crypto) throws WSSecurityException {
		String alias = getX509IssuerSerialAlias(crypto);
		if (alias != null) {
			return crypto.getCertificates(alias);
		}
		return null;
	}

	/**
	 * Gets the alias name of the certificate identified with X509 issuerSerial data. The keystore
	 * identifies the certificate and the key with this alias name.
	 * 
	 * @return the alias name for the certificate or null if nothing found
	 */
	public String getX509IssuerSerialAlias(Crypto crypto) throws WSSecurityException {
		if (issuerSerial == null) {
			issuerSerial = getIssuerSerial();
			if (issuerSerial == null) {
				return null;
			}
		}

		String alias = crypto.getAliasForX509Cert(issuerSerial.getIssuerName(),
				issuerSerial.getSerialNumber());
		if (doDebug) {
			log.info("X509IssuerSerial alias: " + alias);
		}
		return alias;
	}

	private XMLX509IssuerSerial getIssuerSerial() throws WSSecurityException {
		if (issuerSerial != null) {
			return issuerSerial;
		}
		Element elem = getFirstElement();
		if (elem == null) {
			return null;
		}
		try {
			if (Constants._TAG_X509DATA.equals(elem.getLocalName())) {
				elem = (Element) WSSecurityUtil.findElement(elem, Constants._TAG_X509ISSUERSERIAL,
						Constants.SignatureSpecNS);
			}
			issuerSerial = new XMLX509IssuerSerial(elem, "");
		} catch (XMLSecurityException e) {
			throw new WSSecurityException(WSSecurityException.SECURITY_TOKEN_UNAVAILABLE,
					"noToken", new Object[] { "Issuer/Serial data element missing" }, e);
		}
		return issuerSerial;
	}

	/**
	 * Method containsReference
	 * 
	 * @return true if the <code>SecurtityTokenReference</code> contains a
	 *         <code>wsse:Reference</code> element
	 */
	public boolean containsReference() {
		return this.lengthReference() > 0;
	}

	/**
	 * Method lengthReference.
	 * 
	 * @return number of <code>wsse:Reference</code> elements in the
	 *         <code>SecurtityTokenReference</code>
	 */
	public int lengthReference() {
		return this.length(WSConstants.WSSE_NS, "Reference");
	}

	/**
	 * Method containsX509IssuerSerial
	 * 
	 * @return true if the <code>SecurtityTokenReference</code> contains a
	 *         <code>ds:IssuerSerial</code> element
	 */
	public boolean containsX509IssuerSerial() {
		return this.lengthX509IssuerSerial() > 0;
	}

	/**
	 * Method containsX509Data
	 * 
	 * @return true if the <code>SecurtityTokenReference</code> contains a <code>ds:X509Data</code>
	 *         element
	 */
	public boolean containsX509Data() {
		return this.lengthX509Data() > 0;
	}

	/**
	 * Method lengthX509IssuerSerial.
	 * 
	 * @return number of <code>ds:IssuerSerial</code> elements in the
	 *         <code>SecurtityTokenReference</code>
	 */
	public int lengthX509IssuerSerial() {
		return this.length(WSConstants.SIG_NS, Constants._TAG_X509ISSUERSERIAL);
	}

	/**
	 * Method lengthX509Data.
	 * 
	 * @return number of <code>ds:IssuerSerial</code> elements in the
	 *         <code>SecurtityTokenReference</code>
	 */
	public int lengthX509Data() {
		return this.length(WSConstants.SIG_NS, Constants._TAG_X509DATA);
	}

	/**
	 * Method containsKeyIdentifier.
	 * 
	 * @return true if the <code>SecurtityTokenReference</code> contains a
	 *         <code>wsse:KeyIdentifier</code> element
	 */
	public boolean containsKeyIdentifier() {
		return this.lengthKeyIdentifier() > 0;
	}

	/**
	 * Method lengthKeyIdentifier.
	 * 
	 * @return number of <code>wsse:KeyIdentifier</code> elements in the
	 *         <code>SecurtityTokenReference</code>
	 */
	public int lengthKeyIdentifier() {
		return this.length(WSConstants.WSSE_NS, "KeyIdentifier");
	}

	/**
	 * Method length.
	 * 
	 * @param namespace
	 * @param localname
	 * @return number of elements with matching localname and namespace
	 */
	public int length(String namespace, String localname) {
		NodeList childNodes = this.element.getChildNodes();
		int result = 0;
		for (int i = 0; i < childNodes.getLength(); i++) {
			Node n = childNodes.item(i);
			if (n.getNodeType() == Node.ELEMENT_NODE) {
				String ns = n.getNamespaceURI();
				String name = n.getLocalName();
				if ((((namespace != null) && namespace.equals(ns)) || ((namespace == null) && (ns == null)))
						&& (localname.equals(name))) {
					result++;
				}
			}
		}
		return result;
	}

	/**
	 * get the dom element.
	 * 
	 * @return TODO
	 */
	public Element getElement() {
		return this.element;
	}

	/**
	 * set the id.
	 * 
	 * @param id
	 */
	public void setID(String id) {
		String prefix = WSSecurityUtil.setNamespace(this.element, WSConstants.WSU_NS,
				WSConstants.WSU_PREFIX);
		this.element.setAttributeNS(WSConstants.WSU_NS, prefix + ":Id", id);
	}

	/**
	 * return the string representation.
	 * 
	 * @return TODO
	 */
	public String toString() {
		return DOM2Writer.nodeToString((Node) this.element);
	}

	/**
	 * 
	 * @param session
	 */
	public void setKerberosIdentifierThumb(KrbSession session) {
		Document doc = element.getOwnerDocument();
		Text node = doc.createTextNode(session.getThumbPrintEncoded());
		createKeyIdentifier(doc, KerberosSecurity.GSS_KERBEROSv5_AP_REQ_SHA1, node, false);
	}
	
	public boolean containsKerberosThumbprint() {
		NodeList childNodes = element.getChildNodes();
		int maxLength = childNodes.getLength();
		for (int i = 0; i < maxLength; i++) {
			Node n = childNodes.item(i);
			if (n.getNodeType() != 1)
				continue;
			Node valueType = n.getAttributes().getNamedItem("ValueType");
			if (valueType != null
					&& valueType
							.getNodeValue()
							.equals("http://docs.oasis-open.org/wss/oasis-wss-kerberos-token-profile-1.1#Kerberosv5APREQSHA1"))
				return true;
		}

		return false;
	}

	public KrbSession getKerberosSession() {
		KrbSession result = null;
		Element elem = (Element) WSSecurityUtil
				.findElement(
						element,
						"KeyIdentifier",
						"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

		String thumbPrint = elem.toString();
		thumbPrint = thumbPrint.substring(thumbPrint.indexOf(">") + 1);
		thumbPrint = thumbPrint.substring(0, thumbPrint.indexOf("<"));
		result = KrbSessionCache.getInstance().getSession(thumbPrint);
		return result;
	}
}
