Package org.apache.wss4j.dom.message.token

Source Code of org.apache.wss4j.dom.message.token.UsernameToken

/**
* 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.wss4j.dom.message.token;

import java.io.IOException;
import java.security.Principal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;

import org.apache.wss4j.common.bsp.BSPRule;
import org.apache.wss4j.common.ext.WSPasswordCallback;
import org.apache.wss4j.common.ext.WSSecurityException;
import org.apache.wss4j.common.principal.WSUsernameTokenPrincipalImpl;
import org.apache.wss4j.common.util.DOM2Writer;
import org.apache.wss4j.common.util.DateUtil;
import org.apache.wss4j.common.util.UsernameTokenUtil;
import org.apache.wss4j.common.util.WSCurrentTimeSource;
import org.apache.wss4j.common.util.WSTimeSource;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.WSSConfig;
import org.apache.wss4j.dom.bsp.BSPEnforcer;
import org.apache.wss4j.dom.handler.RequestData;
import org.apache.wss4j.dom.util.WSSecurityUtil;
import org.apache.wss4j.dom.util.XmlSchemaDateFormat;
import org.apache.xml.security.exceptions.Base64DecodingException;
import org.apache.xml.security.utils.Base64;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

/**
* UsernameToken according to WS Security specifications, UsernameToken profile.
*
* Enhanced to support digest password type for username token signature
* Enhanced to support passwordless usernametokens as allowed by spec.
*/
public class UsernameToken {
    public static final String BASE64_ENCODING = WSConstants.SOAPMESSAGE_NS + "#Base64Binary";
    public static final String PASSWORD_TYPE = "passwordType";
    public static final int DEFAULT_ITERATION = 1000;
    public static final QName TOKEN =
        new QName(WSConstants.WSSE_NS, WSConstants.USERNAME_TOKEN_LN);
   
    private static final org.slf4j.Logger LOG =
        org.slf4j.LoggerFactory.getLogger(UsernameToken.class);
    private static final boolean DO_DEBUG = LOG.isDebugEnabled();

    private Element element ;
    private Element elementUsername;
    private Element elementPassword;
    private Element elementNonce;
    private Element elementCreated;
    private Element elementSalt;
    private Element elementIteration;
    private String passwordType;
    private boolean hashed = true;
    private String rawPassword;        // enhancement by Alberto Coletti
    private boolean passwordsAreEncoded;
    private Date createdDate;
   
