View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.ws.security.message;
21  
22  import org.apache.ws.security.WSConstants;
23  import org.apache.ws.security.WSSConfig;
24  import org.apache.ws.security.WSSecurityException;
25  import org.apache.ws.security.message.token.UsernameToken;
26  import org.apache.ws.security.util.Base64;
27  import org.apache.ws.security.util.WSSecurityUtil;
28  import org.w3c.dom.Document;
29  import org.w3c.dom.Element;
30  
31  /**
32   * Builds a WS UsernameToken.
33   * 
34   * Refer to the WS specification, UsernameToken profile
35   * 
36   * @author Werner Dittmann (werner@apache.org).
37   */
38  public class WSSecUsernameToken extends WSSecBase {
39      private static org.apache.commons.logging.Log log = 
40          org.apache.commons.logging.LogFactory.getLog(WSSecUsernameToken.class);
41  
42      private String passwordType = WSConstants.PASSWORD_DIGEST;
43      private UsernameToken ut = null;
44      private boolean nonce = false;
45      private boolean created = false;
46      private boolean useDerivedKey = false;
47      private boolean useMac = false;
48      private byte[] saltValue;
49      private int iteration = UsernameToken.DEFAULT_ITERATION;
50      private int secretKeyLength = WSConstants.WSE_DERIVED_KEY_LEN;
51      private boolean passwordsAreEncoded = false;
52  
53      public WSSecUsernameToken() {
54          super();
55      }
56      public WSSecUsernameToken(WSSConfig config) {
57          super(config);
58      }
59  
60      /**
61       * Defines how to construct the password element of the
62       * <code>UsernameToken</code>.
63       * 
64       * @param pwType
65       *            contains the password type. Only allowed values are
66       *            {@link WSConstants#PASSWORD_DIGEST} and
67       *            {@link WSConstants#PASSWORD_TEXT}.
68       *            or null when no password is needed.
69       */
70      public void setPasswordType(String pwType) {
71          this.passwordType = pwType;
72      }
73  
74      /**
75       * Add a Nonce element to the UsernameToken.
76       */
77      public void addNonce() {
78          nonce = true;
79      }
80  
81      /**
82       * Add a Created element to the UsernameToken.
83       */
84      public void addCreated() {
85          created = true;
86      }
87      
88      /**
89       * Set the secret key length
90       */
91      public void setSecretKeyLength(int length) {
92          secretKeyLength = length;
93      }
94      
95      /**
96       * Get the secret key length
97       */
98      public int getSecretKeyLength() {
99          return secretKeyLength;
100     }
101     
102     /**
103      * Add a derived key to the UsernameToken
104      * @param useMac whether the derived key is to be used for a MAC or not
105      * @param saltValue The salt value to use
106      * @param iteration The number of iterations to use in deriving a key
107      */
108     public void addDerivedKey(boolean useMac, byte[] saltValue, int iteration) {
109         passwordType = null;
110         useDerivedKey = true;
111         this.useMac = useMac;
112         this.saltValue = saltValue;
113         if (iteration > 0) {
114             this.iteration = iteration;
115         }
116     }
117 
118     
119     /**
120      * Get the derived secret key.
121      * 
122      * After the <code>prepare()</code> method was called use this method
123      * to compute a derived secret key. If "useDerivedKey" is set, then the returned secret
124      * key is derived as per the UsernameToken 1.1 specification. Otherwise, the generation 
125      * of this secret key is according to the WS-Trust specifications.
126      * 
127      * @return Return the derived secret key of this token or null if <code>prepare()</code>
128      * was not called before.
129      */
130     public byte[] getSecretKey() throws WSSecurityException {
131         if (ut == null) {
132             return null;
133         }
134         if (useDerivedKey) {
135             if (passwordsAreEncoded) {
136                 return UsernameToken.generateDerivedKey(Base64.decode(password), saltValue, iteration);
137             } else {
138                 return UsernameToken.generateDerivedKey(password, saltValue, iteration);
139             }
140         }
141         return ut.getSecretKey(secretKeyLength);
142     }
143     
144     /**
145      * Get the derived key.
146      * 
147      * After the <code>prepare()</code> method was called use this method
148      * to compute a derived key. The generation of this secret key is according
149      * to the UsernameTokenProfile 1.1 specification (section 4 - Key Derivation).
150      * 
151      * @return Return the derived key of this token or null if <code>prepare()</code>
152      * was not called before.
153      */
154     public byte[] getDerivedKey() throws WSSecurityException {
155         if (ut == null || !useDerivedKey) {
156             return null;
157         }
158         if (passwordsAreEncoded) {
159             return UsernameToken.generateDerivedKey(Base64.decode(password), saltValue, iteration);
160         } else {
161             return UsernameToken.generateDerivedKey(password, saltValue, iteration);
162         }
163     }
164 
165     /**
166      * @param passwordsAreEncoded
167      * whether passwords are encoded
168      */
169     public void setPasswordsAreEncoded(boolean passwordsAreEncoded) {
170         this.passwordsAreEncoded = passwordsAreEncoded;
171     }
172 
173     /**
174      * @return whether passwords are encoded
175      */
176     public boolean getPasswordsAreEncoded() {
177         return passwordsAreEncoded;
178     }
179 
180     /**
181      * Get the id generated during <code>prepare()</code>.
182      * 
183      * Returns the the value of wsu:Id attribute of this UsernameToken. 
184      * 
185      * @return Return the wsu:Id of this token or null if <code>prepare()</code>
186      * was not called before.
187      */
188     public String getId() {
189         if (ut == null) {
190             return null;
191         }
192         return ut.getID();
193     }
194 
195     /**
196      * Creates a Username token.
197      * 
198      * The method prepares and initializes a WSSec UsernameToken structure after
199      * the relevant information was set. A Before calling
200      * <code>prepare()</code> all parameters such as user, password,
201      * passwordType etc. must be set. A complete <code>UsernameToken</code> is
202      * constructed.
203      * 
204      * @param doc The SOAP envelope as W3C document
205      */
206     public void prepare(Document doc) {
207         ut = new UsernameToken(getWsConfig().isPrecisionInMilliSeconds(), doc, passwordType);
208         ut.setPasswordsAreEncoded(passwordsAreEncoded);
209         ut.setName(user);
210         if (useDerivedKey) {
211             saltValue = ut.addSalt(doc, saltValue, useMac);
212             ut.addIteration(doc, iteration);
213         } else {
214             ut.setPassword(password);
215         }
216         if (nonce) {
217             ut.addNonce(doc);
218         }
219         if (created) {
220             ut.addCreated(getWsConfig().isPrecisionInMilliSeconds(), doc);
221         }
222         ut.setID(getWsConfig().getIdAllocator().createId("UsernameToken-", ut));
223     }
224 
225     /**
226      * Prepends the UsernameToken element to the elements already in the
227      * Security header.
228      * 
229      * The method can be called any time after <code>prepare()</code>.
230      * This allows to insert the UsernameToken element at any position in the
231      * Security header.
232      * 
233      * @param secHeader The security header that holds the Signature element.
234      */
235     public void prependToHeader(WSSecHeader secHeader) {
236         WSSecurityUtil.prependChildElement(secHeader.getSecurityHeader(), ut.getElement());
237     }
238 
239     /**
240      * Appends the UsernameToken element to the elements already in the
241      * Security header.
242      * 
243      * The method can be called any time after <code>prepare()</code>.
244      * This allows to insert the UsernameToken element at any position in the
245      * Security header.
246      * 
247      * @param secHeader The security header that holds the Signature element.
248      */
249     public void appendToHeader(WSSecHeader secHeader) {
250         Element secHeaderElement = secHeader.getSecurityHeader();
251         secHeaderElement.appendChild(ut.getElement());
252     }
253     
254     /**
255      * Adds a new <code>UsernameToken</code> to a soap envelope.
256      * 
257      * Before calling <code>build()</code> all parameters such as user,
258      * password, passwordType etc. must be set. A complete
259      * <code>UsernameToken</code> is constructed and added to the
260      * <code>wsse:Security</code> header.
261      * 
262      * @param doc The SOAP envelope as W3C document
263      * @param secHeader The security header inside the SOAP envelope
264      * @return Document with UsernameToken added
265      */
266     public Document build(Document doc, WSSecHeader secHeader) {
267         log.debug("Begin add username token...");
268 
269         prepare(doc);
270         prependToHeader(secHeader);
271 
272         return doc;
273     }
274 
275     /**
276      * Returns the <code>UsernameToken</code> element.
277      * 
278      * The method can be called any time after <code>prepare()</code>.
279      * This allows to insert the UsernameToken element at any position in the
280      * Security header.
281      * 
282      * @return the Username Token element
283      */
284     public Element getUsernameTokenElement() {
285        return ut.getElement(); 
286     }
287 }