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.saml;
21  
22  import javax.xml.crypto.dsig.CanonicalizationMethod;
23  import org.apache.wss4j.common.saml.SamlAssertionWrapper;
24  import org.apache.wss4j.common.util.SOAPUtil;
25  import org.w3c.dom.Document;
26  import org.w3c.dom.Element;
27  import org.apache.wss4j.common.crypto.AlgorithmSuite;
28  import org.apache.wss4j.common.crypto.Crypto;
29  import org.apache.wss4j.common.crypto.CryptoFactory;
30  import org.apache.wss4j.common.ext.WSSecurityException;
31  import org.apache.wss4j.dom.WSConstants;
32  import org.apache.wss4j.dom.common.SAML1CallbackHandler;
33  
34  import org.apache.wss4j.dom.engine.WSSConfig;
35  import org.apache.wss4j.dom.engine.WSSecurityEngine;
36  import org.apache.wss4j.dom.handler.RequestData;
37  import org.apache.wss4j.dom.handler.WSHandlerResult;
38  import org.apache.wss4j.dom.message.WSSecHeader;
39  import org.apache.wss4j.dom.message.WSSecSAMLToken;
40  import org.apache.wss4j.common.saml.SAMLCallback;
41  import org.apache.wss4j.common.saml.SAMLUtil;
42  import org.apache.wss4j.common.saml.builder.SAML1Constants;
43  import org.apache.wss4j.common.util.XMLUtils;
44  import org.apache.wss4j.dom.util.WSSecurityUtil;
45  
46  import org.junit.jupiter.api.Test;
47  
48  import static org.junit.jupiter.api.Assertions.assertTrue;
49  import static org.junit.jupiter.api.Assertions.fail;
50  
51  /**
52   * A set of test-cases for signing and verifying SOAP requests containing a signed
53   * SAML (HOK) assertion when specifying an AlgorithmSuite policy.
54   */
55  public class SamlAlgorithmSuiteTest {
56      private static final org.slf4j.Logger LOG =
57          org.slf4j.LoggerFactory.getLogger(SamlAlgorithmSuiteTest.class);
58      private Crypto crypto;
59  
60      public SamlAlgorithmSuiteTest() throws Exception {
61          WSSConfig.init();
62          crypto = CryptoFactory.getInstance("crypto.properties");
63      }
64  
65      @Test
66      public void testSignedSAML11Assertion() throws Exception {
67          SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
68          callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
69          callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
70          callbackHandler.setIssuer("www.example.com");
71  
72          SAMLCallback samlCallback = new SAMLCallback();
73          SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
74          SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
75  
76          samlAssertion.signAssertion("16c73ab6-b892-458f-abf5-2f875f74882e", "security", crypto, false);
77  
78  
79          Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
80          WSSecHeader secHeader = new WSSecHeader(doc);
81          secHeader.insertSecurityHeader();
82  
83          WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
84          Document signedDoc = wsSign.build(samlAssertion);
85  
86          if (LOG.isDebugEnabled()) {
87              String outputString =
88                  XMLUtils.prettyDocumentToString(signedDoc);
89              LOG.debug(outputString);
90          }
91  
92          Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
93          AlgorithmSuite algorithmSuite = createAlgorithmSuite();
94  
95          verify(securityHeader, algorithmSuite, crypto);
96  
97          algorithmSuite.setMinimumAsymmetricKeyLength(1024);
98  
99          try {
100             verify(securityHeader, algorithmSuite, crypto);
101             fail("Expected failure as 512-bit keys are not allowed");
102         } catch (WSSecurityException ex) {
103             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
104         }
105     }
106 
107     @Test
108     public void testDSASignedSAML11Assertion() throws Exception {
109         Crypto dsaCrypto = CryptoFactory.getInstance("wss40.properties");
110 
111         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
112         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
113         callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
114         callbackHandler.setIssuer("www.example.com");
115 
116         SAMLCallback samlCallback = new SAMLCallback();
117         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
118         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
119 
120         samlAssertion.signAssertion("wss40DSA", "security", dsaCrypto, false);
121 
122         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
123         WSSecHeader secHeader = new WSSecHeader(doc);
124         secHeader.insertSecurityHeader();
125 
126         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
127 
128         Document signedDoc = wsSign.build(samlAssertion);
129 
130         if (LOG.isDebugEnabled()) {
131             String outputString =
132                 XMLUtils.prettyDocumentToString(signedDoc);
133             LOG.debug(outputString);
134         }
135 
136         Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
137         AlgorithmSuite algorithmSuite = createAlgorithmSuite();
138 
139         try {
140             verify(securityHeader, algorithmSuite, dsaCrypto);
141             fail("Expected failure as DSA is not allowed");
142         } catch (WSSecurityException ex) {
143             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
144         }
145 
146         algorithmSuite.addSignatureMethod(WSConstants.DSA);
147         verify(securityHeader, algorithmSuite, dsaCrypto);
148     }
149 
150     @Test
151     public void testC14nMethod() throws Exception {
152         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
153         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
154         callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
155         callbackHandler.setIssuer("www.example.com");
156 
157         SAMLCallback samlCallback = new SAMLCallback();
158         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
159         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
160 
161         samlAssertion.signAssertion(
162             "16c73ab6-b892-458f-abf5-2f875f74882e", "security", crypto, false,
163             WSConstants.C14N_EXCL_WITH_COMMENTS, WSConstants.RSA_SHA1);
164 
165 
166         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
167         WSSecHeader secHeader = new WSSecHeader(doc);
168         secHeader.insertSecurityHeader();
169 
170         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
171 
172         Document signedDoc = wsSign.build(samlAssertion);
173 
174         if (LOG.isDebugEnabled()) {
175             String outputString =
176                 XMLUtils.prettyDocumentToString(signedDoc);
177             LOG.debug(outputString);
178         }
179 
180         Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
181         AlgorithmSuite algorithmSuite = createAlgorithmSuite();
182 
183         try {
184             verify(securityHeader, algorithmSuite, crypto);
185             fail("Expected failure as C14n algorithm is not allowed");
186         } catch (WSSecurityException ex) {
187             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
188         }
189 
190         algorithmSuite.addC14nAlgorithm(WSConstants.C14N_EXCL_WITH_COMMENTS);
191         verify(securityHeader, algorithmSuite, crypto);
192     }
193 
194     @Test
195     public void signWithEcdsaAlgorithmSHA1() throws Exception {
196         crypto = CryptoFactory.getInstance("wss40.properties");
197         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
198         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
199         callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
200         callbackHandler.setIssuer("www.example.com");
201 
202         SAMLCallback samlCallback = new SAMLCallback();
203         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
204         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
205 
206         samlAssertion.signAssertion(
207             "wss40ec", "security", crypto, false,
208             CanonicalizationMethod.EXCLUSIVE, WSConstants.ECDSA_SHA1);
209 
210 
211         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
212         WSSecHeader secHeader = new WSSecHeader(doc);
213         secHeader.insertSecurityHeader();
214 
215         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
216 
217         Document signedDoc = wsSign.build(samlAssertion);
218 
219         if (LOG.isDebugEnabled()) {
220             String outputString =
221                 XMLUtils.prettyDocumentToString(signedDoc);
222             LOG.debug(outputString);
223         }
224 
225         Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
226         AlgorithmSuite algorithmSuite = createAlgorithmSuite();
227 
228         try {
229             verify(securityHeader, algorithmSuite, crypto);
230             fail("Expected failure as C14n algorithm is not allowed");
231         } catch (WSSecurityException ex) {
232             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
233         }
234 
235         algorithmSuite.addSignatureMethod(WSConstants.ECDSA_SHA1);
236 
237         verify(securityHeader, algorithmSuite, crypto);
238     }
239 
240     @Test
241     public void signWithEcdsaAlgorithmSHA256() throws Exception {
242         crypto = CryptoFactory.getInstance("wss40.properties");
243         SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
244         callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
245         callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
246         callbackHandler.setIssuer("www.example.com");
247 
248         SAMLCallback samlCallback = new SAMLCallback();
249         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
250         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
251 
252         samlAssertion.signAssertion(
253                 "wss40ec", "security", crypto, false,
254                 CanonicalizationMethod.EXCLUSIVE, WSConstants.ECDSA_SHA256);
255 
256 
257         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
258         WSSecHeader secHeader = new WSSecHeader(doc);
259         secHeader.insertSecurityHeader();
260 
261         WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
262 
263         Document signedDoc = wsSign.build(samlAssertion);
264 
265         if (LOG.isDebugEnabled()) {
266             String outputString =
267                     XMLUtils.prettyDocumentToString(signedDoc);
268             LOG.debug(outputString);
269         }
270 
271         Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
272         AlgorithmSuite algorithmSuite = createAlgorithmSuite();
273 
274         try {
275             verify(securityHeader, algorithmSuite, crypto);
276             fail("Expected failure as C14n algorithm is not allowed");
277         } catch (WSSecurityException ex) {
278             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
279         }
280 
281         algorithmSuite.addSignatureMethod(WSConstants.ECDSA_SHA256);
282 
283         verify(securityHeader, algorithmSuite, crypto);
284     }
285 
286     private AlgorithmSuite createAlgorithmSuite() {
287         AlgorithmSuite algorithmSuite = new AlgorithmSuite();
288         algorithmSuite.addSignatureMethod(WSConstants.RSA_SHA1);
289         algorithmSuite.setMinimumAsymmetricKeyLength(512);
290         algorithmSuite.addC14nAlgorithm(WSConstants.C14N_EXCL_OMIT_COMMENTS);
291         algorithmSuite.addDigestAlgorithm(WSConstants.SHA1);
292 
293         return algorithmSuite;
294     }
295 
296     private WSHandlerResult verify(
297         Element securityHeader, AlgorithmSuite algorithmSuite, Crypto sigVerCrypto
298     ) throws Exception {
299         WSSecurityEngine secEngine = new WSSecurityEngine();
300         RequestData data = new RequestData();
301         data.setSigVerCrypto(sigVerCrypto);
302         data.setSamlAlgorithmSuite(algorithmSuite);
303         data.setValidateSamlSubjectConfirmation(false);
304 
305         return secEngine.processSecurityHeader(securityHeader, data);
306     }
307 
308 
309 }