    /**
     * Constructs a <code>UsernameToken</code> object and parses the
     * <code>wsse:UsernameToken</code> element to initialize it.
     *
     * @param elem the <code>wsse:UsernameToken</code> element that contains
     *             the UsernameToken data
     * @param allowNamespaceQualifiedPasswordTypes whether to allow (wsse)
     *        namespace qualified password types or not (for interop with WCF)
     * @param bspEnforcer a BSPEnforcer instance to enforce BSP rules
     * @throws WSSecurityException
     */
    public UsernameToken(
        Element elem,
        boolean allowNamespaceQualifiedPasswordTypes,
        BSPEnforcer bspEnforcer
    ) throws WSSecurityException {
        element = elem;
        QName el = new QName(element.getNamespaceURI(), element.getLocalName());
        if (!el.equals(TOKEN)) {
            throw new WSSecurityException(
                WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN,
                "badElement",
                TOKEN,
                el
            );
        }
        elementUsername =
            WSSecurityUtil.getDirectChildElement(
                element, WSConstants.USERNAME_LN, WSConstants.WSSE_NS
            );
        elementPassword =
            WSSecurityUtil.getDirectChildElement(
                element, WSConstants.PASSWORD_LN, WSConstants.WSSE_NS
            );
        elementNonce =
            WSSecurityUtil.getDirectChildElement(
                element, WSConstants.NONCE_LN, WSConstants.WSSE_NS
            );
        elementCreated =
            WSSecurityUtil.getDirectChildElement(
                element, WSConstants.CREATED_LN, WSConstants.WSU_NS
            );
        elementSalt =
            WSSecurityUtil.getDirectChildElement(
                element, WSConstants.SALT_LN, WSConstants.WSSE11_NS
            );
        elementIteration =
            WSSecurityUtil.getDirectChildElement(
                element, WSConstants.ITERATION_LN, WSConstants.WSSE11_NS
            );
        if (elementUsername == null) {
            throw new WSSecurityException(
                WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN,
                "badUsernameToken",
                "Username is missing"
            );
        }
       
        checkBSPCompliance(bspEnforcer);
       
        hashed = false;
        if (elementSalt != null) {
            //
            // If the UsernameToken is to be used for key derivation, the (1.1)
            // spec says that it cannot contain a password, and it must contain
            // an Iteration element
            //
            if (elementPassword != null || elementIteration == null) {
                throw new WSSecurityException(
                    WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN,
                    "badUsernameToken",
                    "Password is missing"
                );
            }
            return;
        }
       
        // Guard against a malicious user sending a bogus iteration value
        if (elementIteration != null) {
            String iter = nodeString(elementIteration);
            if (iter != null) {
                int iterInt = Integer.parseInt(iter);
                if (iterInt < 0 || iterInt > 10000) {
                    throw new WSSecurityException(
                        WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN,
                        "badUsernameToken",
                        "Iteration is missing"
                    );
                }
            }
        }
       
        if (elementPassword != null) {
            if (elementPassword.hasAttribute(WSConstants.PASSWORD_TYPE_ATTR)) {
                passwordType = elementPassword.getAttributeNS(null, WSConstants.PASSWORD_TYPE_ATTR);
            } else if (elementPassword.hasAttributeNS(
                WSConstants.WSSE_NS, WSConstants.PASSWORD_TYPE_ATTR)
            ) {
                if (allowNamespaceQualifiedPasswordTypes) {
                    passwordType =
                        elementPassword.getAttributeNS(
                            WSConstants.WSSE_NS, WSConstants.PASSWORD_TYPE_ATTR
                        );
                } else {
                    throw new WSSecurityException(
                        WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN,
                        "badUsernameToken",
                        "The Password Type is not allowed to be namespace qualified"
                    );
                }
            }
           
        }
        if (WSConstants.PASSWORD_DIGEST.equals(passwordType)) {
            hashed = true;
            if (elementNonce == null || elementCreated == null) {
                throw new WSSecurityException(
                    WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN,
                    "badUsernameToken",
                    "Nonce or Created is missing"
                );
            }
        }
       
        if (elementCreated != null) {
            String createdString = getCreated();
            if (createdString != null && !"".equals(createdString)) {
                XMLGregorianCalendar createdCalendar = null;
                try {
                    createdCalendar =
                        WSSConfig.datatypeFactory.newXMLGregorianCalendar(createdString);
                } catch (IllegalArgumentException e) {
                    throw new WSSecurityException(
                        WSSecurityException.ErrorCode.INVALID_SECURITY_TOKEN,
                        "badUsernameToken", e,
                        "Error parsing UsernameToken Created value"
                    );
                }
                createdDate = createdCalendar.toGregorianCalendar().getTime();
            }
        }
    }

    /**
     * Constructs a <code>UsernameToken</code> object according to the defined
     * parameters. <p/> This constructs set the password encoding to
     * {@link WSConstants#PASSWORD_DIGEST}
     *
     * @param doc the SOAP envelope as <code>Document</code>
     */
    public UsernameToken(boolean milliseconds, Document doc) {
        this(milliseconds, doc, WSConstants.PASSWORD_DIGEST);
    }

    /**
     * Constructs a <code>UsernameToken</code> object according to the defined
     * parameters.
     *
     * @param doc the SOAP envelope as <code>Document</code>
     * @param pwType the required password encoding, either
     *               {@link WSConstants#PASSWORD_DIGEST} or
     *               {@link WSConstants#PASSWORD_TEXT} or
     *               {@link WSConstants#PW_NONE} <code>null</code> if no
     *               password required
     */
    public UsernameToken(boolean milliseconds, Document doc, String pwType) {
        this(milliseconds, doc, new WSCurrentTimeSource(), pwType);
    }
   
