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.security.cert.X509Certificate;
23  import java.util.Arrays;
24  import java.util.List;
25  
26  import org.apache.wss4j.common.crypto.Crypto;
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.SecurityTokenReference;
34  import org.apache.wss4j.common.util.KeyUtils;
35  import org.apache.wss4j.common.util.XMLUtils;
36  import org.apache.wss4j.dom.WSConstants;
37  import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
38  import org.apache.wss4j.dom.handler.RequestData;
39  import org.apache.wss4j.dom.saml.WSSSAMLKeyInfoProcessor;
40  
41  /**
42   * This implementation of STRParser is for parsing a SecurityTokenReference element associated
43   * with a DerivedKeyToken element.
44   */
45  public class DerivedKeyTokenSTRParser implements STRParser {
46  
47      /**
48       * Parse a SecurityTokenReference element and extract credentials.
49       *
50       * @param parameters The parameters to parse
51       * @return the STRParserResult Object containing the parsing results
52       * @throws WSSecurityException
53       */
54      public STRParserResult parseSecurityTokenReference(STRParserParameters parameters) throws WSSecurityException {
55  
56          if (parameters == null || parameters.getData() == null || parameters.getData().getWsDocInfo() == null
57              || parameters.getStrElement() == null) {
58              throw new WSSecurityException(
59                  WSSecurityException.ErrorCode.FAILURE, "invalidSTRParserParameter"
60              );
61          }
62  
63          SecurityTokenReference secRef =
64              new SecurityTokenReference(parameters.getStrElement(), parameters.getData().getBSPEnforcer());
65  
66          String uri = null;
67          if (secRef.getReference() != null) {
68              uri = secRef.getReference().getURI();
69              uri = XMLUtils.getIDFromReference(uri);
70          } else if (secRef.containsKeyIdentifier()) {
71              uri = secRef.getKeyIdentifierValue();
72          }
73  
74          WSSecurityEngineResult result = parameters.getData().getWsDocInfo().getResult(uri);
75          if (result != null) {
76              return processPreviousResult(result, secRef, parameters);
77          }
78  
79          return processSTR(secRef, uri, parameters);
80      }
81  
82      /**
83       * Process a previous security result
84       */
85      private STRParserResult processPreviousResult(
86          WSSecurityEngineResult result,
87          SecurityTokenReference secRef,
88          STRParserParameters parameters
89      ) throws WSSecurityException {
90          STRParserResult parserResult = new STRParserResult();
91          RequestData data = parameters.getData();
92  
93          Integer action = (Integer)result.get(WSSecurityEngineResult.TAG_ACTION);
94          if (action != null
95              && (WSConstants.UT_NOPASSWORD == action.intValue() || WSConstants.UT == action.intValue())) {
96              STRParserUtil.checkUsernameTokenBSPCompliance(secRef, data.getBSPEnforcer());
97              byte[] secretKey = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET);
98              parserResult.setSecretKey(secretKey);
99          } else if (action != null && WSConstants.ENCR == action.intValue()) {
100             STRParserUtil.checkEncryptedKeyBSPCompliance(secRef, data.getBSPEnforcer());
101             byte[] secretKey = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET);
102             parserResult.setSecretKey(secretKey);
103         } else if (action != null && (WSConstants.SCT == action.intValue() || WSConstants.BST == action.intValue())) {
104             byte[] secretKey = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET);
105             parserResult.setSecretKey(secretKey);
106         } else if (action != null
107             && (WSConstants.ST_UNSIGNED == action.intValue() || WSConstants.ST_SIGNED == action.intValue())) {
108             SamlAssertionWrapper samlAssertion =
109                 (SamlAssertionWrapper)result.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
110             STRParserUtil.checkSamlTokenBSPCompliance(secRef, samlAssertion, data.getBSPEnforcer());
111 
112             SAMLKeyInfo keyInfo =
113                 SAMLUtil.getCredentialFromSubject(samlAssertion, new WSSSAMLKeyInfoProcessor(data), data.getSigVerCrypto());
114             // TODO Handle malformed SAML tokens where they don't have the
115             // secret in them
116             byte[] secretKey = keyInfo.getSecret();
117             parserResult.setSecretKey(secretKey);
118         } else {
119             throw new WSSecurityException(
120                 WSSecurityException.ErrorCode.FAILED_CHECK, "unsupportedKeyId"
121             );
122         }
123 
124         return parserResult;
125     }
126 
127     private STRParserResult processSTR(
128         SecurityTokenReference secRef,
129         String uri,
130         STRParserParameters parameters
131     ) throws WSSecurityException {
132         STRParserResult parserResult = new STRParserResult();
133         RequestData data = parameters.getData();
134 
135         if (secRef.containsReference()) {
136             // Now use the callback and get it
137             byte[] secretKey =
138                 STRParserUtil.getSecretKeyFromToken(uri, null, WSPasswordCallback.SECURITY_CONTEXT_TOKEN, data);
139             if (secretKey == null || secretKey.length == 0) {
140                 throw new WSSecurityException(
141                     WSSecurityException.ErrorCode.FAILED_CHECK, "unsupportedKeyId",
142                     new Object[] {uri});
143             }
144             parserResult.setSecretKey(secretKey);
145         } else if (secRef.containsKeyIdentifier()) {
146             String keyIdentifierValueType = secRef.getKeyIdentifierValueType();
147             if (WSConstants.WSS_KRB_KI_VALUE_TYPE.equals(keyIdentifierValueType)) {
148                 byte[] secretKey =
149                     STRParserUtil.getSecretKeyFromToken(
150                         secRef.getKeyIdentifierValue(), keyIdentifierValueType,
151                         WSPasswordCallback.SECRET_KEY, data
152                     );
153                 if (secretKey == null || secretKey.length == 0) {
154                     byte[] keyBytes = secRef.getSKIBytes();
155                     List<WSSecurityEngineResult> resultsList =
156                         data.getWsDocInfo().getResultsByTag(WSConstants.BST);
157                     for (WSSecurityEngineResult bstResult : resultsList) {
158                         BinarySecurity bstToken =
159                             (BinarySecurity)bstResult.get(WSSecurityEngineResult.TAG_BINARY_SECURITY_TOKEN);
160                         byte[] tokenDigest = KeyUtils.generateDigest(bstToken.getToken());
161                         if (Arrays.equals(tokenDigest, keyBytes)) {
162                             secretKey = (byte[])bstResult.get(WSSecurityEngineResult.TAG_SECRET);
163                             break;
164                         }
165                     }
166                 }
167                 if (secretKey == null) {
168                     throw new WSSecurityException(
169                         WSSecurityException.ErrorCode.FAILED_CHECK, "unsupportedKeyId",
170                         new Object[] {uri});
171                 }
172                 parserResult.setSecretKey(secretKey);
173             } else {
174                 if (SecurityTokenReference.ENC_KEY_SHA1_URI.equals(keyIdentifierValueType)) {
175                     STRParserUtil.checkEncryptedKeyBSPCompliance(secRef, data.getBSPEnforcer());
176                 }
177                 Crypto crypto = data.getDecCrypto();
178                 X509Certificate[] certs = secRef.getKeyIdentifier(crypto);
179                 if (certs == null || certs.length < 1 || certs[0] == null) {
180                     byte[] secretKey =
181                         STRParserUtil.getSecretKeyFromToken(
182                             secRef.getKeyIdentifierValue(), keyIdentifierValueType,
183                             WSPasswordCallback.SECRET_KEY, data
184                        );
185                     if (secretKey == null || secretKey.length == 0) {
186                         throw new WSSecurityException(
187                             WSSecurityException.ErrorCode.FAILED_CHECK, "unsupportedKeyId",
188                             new Object[] {uri});
189                     }
190                     parserResult.setSecretKey(secretKey);
191                 } else {
192                     byte[] secretKey = crypto.getPrivateKey(certs[0], data.getCallbackHandler()).getEncoded();
193                     parserResult.setSecretKey(secretKey);
194                 }
195             }
196         } else {
197             throw new WSSecurityException(
198                 WSSecurityException.ErrorCode.FAILED_CHECK, "unsupportedKeyId"
199             );
200         }
201 
202         return parserResult;
203     }
204 
205 }