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.ext;
21  
22  import java.io.InputStream;
23  import java.security.KeyStore;
24  
25  import javax.xml.parsers.DocumentBuilderFactory;
26  
27  import org.apache.wss4j.common.crypto.Crypto;
28  import org.apache.wss4j.common.crypto.CryptoType;
29  import org.apache.wss4j.common.crypto.Merlin;
30  import org.apache.wss4j.common.saml.SAMLCallback;
31  import org.apache.wss4j.common.saml.SAMLKeyInfo;
32  import org.apache.wss4j.common.saml.SAMLUtil;
33  import org.apache.wss4j.common.saml.SamlAssertionWrapper;
34  import org.apache.wss4j.common.saml.builder.SAML2Constants;
35  import org.apache.wss4j.common.util.DOM2Writer;
36  import org.apache.wss4j.common.util.Loader;
37  import org.apache.wss4j.dom.common.SAML2CallbackHandler;
38  
39  import org.apache.wss4j.dom.engine.WSSConfig;
40  
41  import org.junit.jupiter.api.Test;
42  import org.opensaml.xmlsec.signature.Signature;
43  import org.opensaml.xmlsec.signature.support.SignatureConstants;
44  import org.w3c.dom.Document;
45  import org.w3c.dom.Element;
46  
47  import static org.junit.jupiter.api.Assertions.assertEquals;
48  import static org.junit.jupiter.api.Assertions.assertTrue;
49  
50  /**
51   * A list of test-cases to test the functionality of signing with
52   * SamlAssertionWrapper class implementation.
53   */
54  
55  public class AssertionSigningTest {
56  
57      private Crypto issuerCrypto;
58      // Default Canonicalization algorithm used by SamlAssertionWrapper class.
59      private final String defaultCanonicalizationAlgorithm = SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS;
60      // Default RSA Signature algorithm used by SamlAssertionWrapper class.
61      private final String defaultRSASignatureAlgorithm = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1;
62      // Default DSA Signature algorithm used by SamlAssertionWrapper class.
63      private final String defaultDSASignatureAlgorithm = SignatureConstants.ALGO_ID_SIGNATURE_DSA;
64      // Custom Signature algorithm
65      private final String customSignatureAlgorithm = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256;
66      // Custom Canonicalization algorithm
67      private final String customCanonicalizationAlgorithm = SignatureConstants.ALGO_ID_C14N_OMIT_COMMENTS;
68      // Custom Signature Digest algorithm
69      private final String customSignatureDigestAlgorithm = SignatureConstants.ALGO_ID_DIGEST_SHA256;
70      private final DocumentBuilderFactory dbf;
71  
72      public AssertionSigningTest() throws Exception {
73          WSSConfig.init();
74          // Load the issuer keystore
75          issuerCrypto = new Merlin();
76          KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
77          ClassLoader loader = Loader.getClassLoader(AssertionSigningTest.class);
78          InputStream input = Merlin.loadInputStream(loader,
79                  "keys/wss40.jks");
80          keyStore.load(input, "security".toCharArray());
81          input.close();
82          ((Merlin) issuerCrypto).setKeyStore(keyStore);
83  
84          dbf = DocumentBuilderFactory.newInstance();
85          dbf.setNamespaceAware(true);
86      }
87  
88      /**
89       * Test that creates an SamlAssertionWrapper object and signs using default
90       * signature and canonicalization algorithms. The defaults should match
91       * otherwise the test-case fails.
92       */
93      @Test
94      public void testSigningWithDefaultAlgorithms() throws Exception {
95          SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
96          callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
97          callbackHandler
98                  .setConfirmationMethod(SAML2Constants.CONF_SENDER_VOUCHES);
99          callbackHandler.setIssuer("www.example.com");
100 
101         SAMLCallback samlCallback = new SAMLCallback();
102         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
103         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
104 
105         samlAssertion.signAssertion("wss40", "security", issuerCrypto,
106                 false);
107         Signature signature = samlAssertion.getSaml2().getSignature();
108         assertTrue(signature.getSignatureAlgorithm().equalsIgnoreCase(
109                 defaultRSASignatureAlgorithm)
110                 || signature.getSignatureAlgorithm().equalsIgnoreCase(
111                         defaultDSASignatureAlgorithm));
112         assertEquals(defaultCanonicalizationAlgorithm,
113                 signature.getCanonicalizationAlgorithm());
114 
115         // Verify Signature
116         SAMLKeyInfo keyInfo = new SAMLKeyInfo();
117         CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
118         cryptoType.setAlias("wss40");
119         keyInfo.setCerts(issuerCrypto.getX509Certificates(cryptoType));
120 
121         Document doc = dbf.newDocumentBuilder().newDocument();
122 
123         Element assertionElement = samlAssertion.toDOM(doc);
124         doc.appendChild(assertionElement);
125 
126         samlAssertion = new SamlAssertionWrapper(assertionElement);
127         samlAssertion.verifySignature(keyInfo);
128     }
129 
130     /**
131      * Test that creates an SamlAssertionWrapper object and signs using custom
132      * signature and canonicalization algorithms.
133      */
134     @Test
135     public void testSigningWithCustomAlgorithms() throws Exception {
136         SAML2CallbackHandler callbackHandler = new SAML2CallbackHandler();
137         callbackHandler.setStatement(SAML2CallbackHandler.Statement.AUTHN);
138         callbackHandler
139                 .setConfirmationMethod(SAML2Constants.CONF_SENDER_VOUCHES);
140         callbackHandler.setIssuer("www.example.com");
141 
142         SAMLCallback samlCallback = new SAMLCallback();
143         SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
144         SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
145 
146         samlAssertion.signAssertion("wss40", "security", issuerCrypto,
147                 false, customCanonicalizationAlgorithm,
148                 customSignatureAlgorithm, customSignatureDigestAlgorithm);
149         Signature signature = samlAssertion.getSaml2().getSignature();
150         assertEquals(customSignatureAlgorithm,
151                 signature.getSignatureAlgorithm());
152         assertEquals(customCanonicalizationAlgorithm,
153                 signature.getCanonicalizationAlgorithm());
154 
155         Document doc = dbf.newDocumentBuilder().newDocument();
156 
157         Element assertionElement = samlAssertion.toDOM(doc);
158         doc.appendChild(assertionElement);
159         String assertionString = DOM2Writer.nodeToString(assertionElement);
160         assertTrue(assertionString.contains(customSignatureDigestAlgorithm));
161 
162         // Verify Signature
163         SAMLKeyInfo keyInfo = new SAMLKeyInfo();
164         CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
165         cryptoType.setAlias("wss40");
166         keyInfo.setCerts(issuerCrypto.getX509Certificates(cryptoType));
167 
168         samlAssertion = new SamlAssertionWrapper(assertionElement);
169         samlAssertion.verifySignature(keyInfo);
170     }
171 
172 }