    public UsernameToken(boolean milliseconds, Document doc, WSTimeSource timeSource, String pwType) {
        element =
            doc.createElementNS(WSConstants.WSSE_NS, "wsse:" + WSConstants.USERNAME_TOKEN_LN);

        elementUsername =
            doc.createElementNS(WSConstants.WSSE_NS, "wsse:" + WSConstants.USERNAME_LN);
        elementUsername.appendChild(doc.createTextNode(""));
        element.appendChild(elementUsername);

        if (pwType != null) {
            elementPassword =
                doc.createElementNS(WSConstants.WSSE_NS, "wsse:" + WSConstants.PASSWORD_LN);
            elementPassword.appendChild(doc.createTextNode(""));
            element.appendChild(elementPassword);

            passwordType = pwType;
            if (passwordType.equals(WSConstants.PASSWORD_DIGEST)) {
                addNonce(doc);
                addCreated(milliseconds, timeSource, doc);
            } else {
                hashed = false;
            }
        }
    }
   
    /**
     * Add the WSSE Namespace to this UT. The namespace is not added by default for
     * efficiency purposes.
     */
    public void addWSSENamespace() {
        WSSecurityUtil.setNamespace(element, WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX);
    }
   
    /**
     * Add the WSU Namespace to this UT. The namespace is not added by default for
     * efficiency purposes.
     */
    public void addWSUNamespace() {
        WSSecurityUtil.setNamespace(element, WSConstants.WSU_NS, WSConstants.WSU_PREFIX);
    }

    /**
     * Creates and adds a Nonce element to this UsernameToken
     */
    public void addNonce(Document doc) {
        if (elementNonce != null) {
            return;
        }
        byte[] nonceValue = null;
        try {
            nonceValue = WSSecurityUtil.generateNonce(16);
        } catch (WSSecurityException ex) {
            LOG.debug(ex.getMessage(), ex);
            return;
        }
        elementNonce = doc.createElementNS(WSConstants.WSSE_NS, "wsse:" + WSConstants.NONCE_LN);
        elementNonce.appendChild(doc.createTextNode(Base64.encode(nonceValue)));
        elementNonce.setAttributeNS(null, "EncodingType", BASE64_ENCODING);
        element.appendChild(elementNonce);
    }

    /**
     * Creates and adds a Created element to this UsernameToken
     */
    public void addCreated(boolean milliseconds, Document doc) {
        addCreated(milliseconds, new WSCurrentTimeSource(), doc);
    }
   
    /**
     * Creates and adds a Created element to this UsernameToken
     */
    public void addCreated(boolean milliseconds, WSTimeSource timeSource, Document doc) {
        if (elementCreated != null) {
            return;
        }
        DateFormat zulu = null;
        if (milliseconds) {
            zulu = new XmlSchemaDateFormat();
        } else {
            zulu = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
            zulu.setTimeZone(TimeZone.getTimeZone("UTC"));
        }
        elementCreated =
            doc.createElementNS(
                WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" + WSConstants.CREATED_LN
            );
        Date currentTime = timeSource.now();
        elementCreated.appendChild(doc.createTextNode(zulu.format(currentTime)));
        element.appendChild(elementCreated);
    }

    /**
     * Adds and optionally creates a Salt element to this UsernameToken.
     *
     * If the <code>saltValue</code> is <code>null</code> the the method
     * generates a new salt. Otherwise it uses the the given value.
     *
     * @param doc The Document for the UsernameToken
     * @param saltValue The salt to add, if null generate a new salt value
     * @param mac If <code>true</code> then an optionally generated value is
     *            usable for a MAC
     * @return Returns the added salt
     */
    public byte[] addSalt(Document doc, byte[] saltValue, boolean mac) {
        if (saltValue == null) {
            saltValue = UsernameTokenUtil.generateSalt(mac);
        }
        elementSalt =
            doc.createElementNS(
                WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX + ":" + WSConstants.SALT_LN
            );
        WSSecurityUtil.setNamespace(element, WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX);
        elementSalt.appendChild(doc.createTextNode(Base64.encode(saltValue)));
        element.appendChild(elementSalt);
        return saltValue;
    }

