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.wss4j.dom.str;
21  
22  import java.util.Arrays;
23  import java.util.List;
24  
25  import javax.xml.namespace.QName;
26  
27  import org.apache.wss4j.common.ext.WSPasswordCallback;
28  import org.apache.wss4j.common.ext.WSSecurityException;
29  import org.apache.wss4j.common.saml.SAMLKeyInfo;
30  import org.apache.wss4j.common.saml.SAMLUtil;
31  import org.apache.wss4j.common.saml.SamlAssertionWrapper;
32  import org.apache.wss4j.common.token.BinarySecurity;
33  import org.apache.wss4j.common.token.Reference;
34  import org.apache.wss4j.common.token.SecurityTokenReference;
35  import org.apache.wss4j.common.util.KeyUtils;
36  import org.apache.wss4j.common.util.UsernameTokenUtil;
37  import org.apache.wss4j.common.util.XMLUtils;
38  import org.apache.wss4j.dom.WSConstants;
39  import org.apache.wss4j.dom.WSDocInfo;
40  import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
41  import org.apache.wss4j.dom.handler.RequestData;
42  import org.apache.wss4j.dom.message.token.DerivedKeyToken;
43  import org.apache.wss4j.dom.message.token.UsernameToken;
44  import org.apache.wss4j.dom.processor.Processor;
45  import org.apache.wss4j.dom.saml.WSSSAMLKeyInfoProcessor;
46  import org.w3c.dom.Element;
47  
48  /**
49   * This implementation of STRParser is for parsing a SecurityTokenReference element, found in the
50   * KeyInfo element associated with an EncryptedData element.
51   */
52  public class SecurityTokenRefSTRParser implements STRParser {
53  
54      /**
55       * Parse a SecurityTokenReference element and extract credentials.
56       *
57       * @param parameters The parameters to parse
58       * @return the STRParserResult Object containing the parsing results
59       * @throws WSSecurityException
60       */
61      public STRParserResult parseSecurityTokenReference(STRParserParameters parameters) throws WSSecurityException {
62  
63          if (parameters == null || parameters.getData() == null || parameters.getData().getWsDocInfo() == null
64              || parameters.getStrElement() == null) {
65              throw new WSSecurityException(
66                  WSSecurityException.ErrorCode.FAILURE, "invalidSTRParserParameter"
67              );
68          }
69  
70          SecurityTokenReference secRef =
71              new SecurityTokenReference(parameters.getStrElement(), parameters.getData().getBSPEnforcer());
72  
73          String uri = null;
74          if (secRef.getReference() != null) {
75              uri = secRef.getReference().getURI();
76              uri = XMLUtils.getIDFromReference(uri);
77          } else if (secRef.containsKeyIdentifier()) {
78              uri = secRef.getKeyIdentifierValue();
79          }
80  
81          WSSecurityEngineResult result = parameters.getData().getWsDocInfo().getResult(uri);
82          if (result != null) {
83              return processPreviousResult(result, secRef, uri, parameters);
84          }
85  
86          return processSTR(secRef, uri, parameters);
87      }
88  
89      /**
90       * Get a SecretKey from a SAML Assertion
91       */
92      private byte[] getSecretKeyFromAssertion(
93          SamlAssertionWrapper samlAssertion,
94          SecurityTokenReference secRef,
95          RequestData data
96      ) throws WSSecurityException {
97          STRParserUtil.checkSamlTokenBSPCompliance(secRef, samlAssertion, data.getBSPEnforcer());
98          SAMLKeyInfo samlKi =
99              SAMLUtil.getCredentialFromSubject(samlAssertion, new WSSSAMLKeyInfoProcessor(data), data.getSigVerCrypto());
100         if (samlKi == null) {
101             throw new WSSecurityException(
102                 WSSecurityException.ErrorCode.FAILED_CHECK, "invalidSAMLToken",
103                 new Object[] {"No Secret Key"});
104         }
105         return samlKi.getSecret();
106     }
107 
108     /**
109      * Process a previous security result
110      */
111     private STRParserResult processPreviousResult(
112         WSSecurityEngineResult result,
113         SecurityTokenReference secRef,
114         String uri,
115         STRParserParameters parameters
116     ) throws WSSecurityException {
117         STRParserResult parserResult = new STRParserResult();
118         RequestData data = parameters.getData();
119 
120         Integer action = (Integer) result.get(WSSecurityEngineResult.TAG_ACTION);
121         if (action != null && WSConstants.ENCR == action.intValue()) {
122             STRParserUtil.checkEncryptedKeyBSPCompliance(secRef, data.getBSPEnforcer());
123             byte[] secretKey = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET);
124             parserResult.setSecretKey(secretKey);
125         } else if (action != null && WSConstants.DKT == action.intValue()) {
126             DerivedKeyToken dkt =
127                 (DerivedKeyToken)result.get(WSSecurityEngineResult.TAG_DERIVED_KEY_TOKEN);
128             int keyLength = dkt.getLength();
129             if (keyLength <= 0 && parameters.getDerivationKeyLength() > 0) {
130                 keyLength = parameters.getDerivationKeyLength();
131             }
132             byte[] secret = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET);
133             parserResult.setSecretKey(dkt.deriveKey(keyLength, secret));
134             parserResult.setPrincipal(dkt.createPrincipal());
135         } else if (action != null
136             && (WSConstants.ST_UNSIGNED == action.intValue() || WSConstants.ST_SIGNED == action.intValue())) {
137             SamlAssertionWrapper samlAssertion =
138                 (SamlAssertionWrapper)result.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
139             byte[] secretKey =
140                 getSecretKeyFromAssertion(samlAssertion, secRef, data);
141             parserResult.setSecretKey(secretKey);
142         } else if (action != null
143             && (WSConstants.SCT == action.intValue() || WSConstants.BST == action.intValue())) {
144             byte[] secretKey = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET);
145             parserResult.setSecretKey(secretKey);
146         } else if (action != null
147             && (WSConstants.UT_NOPASSWORD == action.intValue() || WSConstants.UT == action.intValue())) {
148             STRParserUtil.checkUsernameTokenBSPCompliance(secRef, data.getBSPEnforcer());
149             UsernameToken usernameToken =
150                 (UsernameToken)result.get(WSSecurityEngineResult.TAG_USERNAME_TOKEN);
151 
152             String rawPassword =
153                 UsernameTokenUtil.getRawPassword(data.getCallbackHandler(), usernameToken.getName(),
154                                                  usernameToken.getPassword(), usernameToken.getPasswordType());
155             byte[] secretKey = usernameToken.getDerivedKey(data.getBSPEnforcer(), rawPassword);
156             parserResult.setSecretKey(secretKey);
157         }
158 
159         if (parserResult.getSecretKey() == null) {
160             throw new WSSecurityException(
161                 WSSecurityException.ErrorCode.FAILED_CHECK, "unsupportedKeyId",
162                 new Object[] {uri});
163         }
164 
165         return parserResult;
166     }
167 
168     private STRParserResult processSTR(
169         SecurityTokenReference secRef,
170         String uri,
171         STRParserParameters parameters
172     ) throws WSSecurityException {
173         STRParserResult parserResult = new STRParserResult();
174         RequestData data = parameters.getData();
175         Element strElement = parameters.getStrElement();
176         WSDocInfo wsDocInfo = data.getWsDocInfo();
177 
178         if (secRef.containsReference()) {
179             Reference reference = secRef.getReference();
180             // Try asking the CallbackHandler for the secret key
181             byte[] secretKey =
182                 STRParserUtil.getSecretKeyFromToken(uri, reference.getValueType(),
183                                                     WSPasswordCallback.SECRET_KEY, data);
184             if (secretKey == null || secretKey.length == 0) {
185                 Element token =
186                     STRParserUtil.getTokenElement(strElement.getOwnerDocument(), wsDocInfo, data.getCallbackHandler(),
187                                                   uri, reference.getValueType());
188                 QName el = new QName(token.getNamespaceURI(), token.getLocalName());
189                 if (el.equals(WSConstants.BINARY_TOKEN)) {
190                     Processor proc = data.getWssConfig().getProcessor(WSConstants.BINARY_TOKEN);
191                     List<WSSecurityEngineResult> bstResult = proc.handleToken(token, data);
192                     BinarySecurity bstToken =
193                             (BinarySecurity)bstResult.get(0).get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
194                     STRParserUtil.checkBinarySecurityBSPCompliance(secRef, bstToken, data.getBSPEnforcer());
195                     secretKey = (byte[])bstResult.get(0).get(WSSecurityEngineResult.TAG_SECRET);
196                 }
197             }
198             if (secretKey == null) {
199                 throw new WSSecurityException(
200                     WSSecurityException.ErrorCode.FAILED_CHECK, "unsupportedKeyId",
201                     new Object[] {uri});
202             }
203             parserResult.setSecretKey(secretKey);
204         } else if (secRef.containsKeyIdentifier()) {
205             String valueType = secRef.getKeyIdentifierValueType();
206             if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(valueType)
207                 || WSConstants.WSS_SAML2_KI_VALUE_TYPE.equals(valueType)) {
208                 byte[] secretKey =
209                     STRParserUtil.getSecretKeyFromToken(secRef.getKeyIdentifierValue(), valueType,
210                                                         WSPasswordCallback.SECRET_KEY, data);
211                 if (secretKey == null || secretKey.length == 0) {
212                     SamlAssertionWrapper samlAssertion =
213                         STRParserUtil.getAssertionFromKeyIdentifier(
214                             secRef, strElement, data
215                         );
216                     secretKey = getSecretKeyFromAssertion(samlAssertion, secRef, data);
217                 }
218                 parserResult.setSecretKey(secretKey);
219             } else if (WSConstants.WSS_KRB_KI_VALUE_TYPE.equals(valueType)) {
220                 byte[] secretKey =
221                     STRParserUtil.getSecretKeyFromToken(secRef.getKeyIdentifierValue(), valueType,
222                                                         WSPasswordCallback.SECRET_KEY, data);
223                 if (secretKey == null || secretKey.length == 0) {
224                     byte[] keyBytes = secRef.getSKIBytes();
225                     List<WSSecurityEngineResult> resultsList =
226                         wsDocInfo.getResultsByTag(WSConstants.BST);
227                     for (WSSecurityEngineResult bstResult : resultsList) {
228                         BinarySecurity bstToken =
229                             (BinarySecurity)bstResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
230                         byte[] tokenDigest = KeyUtils.generateDigest(bstToken.getToken());
231                         if (Arrays.equals(tokenDigest, keyBytes)) {
232                             secretKey = (byte[])bstResult.get(WSSecurityEngineResult.TAG_SECRET);
233                             break;
234                         }
235                     }
236                 }
237                 if (secretKey == null) {
238                     throw new WSSecurityException(
239                         WSSecurityException.ErrorCode.FAILED_CHECK, "unsupportedKeyId",
240                         new Object[] {uri});
241                 }
242                 parserResult.setSecretKey(secretKey);
243             } else {
244                 if (SecurityTokenReference.ENC_KEY_SHA1_URI.equals(valueType)) {
245                     STRParserUtil.checkEncryptedKeyBSPCompliance(secRef, data.getBSPEnforcer());
246                 }
247                 byte[] secretKey =
248                     STRParserUtil.getSecretKeyFromToken(
249                         secRef.getKeyIdentifierValue(), secRef.getKeyIdentifierValueType(),
250                         WSPasswordCallback.SECRET_KEY, data
251                     );
252                 if (secretKey == null || secretKey.length == 0) {
253                     throw new WSSecurityException(
254                         WSSecurityException.ErrorCode.FAILED_CHECK, "unsupportedKeyId",
255                         new Object[] {uri});
256                 }
257                 parserResult.setSecretKey(secretKey);
258             }
259         } else {
260             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_CHECK, "noReference");
261         }
262 
263         return parserResult;
264     }
265 
266 }