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.message;
21  
22  import java.util.Collections;
23  import java.util.regex.Pattern;
24  
25  import org.apache.wss4j.common.crypto.Crypto;
26  import org.apache.wss4j.common.crypto.CryptoFactory;
27  import org.apache.wss4j.common.ext.WSSecurityException;
28  import org.apache.wss4j.common.util.SOAPUtil;
29  import org.apache.wss4j.common.util.XMLUtils;
30  import org.apache.wss4j.dom.WSConstants;
31  
32  import org.apache.wss4j.dom.engine.WSSConfig;
33  import org.apache.wss4j.dom.engine.WSSecurityEngine;
34  import org.apache.wss4j.dom.handler.RequestData;
35  import org.apache.wss4j.dom.handler.WSHandlerResult;
36  import org.apache.wss4j.dom.util.WSSecurityUtil;
37  
38  import org.junit.jupiter.api.Test;
39  import org.w3c.dom.Document;
40  import org.w3c.dom.Element;
41  
42  import static org.junit.jupiter.api.Assertions.assertTrue;
43  import static org.junit.jupiter.api.Assertions.fail;
44  
45  
46  /**
47   * A set of test-cases for signing and verifying SOAP requests, where the issuer of the certificate used to
48   * verify the signature is validated against a set of cert constraints.
49   */
50  public class SignatureIssuerCertConstraintsTest {
51      private static final org.slf4j.Logger LOG =
52          org.slf4j.LoggerFactory.getLogger(SignatureIssuerCertConstraintsTest.class);
53      private Crypto crypto;
54      private Crypto cryptoCA;
55  
56      public SignatureIssuerCertConstraintsTest() throws Exception {
57          WSSConfig.init();
58          crypto = CryptoFactory.getInstance("wss40.properties");
59          cryptoCA = CryptoFactory.getInstance("wss40CA.properties");
60      }
61  
62      /**
63       * The test uses the BinarySecurityToken key identifier type.
64       */
65      @Test
66      public void testBSTSignature() throws Exception {
67          Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
68          WSSecHeader secHeader = new WSSecHeader(doc);
69          secHeader.insertSecurityHeader();
70  
71          WSSecSignature builder = new WSSecSignature(secHeader);
72          builder.setUserInfo("wss40", "security");
73          builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
74  
75          Document signedDoc = builder.build(crypto);
76  
77          if (LOG.isDebugEnabled()) {
78              LOG.debug("Signed message with BST key identifier:");
79              String outputString =
80                  XMLUtils.prettyDocumentToString(signedDoc);
81              LOG.debug(outputString);
82          }
83  
84          Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
85          String certConstraint = ".*CN=Werner.*OU=Apache.*";
86          verify(securityHeader, cryptoCA, certConstraint);
87  
88          certConstraint = ".*CN=Werner2.*O=Apache.*";
89          try {
90              verify(securityHeader, cryptoCA, certConstraint);
91              fail("Failure expected on a bad cert constraint");
92          } catch (WSSecurityException ex) {
93              assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
94          }
95      }
96  
97      /**
98       * The test uses the BinarySecurityToken key identifier type.
99       */
100     @Test
101     public void testBSTSignaturePKIPath() throws Exception {
102         Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
103         WSSecHeader secHeader = new WSSecHeader(doc);
104         secHeader.insertSecurityHeader();
105 
106         WSSecSignature builder = new WSSecSignature(secHeader);
107         builder.setUserInfo("wss40", "security");
108         builder.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
109         builder.setUseSingleCertificate(false);
110 
111         Document signedDoc = builder.build(crypto);
112 
113         if (LOG.isDebugEnabled()) {
114             LOG.debug("Signed message with BST key identifier:");
115             String outputString =
116                 XMLUtils.prettyDocumentToString(signedDoc);
117             LOG.debug(outputString);
118         }
119 
120         Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
121         String certConstraint = ".*CN=Werner.*OU=Apache.*";
122         verify(securityHeader, cryptoCA, certConstraint);
123 
124         certConstraint = ".*CN=Werner2.*O=Apache.*";
125         try {
126             verify(securityHeader, cryptoCA, certConstraint);
127             fail("Failure expected on a bad cert constraint");
128         } catch (WSSecurityException ex) {
129             assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);
130         }
131     }
132 
133     private WSHandlerResult verify(
134         Element securityHeader, Crypto sigCrypto, String certConstraint
135     ) throws Exception {
136         WSSecurityEngine secEngine = new WSSecurityEngine();
137         RequestData data = new RequestData();
138         data.setSigVerCrypto(sigCrypto);
139 
140         if (certConstraint != null) {
141             Pattern issuerDNPattern = Pattern.compile(certConstraint.trim());
142             data.setIssuerDNPatterns(Collections.singletonList(issuerDNPattern));
143         }
144 
145         return secEngine.processSecurityHeader(securityHeader, data);
146     }
147 
148 }