    /**
     * Creates and adds a Iteration element to this UsernameToken
     */
    public void addIteration(Document doc, int iteration) {
        String text = "" + iteration;
        elementIteration =
            doc.createElementNS(
                WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX + ":" + WSConstants.ITERATION_LN
            );
        WSSecurityUtil.setNamespace(element, WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX);
        elementIteration.appendChild(doc.createTextNode(text));
        element.appendChild(elementIteration);
    }

    /**
     * Get the user name.
     *
     * @return the data from the user name element.
     */
    public String getName() {
        return nodeString(elementUsername);
    }

    /**
     * Set the user name.
     *
     * @param name sets a text node containing the use name into the user name
     *             element.
     */
    public void setName(String name) {
        Text node = getFirstNode(elementUsername);
        node.setData(name);
    }

    /**
     * Get the nonce.
     *
     * @return the data from the nonce element.
     */
    public String getNonce() {
        return nodeString(elementNonce);
    }

    /**
     * Get the created timestamp.
     *
     * @return the data from the created time element.
     */
    public String getCreated() {
        return nodeString(elementCreated);
    }
   
    /**
     * Return the Created Element as a Date object
     * @return the Created Date
     */
    public Date getCreatedDate() {
       return createdDate;
    }

    /**
     * Gets the password string. This is the password as it is in the password
     * element of a username token. Thus it can be either plain text or the
     * password digest value.
     *
     * @return the password string or <code>null</code> if no such node exists.
     */
    public String getPassword() {
        String password = nodeString(elementPassword);
        // See WSS-219
        if (password == null && elementPassword != null) {
            return "";
        }
        return password;
    }
   
    /**
     * Return true if this UsernameToken contains a Password element
     */
    public boolean containsPasswordElement() {
        return elementPassword != null;
    }

