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.str;
21  
22  import org.apache.ws.security.WSConstants;
23  import org.apache.ws.security.WSDocInfo;
24  import org.apache.ws.security.WSPasswordCallback;
25  import org.apache.ws.security.WSSConfig;
26  import org.apache.ws.security.WSSecurityEngine;
27  import org.apache.ws.security.WSSecurityEngineResult;
28  import org.apache.ws.security.WSSecurityException;
29  import org.apache.ws.security.handler.RequestData;
30  import org.apache.ws.security.message.token.BinarySecurity;
31  import org.apache.ws.security.message.token.DerivedKeyToken;
32  import org.apache.ws.security.message.token.Reference;
33  import org.apache.ws.security.message.token.SecurityTokenReference;
34  import org.apache.ws.security.message.token.UsernameToken;
35  import org.apache.ws.security.processor.Processor;
36  import org.apache.ws.security.saml.SAMLKeyInfo;
37  import org.apache.ws.security.saml.SAMLUtil;
38  import org.apache.ws.security.saml.ext.AssertionWrapper;
39  import org.apache.ws.security.util.WSSecurityUtil;
40  import org.w3c.dom.Element;
41  
42  import java.security.Principal;
43  import java.security.PublicKey;
44  import java.security.cert.X509Certificate;
45  import java.util.Arrays;
46  import java.util.List;
47  import java.util.Map;
48  
49  import javax.security.auth.callback.Callback;
50  import javax.xml.namespace.QName;
51  
52  /**
53   * This implementation of STRParser is for parsing a SecurityTokenReference element, found in the
54   * KeyInfo element associated with an EncryptedData element.
55   */
56  public class SecurityTokenRefSTRParser implements STRParser {
57      
58      /**
59       * The Signature method. This is used when deriving a key.
60       */
61      public static final String SIGNATURE_METHOD = "signature_method";
62      
63      private byte[] secretKey;
64      private Principal principal;
65      
66      /**
67       * Parse a SecurityTokenReference element and extract credentials.
68       * 
69       * @param strElement The SecurityTokenReference element
70       * @param data the RequestData associated with the request
71       * @param wsDocInfo The WSDocInfo object to access previous processing results
72       * @param parameters A set of implementation-specific parameters
73       * @throws WSSecurityException
74       */
75      public void parseSecurityTokenReference(
76          Element strElement,
77          RequestData data,
78          WSDocInfo wsDocInfo,
79          Map<String, Object> parameters
80      ) throws WSSecurityException {
81          boolean bspCompliant = true;
82          WSSConfig config = data.getWssConfig();
83          if (config != null) {
84              bspCompliant = config.isWsiBSPCompliant();
85          }
86          
87          SecurityTokenReference secRef = new SecurityTokenReference(strElement, bspCompliant);
88          
89          String uri = null;
90          if (secRef.containsReference()) {
91              uri = secRef.getReference().getURI();
92              if (uri.charAt(0) == '#') {
93                  uri = uri.substring(1);
94              }
95          } else if (secRef.containsKeyIdentifier()) {
96              uri = secRef.getKeyIdentifierValue();
97          }
98          
99          WSSecurityEngineResult result = wsDocInfo.getResult(uri);
100         if (result != null) {
101             processPreviousResult(result, secRef, data, parameters, wsDocInfo, bspCompliant);
102             
103             if (secretKey == null) {
104                 throw new WSSecurityException(
105                     WSSecurityException.FAILED_CHECK, "unsupportedKeyId", new Object[] {uri}
106                 );
107             }
108         } else if (secRef.containsReference()) {
109             Reference reference = secRef.getReference();
110             // Try asking the CallbackHandler for the secret key
111             secretKey = getSecretKeyFromToken(uri, reference.getValueType(), data);
112             if (secretKey == null) {
113                 Element token = 
114                     secRef.getTokenElement(strElement.getOwnerDocument(), wsDocInfo, data.getCallbackHandler());
115                 QName el = new QName(token.getNamespaceURI(), token.getLocalName());
116                 if (el.equals(WSSecurityEngine.BINARY_TOKEN)) {
117                     Processor proc = data.getWssConfig().getProcessor(WSSecurityEngine.BINARY_TOKEN);
118                     List<WSSecurityEngineResult> bstResult =
119                             proc.handleToken(token, data, wsDocInfo);
120                     BinarySecurity bstToken = 
121                             (BinarySecurity)bstResult.get(0).get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
122                     if (bspCompliant) {
123                         BSPEnforcer.checkBinarySecurityBSPCompliance(secRef, bstToken);
124                     }
125                     secretKey = (byte[])bstResult.get(0).get(WSSecurityEngineResult.TAG_SECRET);
126                 } 
127             }
128             if (secretKey == null) {
129                 throw new WSSecurityException(
130                     WSSecurityException.FAILED_CHECK, "unsupportedKeyId", new Object[] {uri}
131                 );
132             }
133         } else if (secRef.containsKeyIdentifier()) {
134             String valueType = secRef.getKeyIdentifierValueType();
135             if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(valueType)
136                 || WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(valueType)) {
137                 secretKey = 
138                     getSecretKeyFromToken(secRef.getKeyIdentifierValue(), valueType, data);
139                 if (secretKey == null) {
140                     AssertionWrapper assertion = 
141                         SAMLUtil.getAssertionFromKeyIdentifier(
142                             secRef, strElement, 
143                             data, wsDocInfo
144                         );
145                     secretKey = 
146                         getSecretKeyFromAssertion(assertion, secRef, data, wsDocInfo, bspCompliant);
147                 }
148             } else if (WSConstants.WSS_KRB_KI_VALUE_TYPE.equals(valueType)) {
149                 secretKey = 
150                     getSecretKeyFromToken(secRef.getKeyIdentifierValue(), valueType, data);
151                 if (secretKey == null) {
152                     byte[] keyBytes = secRef.getSKIBytes();
153                     List<WSSecurityEngineResult> resultsList = 
154                         wsDocInfo.getResultsByTag(WSConstants.BST);
155                     for (WSSecurityEngineResult bstResult : resultsList) {
156                         BinarySecurity bstToken = 
157                             (BinarySecurity)bstResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
158                         byte[] tokenDigest = WSSecurityUtil.generateDigest(bstToken.getToken());
159                         if (Arrays.equals(tokenDigest, keyBytes)) {
160                             secretKey = (byte[])bstResult.get(WSSecurityEngineResult.TAG_SECRET);
161                             break;
162                         }
163                     }
164                 }
165                 if (secretKey == null) {
166                     throw new WSSecurityException(
167                         WSSecurityException.FAILED_CHECK, "unsupportedKeyId", new Object[] {uri}
168                     );
169                 }
170             } else {
171                 if (bspCompliant && SecurityTokenReference.ENC_KEY_SHA1_URI.equals(valueType)) {
172                     BSPEnforcer.checkEncryptedKeyBSPCompliance(secRef);
173                 } 
174                 secretKey = 
175                     getSecretKeyFromToken(
176                         secRef.getKeyIdentifierValue(), secRef.getKeyIdentifierValueType(), data
177                     );
178                 if (secretKey == null) {
179                     throw new WSSecurityException(
180                         WSSecurityException.FAILED_CHECK, "unsupportedKeyId", new Object[] {uri}
181                     );
182                 }
183             }
184         } else {
185             throw new WSSecurityException(WSSecurityException.FAILED_CHECK, "noReference");
186         }
187     }
188     
189     /**
190      * Get the X509Certificates associated with this SecurityTokenReference
191      * @return the X509Certificates associated with this SecurityTokenReference
192      */
193     public X509Certificate[] getCertificates() {
194         return null;
195     }
196     
197     /**
198      * Get the Principal associated with this SecurityTokenReference
199      * @return the Principal associated with this SecurityTokenReference
200      */
201     public Principal getPrincipal() {
202         return principal;
203     }
204     
205     /**
206      * Get the PublicKey associated with this SecurityTokenReference
207      * @return the PublicKey associated with this SecurityTokenReference
208      */
209     public PublicKey getPublicKey() {
210         return null;
211     }
212     
213     /**
214      * Get the Secret Key associated with this SecurityTokenReference
215      * @return the Secret Key associated with this SecurityTokenReference
216      */
217     public byte[] getSecretKey() {
218         return secretKey;
219     }
220     
221     /**
222      * Get how the certificates were referenced
223      * @return how the certificates were referenced
224      */
225     public REFERENCE_TYPE getCertificatesReferenceType() {
226         return null;
227     }
228     
229     /**
230      * Get whether the returned credential is already trusted or not. This is currently
231      * applicable in the case of a credential extracted from a trusted HOK SAML Assertion,
232      * and a BinarySecurityToken that has been processed by a Validator. In these cases,
233      * the SignatureProcessor does not need to verify trust on the credential.
234      * @return true if trust has already been verified on the returned Credential
235      */
236     public boolean isTrustedCredential() {
237         return false;
238     }
239     
240     /**
241      * Get the Secret Key from a CallbackHandler
242      * @param id The id of the element
243      * @param type The type of the element (may be null)
244      * @param cb The CallbackHandler object
245      * @return A Secret Key
246      * @throws WSSecurityException
247      */
248     private byte[] getSecretKeyFromToken(
249         String id,
250         String type,
251         RequestData data
252     ) throws WSSecurityException {
253         if (id.charAt(0) == '#') {
254             id = id.substring(1);
255         }
256         WSPasswordCallback pwcb = 
257             new WSPasswordCallback(id, null, type, WSPasswordCallback.SECRET_KEY, data);
258         try {
259             Callback[] callbacks = new Callback[]{pwcb};
260             if (data.getCallbackHandler() != null) {
261                 data.getCallbackHandler().handle(callbacks);
262                 return pwcb.getKey();
263             }
264         } catch (Exception e) {
265             throw new WSSecurityException(
266                 WSSecurityException.FAILURE,
267                 "noPassword", 
268                 new Object[] {id}, 
269                 e
270             );
271         }
272 
273         return null;
274     }
275     
276     /**
277      * Get a SecretKey from a SAML Assertion
278      */
279     private byte[] getSecretKeyFromAssertion(
280         AssertionWrapper assertion, 
281         SecurityTokenReference secRef,
282         RequestData data,
283         WSDocInfo wsDocInfo,
284         boolean bspCompliant
285     ) throws WSSecurityException {
286         if (bspCompliant) {
287             BSPEnforcer.checkSamlTokenBSPCompliance(secRef, assertion);
288         }
289         SAMLKeyInfo samlKi = 
290             SAMLUtil.getCredentialFromSubject(assertion, data, wsDocInfo, bspCompliant);
291         if (samlKi == null) {
292             throw new WSSecurityException(
293                 WSSecurityException.FAILED_CHECK, "invalidSAMLToken", new Object[] {"No Secret Key"}
294             );
295         }
296         return samlKi.getSecret();
297     }
298     
299     /**
300      * Process a previous security result
301      */
302     private void processPreviousResult(
303         WSSecurityEngineResult result,
304         SecurityTokenReference secRef,
305         RequestData data,
306         Map<String, Object> parameters,
307         WSDocInfo wsDocInfo,
308         boolean bspCompliant
309     ) throws WSSecurityException {
310         int action = ((Integer)result.get(WSSecurityEngineResult.TAG_ACTION)).intValue();
311         if (WSConstants.ENCR == action) {
312             if (bspCompliant) {
313                 BSPEnforcer.checkEncryptedKeyBSPCompliance(secRef);
314             }
315             secretKey = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET);
316         } else if (WSConstants.DKT == action) {
317             DerivedKeyToken dkt = 
318                 (DerivedKeyToken)result.get(WSSecurityEngineResult.TAG_DERIVED_KEY_TOKEN);
319             byte[] secret = 
320                 (byte[])result.get(WSSecurityEngineResult.TAG_SECRET);
321             String algorithm = (String)parameters.get(SIGNATURE_METHOD);
322             secretKey = dkt.deriveKey(WSSecurityUtil.getKeyLength(algorithm), secret);
323             principal = dkt.createPrincipal();
324         } else if (WSConstants.ST_UNSIGNED == action || WSConstants.ST_SIGNED == action) {
325             AssertionWrapper assertion = 
326                 (AssertionWrapper)result.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
327             secretKey = 
328                 getSecretKeyFromAssertion(assertion, secRef, data, wsDocInfo, bspCompliant);
329         } else if (WSConstants.SCT == action || WSConstants.BST == action) {
330             secretKey = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET);
331         } else if (WSConstants.UT_NOPASSWORD == action || WSConstants.UT == action) {
332             if (bspCompliant) {
333                 BSPEnforcer.checkUsernameTokenBSPCompliance(secRef);
334             }
335             UsernameToken usernameToken = 
336                 (UsernameToken)result.get(WSSecurityEngineResult.TAG_USERNAME_TOKEN);
337 
338             usernameToken.setRawPassword(data);
339             secretKey = usernameToken.getDerivedKey();
340         } 
341     }
342     
343     
344 }