You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fx-dev@ws.apache.org by we...@apache.org on 2005/05/01 20:17:05 UTC
cvs commit: ws-fx/wss4j/src/org/apache/ws/security/message/token UsernameToken.java
werner 2005/05/01 11:17:05
Modified: wss4j/src/org/apache/ws/security/message/token
UsernameToken.java
Log:
Fix some problems that lead to NPE. Thanks to members
of the mailing list for the problem reports.
Revision Changes Path
1.14 +518 -537 ws-fx/wss4j/src/org/apache/ws/security/message/token/UsernameToken.java
Index: UsernameToken.java
===================================================================
RCS file: /home/cvs/ws-fx/wss4j/src/org/apache/ws/security/message/token/UsernameToken.java,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- UsernameToken.java 31 Oct 2004 08:11:17 -0000 1.13
+++ UsernameToken.java 1 May 2005 18:17:05 -0000 1.14
@@ -1,537 +1,518 @@
-/*
- * Copyright 2003-2004 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.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.WSSConfig;
-import org.apache.ws.security.WSSecurityException;
-import org.apache.ws.security.util.DOM2Writer;
-import org.apache.ws.security.util.WSSecurityUtil;
-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;
-
-import javax.crypto.Mac;
-import javax.crypto.spec.SecretKeySpec;
-import javax.xml.namespace.QName;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.TimeZone;
-
-/**
- * UsernameToken according to WS Security specifications,
- * UsernameToken profile.
- *
- * @author Davanum Srinivas (dims@yahoo.com)
- * @author Werner Dittmann (Werner.Dittmann@siemens.com)
- */
-public class UsernameToken {
- private static Log log = LogFactory.getLog(UsernameToken.class.getName());
-
- public QName token;
- public static final String PASSWORD_TYPE = "passwordType";
-
- protected Element element = null;
- protected Element elementUsername = null;
- protected Element elementPassword = null;
- protected Element elementNonce = null;
- protected Element elementCreated = null;
- protected boolean hashed = true;
- private static SecureRandom random = null;
- protected WSSConfig wssConfig = WSSConfig.getDefaultWSConfig();
-
- public static String TOKEN = "UsernameToken";
-
- static {
- try {
- random = SecureRandom.getInstance("SHA1PRNG");
- } catch (NoSuchAlgorithmException nsae) {
- nsae.printStackTrace();
- }
- }
-
- /**
- * Constructs a <code>UsernameToken</code> object and parses the
- * <code>wsse:UsernameToken</code> element to initialize it.
- *
- * @param wssConfig Configuration options for processing and building the <code>wsse:Security</code> header
- * @param elem the <code>wsse:UsernameToken</code> element that
- * contains the UsernameToken data
- * @throws WSSecurityException
- */
- public UsernameToken(WSSConfig wssConfig, Element elem) throws WSSecurityException {
- this.element = elem;
- this.wssConfig = wssConfig;
- token = new QName(wssConfig.getWsseNS(), TOKEN);
- QName el = new QName(this.element.getNamespaceURI(), this.element.getLocalName());
- if (!el.equals(token)) {
- throw new WSSecurityException(WSSecurityException.INVALID_SECURITY_TOKEN, "badTokenType00", new Object[]{el});
- }
- if (wssConfig.getProcessNonCompliantMessages()) {
- elementUsername = (Element) WSSecurityUtil.getDirectChildWSSE(element, "Username");
- elementPassword = (Element) WSSecurityUtil.getDirectChildWSSE(element, "Password");
- elementNonce = (Element) WSSecurityUtil.getDirectChildWSSE(element, "Nonce");
- elementCreated = (Element) WSSecurityUtil.getDirectChildWSU(element, "Created");
- } else {
- elementUsername = (Element) WSSecurityUtil.getDirectChild(element, "Username", wssConfig.getWsseNS());
- elementPassword = (Element) WSSecurityUtil.getDirectChild(element, "Password", wssConfig.getWsseNS());
- elementNonce = (Element) WSSecurityUtil.getDirectChild(element, "Nonce", wssConfig.getWsseNS());
- elementCreated = (Element) WSSecurityUtil.getDirectChild(element, "Created", wssConfig.getWsuNS());
- }
- if (elementUsername == null) {
- throw new WSSecurityException(WSSecurityException.INVALID_SECURITY_TOKEN, "badTokenType01", new Object[]{el});
- }
- String type = elementPassword.getAttribute("Type");
- if (type.equals(WSConstants.PASSWORD_DIGEST)) {
- hashed = true;
- if (elementNonce == null || elementCreated == null) {
- throw new WSSecurityException(WSSecurityException.INVALID_SECURITY_TOKEN, "badTokenType01", new Object[]{el});
- }
- } else {
- hashed = false;
- }
- }
-
- /**
- * Constructs a <code>UsernameToken</code> object according
- * to the defined parameters.
- * <p/>
- * This constructes set the password encoding to
- * {@link WSConstants#PASSWORD_DIGEST}
- *
- * @param wssConfig Configuration options for processing and building the <code>wsse:Security</code> header
- * @param doc the SOAP envelope as <code>Document</code>
- */
- public UsernameToken(WSSConfig wssConfig, Document doc) {
- this(wssConfig, doc, WSConstants.PASSWORD_DIGEST);
- }
-
- /**
- * Constructs a <code>UsernameToken</code> object according
- * to the defined parameters.
- * <p/>
- *
- * @param wssConfig Configuration options for processing and building the <code>wsse:Security</code> header
- * @param doc the SOAP envelope as <code>Document</code>
- * @param passwordType the required password encoding, either
- * {@link WSConstants#PASSWORD_DIGEST} or
- * {@link WSConstants#PASSWORD_TEXT}
- */
- public UsernameToken(WSSConfig wssConfig, Document doc, String passwordType) {
- this.wssConfig = wssConfig;
- this.element = doc.createElementNS(wssConfig.getWsseNS(), "wsse:" + WSConstants.USERNAME_TOKEN_LN);
- WSSecurityUtil.setNamespace(this.element, wssConfig.getWsseNS(), WSConstants.WSSE_PREFIX);
-
- this.elementUsername = doc.createElementNS(wssConfig.getWsseNS(), "wsse:" + WSConstants.USERNAME_LN);
- WSSecurityUtil.setNamespace(this.elementUsername, wssConfig.getWsseNS(), WSConstants.WSSE_PREFIX);
- this.elementUsername.appendChild(doc.createTextNode(""));
- element.appendChild(elementUsername);
-
- this.elementPassword = doc.createElementNS(wssConfig.getWsseNS(), "wsse:" + WSConstants.PASSWORD_LN);
- WSSecurityUtil.setNamespace(this.elementPassword, wssConfig.getWsseNS(), WSConstants.WSSE_PREFIX);
- this.elementPassword.appendChild(doc.createTextNode(""));
- element.appendChild(elementPassword);
-
- if (passwordType.equals(WSConstants.PASSWORD_TEXT)) {
- hashed = false;
- } else {
- hashed = true;
- addNonce(doc);
- addCreated(doc);
- }
- }
-
- /**
- * Creates and adds a Nonce element to this UsernameToken
- */
- public void addNonce(Document doc) {
- if (elementNonce != null) {
- return;
- }
- byte[] nonceValue = new byte[16];
- random.nextBytes(nonceValue);
- this.elementNonce = doc.createElementNS(wssConfig.getWsseNS(), "wsse:" + WSConstants.NONCE_LN);
- WSSecurityUtil.setNamespace(this.elementNonce, wssConfig.getWsseNS(), WSConstants.WSSE_PREFIX);
- this.elementNonce.appendChild(doc.createTextNode(Base64.encode(nonceValue)));
- element.appendChild(elementNonce);
- }
-
- /**
- * Creates and adds a Created element to this UsernameToken
- */
- public void addCreated(Document doc) {
- if (elementCreated != null) {
- return;
- }
- SimpleDateFormat zulu = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
- zulu.setTimeZone(TimeZone.getTimeZone("UTC"));
- Calendar rightNow = Calendar.getInstance();
- this.elementCreated = doc.createElementNS(wssConfig.getWsuNS(), "wsu:" + WSConstants.CREATED_LN);
- WSSecurityUtil.setNamespace(this.elementCreated, wssConfig.getWsuNS(), WSConstants.WSU_PREFIX);
- this.elementCreated.appendChild(doc.createTextNode(zulu.format(rightNow.getTime())));
- element.appendChild(elementCreated);
- }
-
- /**
- * Get the user name.
- *
- * @return the data from the user name element.
- */
- public String getName() {
- if (this.elementUsername != null) {
- return getFirstNode(this.elementUsername).getData();
- }
- return null;
- }
-
- /**
- * 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(this.elementUsername);
- node.setData(name);
- }
-
- /**
- * Get the nonce.
- *
- * @return the data from the nonce element.
- */
- public String getNonce() {
- if (this.elementNonce != null) {
- return getFirstNode(this.elementNonce).getData();
- }
- return null;
- }
-
- /**
- * Set the nonce.
- * <p/>
- *
- * @param nonce sets a text node containing the nonce data into
- * the nonce element.
- */
- public void setNonce(String nonce) {
- Text node = getFirstNode(this.elementNonce);
- node.setData(nonce);
- }
-
- /**
- * Get the created timestamp.
- *
- * @return the data from the created time element.
- */
- public String getCreated() {
- if (this.elementCreated != null) {
- return getFirstNode(this.elementCreated).getData();
- }
- return null;
- }
-
- /**
- * Set the created timestamp.
- *
- * @param created sets a text node containing the created time data into
- * the created time element.
- */
- public void setCreated(String created) {
- Text node = getFirstNode(this.elementCreated);
- node.setData(created);
- }
-
- /**
- * 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() {
- Text node = getFirstNode(this.elementPassword);
- if (node == null) {
- return null;
- }
- return node.getData();
- }
-
- /**
- * Get the hashed inidicator.
- * 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;
- }
-
- /**
- * 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) {
- throw new IllegalArgumentException("pwd == null");
- }
- Text node = getFirstNode(this.elementPassword);
- try {
- if (!hashed) {
- node.setData(pwd);
- this.elementPassword.setAttribute("Type", WSConstants.PASSWORD_TEXT);
- } else {
- byte[] b1 = Base64.decode(getNonce());
- byte[] b2 = getCreated().getBytes("UTF-8");
- byte[] b3 = pwd.getBytes("UTF-8");
- byte[] b4 = new byte[b1.length + b2.length + b3.length];
- int i = 0;
- int count = 0;
- for (i = 0; i < b1.length; i++) {
- b4[count++] = b1[i];
- }
- for (i = 0; i < b2.length; i++) {
- b4[count++] = b2[i];
- }
- for (i = 0; i < b3.length; i++) {
- b4[count++] = b3[i];
- }
- MessageDigest sha = MessageDigest.getInstance("SHA-1");
- sha.reset();
- sha.update(b4);
- node.setData(Base64.encode(sha.digest()));
- this.elementPassword.setAttribute("Type", WSConstants.PASSWORD_DIGEST);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public static String doPasswordDigest(String nonce, String created, String password) {
- String passwdDigest = null;
- try {
- byte[] b1 = Base64.decode(nonce);
- byte[] b2 = created.getBytes("UTF-8");
- byte[] b3 = password.getBytes("UTF-8");
- byte[] b4 = new byte[b1.length + b2.length + b3.length];
- int i = 0;
- int count = 0;
- for (i = 0; i < b1.length; i++) {
- b4[count++] = b1[i];
- }
- for (i = 0; i < b2.length; i++) {
- b4[count++] = b2[i];
- }
- for (i = 0; i < b3.length; i++) {
- b4[count++] = b3[i];
- }
- MessageDigest sha = MessageDigest.getInstance("SHA-1");
- sha.reset();
- sha.update(b4);
- passwdDigest = Base64.encode(sha.digest());
- } catch (Exception e) {
- e.printStackTrace();
- }
- 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 instanceof Text) ? (Text) node : null;
- }
-
- /**
- * Returns the dom element of this <code>UsernameToken</code> object.
- *
- * @return the <code>wsse:UsernameToken</code> element
- */
- public Element getElement() {
- return this.element;
- }
-
- /**
- * Returns the string representation of the token.
- *
- * @return a XML string representation
- */
- public String toString() {
- return DOM2Writer.nodeToString((Node) this.element);
- }
-
- /**
- * Gets the id.
- *
- * @return the value of the <code>wsu:Id</code> attribute of this
- * username token
- */
- public String getID() {
- if (wssConfig.getProcessNonCompliantMessages()) {
- return WSSecurityUtil.getAttributeValueWSU(element, "Id", null);
- } else {
- return WSSecurityUtil.getAttributeValueWSU(element, "Id", wssConfig.getWsuNS());
- }
- }
-
- /**
- * 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) {
- String prefix = WSSecurityUtil.setNamespace(this.element, wssConfig
- .getWsuNS(), WSConstants.WSU_PREFIX);
- this.element.setAttributeNS(wssConfig.getWsuNS(), prefix + ":Id", id);
- }
-
- /**
- * Gets the secret key as per WS-Trust spec.
- * This mthod uses default setting to generate the secret key. These
- * default values are suitable for .NET WSE.
- *
- * @return a secret key constructed from information conatined in
- * this username token
- */
- public byte[] getSecretKey() {
- return getSecretKey(WSConstants.WSE_DERIVED_KEY_LEN,
- WSConstants.LABEL_FOR_DERIVED_KEY);
- }
-
- /**
- * Gets the secret key as per WS-Trust spec.
- *
- * @param keylen How many bytes to generate for the key
- * @param labelString the label used to generate the seed
- * @return a secret key constructed from information conatined in
- * this username token
- */
- public byte[] getSecretKey(int keylen, String labelString) {
- byte[] key = null;
- try {
- Mac mac = Mac.getInstance("HMACSHA1");
- byte[] password = getPassword().getBytes("UTF-8");
- byte[] label = labelString.getBytes("UTF-8");
- byte[] nonce = Base64.decode(getNonce());
- byte[] created = getCreated().getBytes("UTF-8");
- byte[] seed = new byte[label.length + nonce.length + created.length];
- int i = 0;
- int count = 0;
- for (i = 0; i < label.length; i++) {
- seed[count++] = label[i];
- }
- for (i = 0; i < nonce.length; i++) {
- seed[count++] = nonce[i];
- }
- for (i = 0; i < created.length; i++) {
- seed[count++] = created[i];
- }
- key = P_hash(password, seed, mac, keylen);
-
- if (log.isDebugEnabled()) {
- log.debug("password :" + Base64.encode(password));
- log.debug("label :" + Base64.encode(label));
- log.debug("nonce :" + Base64.encode(nonce));
- log.debug("created :" + Base64.encode(created));
- log.debug("seed :" + Base64.encode(seed));
- log.debug("Key :" + Base64.encode(key));
- }
- } catch (Exception e) {
- return null;
- }
- return key;
- }
-
- /**
- * P_hash as defined in RFC 2246 for TLS.
- * <p/>
- *
- * @param secret is the key for the HMAC
- * @param seed the seed value to start the generation - A(0)
- * @param mac the HMAC algorithm
- * @param required number of bytes to generate
- * @return a byte array that conatins a secrect key
- * @throws Exception
- */
- private static byte[] P_hash(byte[] secret, byte[] seed, Mac mac,
- int required) throws Exception {
- byte[] out = new byte[required];
- int offset = 0, tocpy;
- byte[] A, tmp;
- /*
- * A(0) is the seed
- */
- A = seed;
- SecretKeySpec key = new SecretKeySpec(secret, "HMACSHA1");
- mac.init(key);
- while (required > 0) {
- mac.update(A);
- A = mac.doFinal();
- mac.update(A);
- mac.update(seed);
- tmp = mac.doFinal();
- tocpy = min(required, tmp.length);
- System.arraycopy(tmp, 0, out, offset, tocpy);
- offset += tocpy;
- required -= tocpy;
- }
- return out;
- }
-
-/*
- * public static void main(String[] args) throws Exception { byte[] secret =
- * Base64.decode("A4BKgeqUKi9VDwWyYPDrskwCwEQ5RIqH"); byte[] seed =
- * Base64.decode("bWFzdGVyIHNlY3JldAAAAAAAAAAAAAAAAAAAAAAy+BE8DDEUf+XnAynZEVU0PUQR4QHesAbNCmt8/Ry6NqBELuBAiZV4Z0FuCT58Fi8=");
- * int required = 48; Mac mac = Mac.getInstance("HMACSHA1"); byte[] out =
- * UsernameToken.P_hash(secret, seed, mac, 48);
- * System.out.println(Base64.encode(out));
- * //UCbz0pT2DxRfx4IpY6iWRE0KCa4Fg9JKNRlrxE8AtjNjb1NEK17NI6XdrMRMOKM2 }
- */
-
- /**
- * helper method.
- * <p/>
- *
- * @param a
- * @param b
- * @return
- */
- private static int min(int a, int b) {
- return (a > b) ? b : a;
- }
-}
+/*
+ * Copyright 2003-2004 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.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.WSSConfig;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.util.DOM2Writer;
+import org.apache.ws.security.util.WSSecurityUtil;
+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;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.namespace.QName;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * UsernameToken according to WS Security specifications,
+ * UsernameToken profile.
+ *
+ * @author Davanum Srinivas (dims@yahoo.com)
+ * @author Werner Dittmann (Werner.Dittmann@siemens.com)
+ */
+public class UsernameToken {
+ private static Log log = LogFactory.getLog(UsernameToken.class.getName());
+
+ public QName token;
+ public static final String PASSWORD_TYPE = "passwordType";
+
+ protected Element element = null;
+ protected Element elementUsername = null;
+ protected Element elementPassword = null;
+ protected Element elementNonce = null;
+ protected Element elementCreated = null;
+ protected boolean hashed = true;
+ private static SecureRandom random = null;
+ protected WSSConfig wssConfig = WSSConfig.getDefaultWSConfig();
+
+ public static String TOKEN = "UsernameToken";
+
+ static {
+ try {
+ random = SecureRandom.getInstance("SHA1PRNG");
+ } catch (NoSuchAlgorithmException nsae) {
+ nsae.printStackTrace();
+ }
+ }
+
+ /**
+ * Constructs a <code>UsernameToken</code> object and parses the
+ * <code>wsse:UsernameToken</code> element to initialize it.
+ *
+ * @param wssConfig Configuration options for processing and building the <code>wsse:Security</code> header
+ * @param elem the <code>wsse:UsernameToken</code> element that
+ * contains the UsernameToken data
+ * @throws WSSecurityException
+ */
+ public UsernameToken(WSSConfig wssConfig, Element elem) throws WSSecurityException {
+ this.element = elem;
+ this.wssConfig = wssConfig;
+ token = new QName(wssConfig.getWsseNS(), TOKEN);
+ QName el = new QName(this.element.getNamespaceURI(), this.element.getLocalName());
+ if (!el.equals(token)) {
+ throw new WSSecurityException(WSSecurityException.INVALID_SECURITY_TOKEN, "badTokenType00", new Object[]{el});
+ }
+ if (wssConfig.getProcessNonCompliantMessages()) {
+ elementUsername = (Element) WSSecurityUtil.getDirectChildWSSE(element, "Username");
+ elementPassword = (Element) WSSecurityUtil.getDirectChildWSSE(element, "Password");
+ elementNonce = (Element) WSSecurityUtil.getDirectChildWSSE(element, "Nonce");
+ elementCreated = (Element) WSSecurityUtil.getDirectChildWSU(element, "Created");
+ } else {
+ elementUsername = (Element) WSSecurityUtil.getDirectChild(element, "Username", wssConfig.getWsseNS());
+ elementPassword = (Element) WSSecurityUtil.getDirectChild(element, "Password", wssConfig.getWsseNS());
+ elementNonce = (Element) WSSecurityUtil.getDirectChild(element, "Nonce", wssConfig.getWsseNS());
+ elementCreated = (Element) WSSecurityUtil.getDirectChild(element, "Created", wssConfig.getWsuNS());
+ }
+ if (elementUsername == null) {
+ throw new WSSecurityException(WSSecurityException.INVALID_SECURITY_TOKEN, "badTokenType01", new Object[]{el});
+ }
+ hashed = false;
+ String type = elementPassword.getAttribute("Type");
+ if (type != null && type.equals(WSConstants.PASSWORD_DIGEST)) {
+ hashed = true;
+ if (elementNonce == null || elementCreated == null) {
+ throw new WSSecurityException(WSSecurityException.INVALID_SECURITY_TOKEN, "badTokenType01", new Object[]{el});
+ }
+ }
+ }
+
+ /**
+ * Constructs a <code>UsernameToken</code> object according
+ * to the defined parameters.
+ * <p/>
+ * This constructes set the password encoding to
+ * {@link WSConstants#PASSWORD_DIGEST}
+ *
+ * @param wssConfig Configuration options for processing and building the <code>wsse:Security</code> header
+ * @param doc the SOAP envelope as <code>Document</code>
+ */
+ public UsernameToken(WSSConfig wssConfig, Document doc) {
+ this(wssConfig, doc, WSConstants.PASSWORD_DIGEST);
+ }
+
+ /**
+ * Constructs a <code>UsernameToken</code> object according
+ * to the defined parameters.
+ * <p/>
+ *
+ * @param wssConfig Configuration options for processing and building the <code>wsse:Security</code> header
+ * @param doc the SOAP envelope as <code>Document</code>
+ * @param passwordType the required password encoding, either
+ * {@link WSConstants#PASSWORD_DIGEST} or
+ * {@link WSConstants#PASSWORD_TEXT}
+ */
+ public UsernameToken(WSSConfig wssConfig, Document doc, String passwordType) {
+ this.wssConfig = wssConfig;
+ this.element = doc.createElementNS(wssConfig.getWsseNS(), "wsse:" + WSConstants.USERNAME_TOKEN_LN);
+ WSSecurityUtil.setNamespace(this.element, wssConfig.getWsseNS(), WSConstants.WSSE_PREFIX);
+
+ this.elementUsername = doc.createElementNS(wssConfig.getWsseNS(), "wsse:" + WSConstants.USERNAME_LN);
+ WSSecurityUtil.setNamespace(this.elementUsername, wssConfig.getWsseNS(), WSConstants.WSSE_PREFIX);
+ this.elementUsername.appendChild(doc.createTextNode(""));
+ element.appendChild(elementUsername);
+
+ this.elementPassword = doc.createElementNS(wssConfig.getWsseNS(), "wsse:" + WSConstants.PASSWORD_LN);
+ WSSecurityUtil.setNamespace(this.elementPassword, wssConfig.getWsseNS(), WSConstants.WSSE_PREFIX);
+ this.elementPassword.appendChild(doc.createTextNode(""));
+ element.appendChild(elementPassword);
+
+ hashed = false;
+ if (passwordType != null && passwordType.equals(WSConstants.PASSWORD_DIGEST)) {
+ hashed = true;
+ addNonce(doc);
+ addCreated(doc);
+ }
+ }
+
+ /**
+ * Creates and adds a Nonce element to this UsernameToken
+ */
+ public void addNonce(Document doc) {
+ if (elementNonce != null) {
+ return;
+ }
+ byte[] nonceValue = new byte[16];
+ random.nextBytes(nonceValue);
+ this.elementNonce = doc.createElementNS(wssConfig.getWsseNS(), "wsse:" + WSConstants.NONCE_LN);
+ WSSecurityUtil.setNamespace(this.elementNonce, wssConfig.getWsseNS(), WSConstants.WSSE_PREFIX);
+ this.elementNonce.appendChild(doc.createTextNode(Base64.encode(nonceValue)));
+ element.appendChild(elementNonce);
+ }
+
+ /**
+ * Creates and adds a Created element to this UsernameToken
+ */
+ public void addCreated(Document doc) {
+ if (elementCreated != null) {
+ return;
+ }
+ SimpleDateFormat zulu = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
+ zulu.setTimeZone(TimeZone.getTimeZone("UTC"));
+ Calendar rightNow = Calendar.getInstance();
+ this.elementCreated = doc.createElementNS(wssConfig.getWsuNS(), "wsu:" + WSConstants.CREATED_LN);
+ WSSecurityUtil.setNamespace(this.elementCreated, wssConfig.getWsuNS(), WSConstants.WSU_PREFIX);
+ this.elementCreated.appendChild(doc.createTextNode(zulu.format(rightNow.getTime())));
+ element.appendChild(elementCreated);
+ }
+
+ /**
+ * Get the user name.
+ *
+ * @return the data from the user name element.
+ */
+ public String getName() {
+ return nodeString (this.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(this.elementUsername);
+ node.setData(name);
+ }
+
+ /**
+ * Get the nonce.
+ *
+ * @return the data from the nonce element.
+ */
+ public String getNonce() {
+ return nodeString(this.elementNonce);
+ }
+
+ /**
+ * Get the created timestamp.
+ *
+ * @return the data from the created time element.
+ */
+ public String getCreated() {
+ return nodeString(this.elementCreated);
+ }
+
+ /**
+ * 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() {
+ return nodeString(this.elementPassword);
+ }
+
+ /**
+ * Get the hashed inidicator.
+ * 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;
+ }
+
+ /**
+ * 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) {
+ throw new IllegalArgumentException("pwd == null");
+ }
+ Text node = getFirstNode(this.elementPassword);
+ try {
+ if (!hashed) {
+ node.setData(pwd);
+ this.elementPassword.setAttribute("Type", WSConstants.PASSWORD_TEXT);
+ } else {
+ byte[] b1 = Base64.decode(getNonce());
+ byte[] b2 = getCreated().getBytes("UTF-8");
+ byte[] b3 = pwd.getBytes("UTF-8");
+ byte[] b4 = new byte[b1.length + b2.length + b3.length];
+ int i = 0;
+ int count = 0;
+ for (i = 0; i < b1.length; i++) {
+ b4[count++] = b1[i];
+ }
+ for (i = 0; i < b2.length; i++) {
+ b4[count++] = b2[i];
+ }
+ for (i = 0; i < b3.length; i++) {
+ b4[count++] = b3[i];
+ }
+ MessageDigest sha = MessageDigest.getInstance("SHA-1");
+ sha.reset();
+ sha.update(b4);
+ node.setData(Base64.encode(sha.digest()));
+ this.elementPassword.setAttribute("Type", WSConstants.PASSWORD_DIGEST);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static String doPasswordDigest(String nonce, String created, String password) {
+ String passwdDigest = null;
+ try {
+ byte[] b1 = Base64.decode(nonce);
+ byte[] b2 = created.getBytes("UTF-8");
+ byte[] b3 = password.getBytes("UTF-8");
+ byte[] b4 = new byte[b1.length + b2.length + b3.length];
+ int i = 0;
+ int count = 0;
+ for (i = 0; i < b1.length; i++) {
+ b4[count++] = b1[i];
+ }
+ for (i = 0; i < b2.length; i++) {
+ b4[count++] = b2[i];
+ }
+ for (i = 0; i < b3.length; i++) {
+ b4[count++] = b3[i];
+ }
+ MessageDigest sha = MessageDigest.getInstance("SHA-1");
+ sha.reset();
+ sha.update(b4);
+ passwdDigest = Base64.encode(sha.digest());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ 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 instanceof Text) ? (Text) node : null;
+ }
+
+ /**
+ * Returns the data of an elemen 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) {
+ Text node = getFirstNode(e);
+ if (node != null) {
+ return node.getData();
+ }
+ }
+ return null;
+
+ }
+ /**
+ * Returns the dom element of this <code>UsernameToken</code> object.
+ *
+ * @return the <code>wsse:UsernameToken</code> element
+ */
+ public Element getElement() {
+ return this.element;
+ }
+
+ /**
+ * Returns the string representation of the token.
+ *
+ * @return a XML string representation
+ */
+ public String toString() {
+ return DOM2Writer.nodeToString((Node) this.element);
+ }
+
+ /**
+ * Gets the id.
+ *
+ * @return the value of the <code>wsu:Id</code> attribute of this
+ * username token
+ */
+ public String getID() {
+ if (wssConfig.getProcessNonCompliantMessages()) {
+ return WSSecurityUtil.getAttributeValueWSU(element, "Id", null);
+ } else {
+ return WSSecurityUtil.getAttributeValueWSU(element, "Id", wssConfig.getWsuNS());
+ }
+ }
+
+ /**
+ * 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) {
+ String prefix = WSSecurityUtil.setNamespace(this.element, wssConfig
+ .getWsuNS(), WSConstants.WSU_PREFIX);
+ this.element.setAttributeNS(wssConfig.getWsuNS(), prefix + ":Id", id);
+ }
+
+ /**
+ * Gets the secret key as per WS-Trust spec.
+ * This mthod uses default setting to generate the secret key. These
+ * default values are suitable for .NET WSE.
+ *
+ * @return a secret key constructed from information conatined in
+ * this username token
+ */
+ public byte[] getSecretKey() {
+ return getSecretKey(WSConstants.WSE_DERIVED_KEY_LEN,
+ WSConstants.LABEL_FOR_DERIVED_KEY);
+ }
+
+ /**
+ * Gets the secret key as per WS-Trust spec.
+ *
+ * @param keylen How many bytes to generate for the key
+ * @param labelString the label used to generate the seed
+ * @return a secret key constructed from information conatined in
+ * this username token
+ */
+ public byte[] getSecretKey(int keylen, String labelString) {
+ byte[] key = null;
+ try {
+ Mac mac = Mac.getInstance("HMACSHA1");
+ byte[] password = getPassword().getBytes("UTF-8");
+ byte[] label = labelString.getBytes("UTF-8");
+ byte[] nonce = Base64.decode(getNonce());
+ byte[] created = getCreated().getBytes("UTF-8");
+ byte[] seed = new byte[label.length + nonce.length + created.length];
+ int i = 0;
+ int count = 0;
+ for (i = 0; i < label.length; i++) {
+ seed[count++] = label[i];
+ }
+ for (i = 0; i < nonce.length; i++) {
+ seed[count++] = nonce[i];
+ }
+ for (i = 0; i < created.length; i++) {
+ seed[count++] = created[i];
+ }
+ key = P_hash(password, seed, mac, keylen);
+
+ if (log.isDebugEnabled()) {
+ log.debug("password :" + Base64.encode(password));
+ log.debug("label :" + Base64.encode(label));
+ log.debug("nonce :" + Base64.encode(nonce));
+ log.debug("created :" + Base64.encode(created));
+ log.debug("seed :" + Base64.encode(seed));
+ log.debug("Key :" + Base64.encode(key));
+ }
+ } catch (Exception e) {
+ return null;
+ }
+ return key;
+ }
+
+ /**
+ * P_hash as defined in RFC 2246 for TLS.
+ * <p/>
+ *
+ * @param secret is the key for the HMAC
+ * @param seed the seed value to start the generation - A(0)
+ * @param mac the HMAC algorithm
+ * @param required number of bytes to generate
+ * @return a byte array that conatins a secrect key
+ * @throws Exception
+ */
+ private static byte[] P_hash(byte[] secret, byte[] seed, Mac mac,
+ int required) throws Exception {
+ byte[] out = new byte[required];
+ int offset = 0, tocpy;
+ byte[] A, tmp;
+ /*
+ * A(0) is the seed
+ */
+ A = seed;
+ SecretKeySpec key = new SecretKeySpec(secret, "HMACSHA1");
+ mac.init(key);
+ while (required > 0) {
+ mac.update(A);
+ A = mac.doFinal();
+ mac.update(A);
+ mac.update(seed);
+ tmp = mac.doFinal();
+ tocpy = min(required, tmp.length);
+ System.arraycopy(tmp, 0, out, offset, tocpy);
+ offset += tocpy;
+ required -= tocpy;
+ }
+ return out;
+ }
+
+/*
+ * public static void main(String[] args) throws Exception { byte[] secret =
+ * Base64.decode("A4BKgeqUKi9VDwWyYPDrskwCwEQ5RIqH"); byte[] seed =
+ * Base64.decode("bWFzdGVyIHNlY3JldAAAAAAAAAAAAAAAAAAAAAAy+BE8DDEUf+XnAynZEVU0PUQR4QHesAbNCmt8/Ry6NqBELuBAiZV4Z0FuCT58Fi8=");
+ * int required = 48; Mac mac = Mac.getInstance("HMACSHA1"); byte[] out =
+ * UsernameToken.P_hash(secret, seed, mac, 48);
+ * System.out.println(Base64.encode(out));
+ * //UCbz0pT2DxRfx4IpY6iWRE0KCa4Fg9JKNRlrxE8AtjNjb1NEK17NI6XdrMRMOKM2 }
+ */
+
+ /**
+ * helper method.
+ * <p/>
+ *
+ * @param a
+ * @param b
+ * @return
+ */
+ private static int min(int a, int b) {
+ return (a > b) ? b : a;
+ }
+}