    /**
     * Get the Salt value of this UsernameToken.
     *
     * @return Returns the binary Salt value or <code>null</code> if no Salt
     *         value is available in the username token.
     * @throws WSSecurityException
     */
    public byte[] getSalt() throws WSSecurityException {
        String salt = nodeString(elementSalt);
        if (salt != null) {
            try {
                return Base64.decode(salt);
            } catch (Base64DecodingException e) {
                throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "decoding.general", e
                );
            }
        }
        return null;
    }

    /**
     * Get the Iteration value of this UsernameToken.
     *
     * @return Returns the Iteration value. If no Iteration was specified in the
     *         username token the default value according to the specification
     *         is returned.
     */
    public int getIteration() {
        String iter = nodeString(elementIteration);
        if (iter != null) {
            return Integer.parseInt(iter);
        }
        return DEFAULT_ITERATION;
    }

    /**
     * Get the hashed indicator. If the indicator is <code>true> the password of the
     * <code>UsernameToken</code> was encoded using {@link WSConstants#PASSWORD_DIGEST}
     *
     * @return the hashed indicator.
     */
    public boolean isHashed() {
        return hashed;
    }

    /**
     * @return Returns the passwordType.
     */
    public String getPasswordType() {
        return passwordType;
    }

    /**
     * Sets the password string. This function sets the password in the
     * <code>UsernameToken</code> either as plain text or encodes the password
     * according to the WS Security specifications, UsernameToken profile, into
     * a password digest.
     *
     * @param pwd the password to use
     */
    public void setPassword(String pwd) {
        if (pwd == null) {
            if (passwordType != null) {
                throw new IllegalArgumentException("pwd == null but a password is needed");
            } else {
                // Ignore setting the password.
                return;
            }
        }
       
        rawPassword = pwd;             // enhancement by Alberto coletti
        Text node = getFirstNode(elementPassword);
        try {
            if (hashed) {
                if (passwordsAreEncoded) {
                    node.setData(doPasswordDigest(getNonce(), getCreated(), Base64.decode(pwd)));
                } else {
                    node.setData(doPasswordDigest(getNonce(), getCreated(), pwd));
                }
            } else {
                node.setData(pwd);
            }
            if (passwordType != null) {
                elementPassword.setAttributeNS(null, "Type", passwordType);
            }
        } catch (Exception e) {
            if (DO_DEBUG) {
                LOG.debug(e.getMessage(), e);
            }
        }
    }

    /**
     * Set the raw (plain text) password used to compute secret key.
     */
    public void setRawPassword(RequestData data) throws WSSecurityException {
        WSPasswordCallback pwCb =
            new WSPasswordCallback(
                getName(), getPassword(), getPasswordType(),
                WSPasswordCallback.USERNAME_TOKEN
            );
       
        if (data.getCallbackHandler() == null) {
            LOG.debug("CallbackHandler is null");
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
        }
        try {
            data.getCallbackHandler().handle(new Callback[]{pwCb});
        } catch (IOException e) {
            if (LOG.isDebugEnabled()) {
                LOG.debug(e.getMessage(), e);
            }
            throw new WSSecurityException(
                WSSecurityException.ErrorCode.FAILED_AUTHENTICATION, e
            );
        } catch (UnsupportedCallbackException e) {
            if (LOG.isDebugEnabled()) {
                LOG.debug(e.getMessage(), e);
            }
            throw new WSSecurityException(
                WSSecurityException.ErrorCode.FAILED_AUTHENTICATION, e
            );
        }
        rawPassword = pwCb.getPassword();
    }
   
    /**
     * @param passwordsAreEncoded whether passwords are encoded
     */
    public void setPasswordsAreEncoded(boolean passwordsAreEncoded) {
        this.passwordsAreEncoded = passwordsAreEncoded;
    }
   
    /**
     * @return whether passwords are encoded
     */
    public boolean getPasswordsAreEncoded() {
        return passwordsAreEncoded;
    }
   
    public static String doPasswordDigest(String nonce, String created, byte[] password) {
        String passwdDigest = null;
        try {
            byte[] b1 = nonce != null ? Base64.decode(nonce) : new byte[0];
            byte[] b2 = created != null ? created.getBytes("UTF-8") : new byte[0];
            byte[] b3 = password;
            byte[] b4 = new byte[b1.length + b2.length + b3.length];
            int offset = 0;
            System.arraycopy(b1, 0, b4, offset, b1.length);
            offset += b1.length;
           
            System.arraycopy(b2, 0, b4, offset, b2.length);
            offset += b2.length;

            System.arraycopy(b3, 0, b4, offset, b3.length);
           
            byte[] digestBytes = WSSecurityUtil.generateDigest(b4);
            passwdDigest = Base64.encode(digestBytes);
        } catch (Exception e) {
            if (DO_DEBUG) {
                LOG.debug(e.getMessage(), e);
            }
        }
        return passwdDigest;
    }

    public static String doPasswordDigest(String nonce, String created, String password) {
        String passwdDigest = null;
        try {
            passwdDigest = doPasswordDigest(nonce, created, password.getBytes("UTF-8"));
        } catch (Exception e) {
            if (DO_DEBUG) {
                LOG.debug(e.getMessage(), e);
            }
        }
        return passwdDigest;
    }

    /**
     * Returns the first text node of an element.
     *
     * @param e the element to get the node from
     * @return the first text node or <code>null</code> if node is null or is
     *         not a text node
     */
    private Text getFirstNode(Element e) {
        Node node = e.getFirstChild();
        return node != null && Node.TEXT_NODE == node.getNodeType() ? (Text) node : null;
    }

    /**
     * Returns the data of an element as String or null if either the the element
     * does not contain a Text node or the node is empty.
     *
     * @param e DOM element
     * @return Element text node data as String
     */
    private String nodeString(Element e) {
        if (e != null) {
            Node node = e.getFirstChild();
            StringBuilder builder = new StringBuilder();
            boolean found = false;
            while (node != null) {
                if (Node.TEXT_NODE == node.getNodeType()) {
                    found = true;
                    builder.append(((Text)node).getData());
                }
                node = node.getNextSibling();
            }
           
            if (!found) {
                return null;
            }
            return builder.toString();
        }
        return null;
    }

    /**
     * Returns the dom element of this <code>UsernameToken</code> object.
     *
     * @return the <code>wsse:UsernameToken</code> element
     */
    public Element getElement() {
        return element;
    }

    /**
     * Returns the string representation of the token.
     *
     * @return a XML string representation
     */
    public String toString() {
        return DOM2Writer.nodeToString(element);
    }

    /**
     * Gets the id.
     *
     * @return the value of the <code>wsu:Id</code> attribute of this username
     *         token
     */
    public String getID() {
        return element.getAttributeNS(WSConstants.WSU_NS, "Id");
    }

    /**
     * Set the id of this username token.
     *
     * @param id
     *            the value for the <code>wsu:Id</code> attribute of this
     *            username token
     */
    public void setID(String id) {
        element.setAttributeNS(WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":Id", id);
    }

    /**
     * This method gets a derived key as defined in WSS Username Token Profile.
     *
     * @return Returns the derived key as a byte array
     * @throws WSSecurityException
     */
    public byte[] getDerivedKey(BSPEnforcer bspEnforcer) throws WSSecurityException {
        if (rawPassword == null) {
            LOG.debug("The raw password was null");
            throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
        }
       
        if (elementSalt == null) {
            // We must have a salt element to use this token for a derived key
            bspEnforcer.handleBSPRule(BSPRule.R4217);
        }
        if (elementIteration == null) {
            // we must have an iteration element to use this token for a derived key
            bspEnforcer.handleBSPRule(BSPRule.R4218);
        } else {
            String iter = nodeString(elementIteration);
            if (iter == null || Integer.parseInt(iter) < 1000) {
                bspEnforcer.handleBSPRule(BSPRule.R4218);
            }
        }
       
        int iteration = getIteration();
        byte[] salt = getSalt();
        if (passwordsAreEncoded) {
            try {
                return UsernameTokenUtil.generateDerivedKey(Base64.decode(rawPassword), salt, iteration);
            } catch (Base64DecodingException e) {
                throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "decoding.general", e
                );
            }
        } else {
            return UsernameTokenUtil.generateDerivedKey(rawPassword, salt, iteration);
        }
    }
   
    /**
     * Return whether the UsernameToken represented by this class is to be used
     * for key derivation as per the UsernameToken Profile 1.1. It does this by
     * checking that the username token has salt and iteration values.
     *
     * @throws WSSecurityException
     */
    public boolean isDerivedKey() throws WSSecurityException {
        if (elementSalt != null && elementIteration != null) {
            return true;
        }
        return false;
    }
   
    /**
     * Create a WSUsernameTokenPrincipal from this UsernameToken object
     */
    public Principal createPrincipal() throws WSSecurityException {
        try {
            WSUsernameTokenPrincipalImpl principal =
                new WSUsernameTokenPrincipalImpl(getName(), isHashed());
            principal.setNonce(Base64.decode(getNonce()));
            principal.setPassword(getPassword());
            principal.setCreatedTime(getCreated());
            return principal;
        } catch (Base64DecodingException e) {
            throw new WSSecurityException(
                    WSSecurityException.ErrorCode.FAILURE, "decoding.general", e
            );
        }
    }
   
    /**
     * Return true if the "Created" value is before the current time minus the timeToLive
     * argument, and if the Created value is not "in the future".
     *
     * @param timeToLive the value in seconds for the validity of the Created time
     * @param futureTimeToLive the value in seconds for the future validity of the Created time
     * @return true if the UsernameToken is before (now-timeToLive), false otherwise
     */
    public boolean verifyCreated(
        int timeToLive,
        int futureTimeToLive
    ) {
        return DateUtil.verifyCreated(createdDate, timeToLive, futureTimeToLive);
    }
   
    @Override
    public int hashCode() {
        int result = 17;
        String username = getName();
        if (username != null) {
            result = 31 * result + username.hashCode();
        }
        String password = getPassword();
        if (password != null) {
            result = 31 * result + password.hashCode();
        }
        String passwordType = getPasswordType();
        if (passwordType != null) {
            result = 31 * result + passwordType.hashCode();
        }
        String nonce = getNonce();
        if (nonce != null) {
            result = 31 * result + nonce.hashCode();
        }
        String created = getCreated();
        if (created != null) {
            result = 31 * result + created.hashCode();
        }
        try {
            byte[] salt = getSalt();
            if (salt != null) {
                result = 31 * result + Arrays.hashCode(salt);
            }
        } catch (WSSecurityException ex) {
            if (LOG.isDebugEnabled()) {
                LOG.debug(ex.getMessage(), ex);
            }
        }
        result = 31 * result + Integer.valueOf(getIteration()).hashCode();
       
        return result;
    }
   
    @Override
    public boolean equals(Object object) {
        if (!(object instanceof UsernameToken)) {
            return false;
        }
        UsernameToken usernameToken = (UsernameToken)object;
        if (!compare(usernameToken.getName(), getName())) {
            return false;
        }
        if (!compare(usernameToken.getPassword(), getPassword())) {
            return false;
        }
        if (!compare(usernameToken.getPasswordType(), getPasswordType())) {
            return false;
        }
        if (!compare(usernameToken.getNonce(), getNonce())) {
            return false;
        }
        if (!compare(usernameToken.getCreated(), getCreated())) {
            return false;
        }
        try {
            byte[] salt = usernameToken.getSalt();
            if (!Arrays.equals(salt, getSalt())) {
                return false;
            }
        } catch (WSSecurityException ex) {
            if (LOG.isDebugEnabled()) {
                LOG.debug(ex.getMessage(), ex);
            }
        }
        int iteration = usernameToken.getIteration();
        if (iteration != getIteration()) {
            return false;
        }
        return true;
    }
   
    private boolean compare(String item1, String item2) {
        if (item1 == null && item2 != null) {
            return false;
        } else if (item1 != null && !item1.equals(item2)) {
            return false;
        }
        return true;
    }

    /**
     * A method to check that the UsernameToken is compliant with the BSP spec.
     * @throws WSSecurityException
     */
    private void checkBSPCompliance(BSPEnforcer bspEnforcer) throws WSSecurityException {
        List<Element> passwordElements =
            WSSecurityUtil.getDirectChildElements(
                element, WSConstants.PASSWORD_LN, WSConstants.WSSE_NS
            );
        // We can only have one password element
        if (passwordElements.size() > 1) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("The Username Token had more than one password element");
            }
            bspEnforcer.handleBSPRule(BSPRule.R4222);
        }
       
        // We must have a password type
        if (passwordElements.size() == 1) {
            Element passwordChild = passwordElements.get(0);
            String type = passwordChild.getAttributeNS(null, WSConstants.PASSWORD_TYPE_ATTR);
            if (type == null || "".equals(type)) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("The Username Token password does not have a Type attribute");
                }
                bspEnforcer.handleBSPRule(BSPRule.R4201);
            }
        }
       
        List<Element> createdElements =
            WSSecurityUtil.getDirectChildElements(
                element, WSConstants.CREATED_LN, WSConstants.WSU_NS
            );
        // We can only have one created element
        if (createdElements.size() > 1) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("The Username Token has more than one created element");
            }
            bspEnforcer.handleBSPRule(BSPRule.R4223);
        }
       
        List<Element> nonceElements =
            WSSecurityUtil.getDirectChildElements(
                element, WSConstants.NONCE_LN, WSConstants.WSSE_NS
            );
        // We can only have one nonce element
        if (nonceElements.size() > 1) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("The Username Token has more than one nonce element");
            }
            bspEnforcer.handleBSPRule(BSPRule.R4225);
        }
       
        if (nonceElements.size() == 1) {
            Element nonce = nonceElements.get(0);
            String encodingType = nonce.getAttributeNS(null, "EncodingType");
            // Encoding Type must be equal to Base64Binary
            if (encodingType == null || "".equals(encodingType)) {
                bspEnforcer.handleBSPRule(BSPRule.R4220);
            } else if (!BinarySecurity.BASE64_ENCODING.equals(encodingType)) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("The Username Token's nonce element has a bad encoding type");
                }
                bspEnforcer.handleBSPRule(BSPRule.R4221);
            }
        }
    }
}
TOP

Related Classes of org.apache.wss4j.dom.message.token.UsernameToken

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.