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  package org.apache.wss4j.stax.test;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.ByteArrayOutputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.util.Collections;
26  import java.util.Enumeration;
27  import java.util.Map;
28  import java.util.Properties;
29  import java.util.regex.Pattern;
30  
31  import javax.xml.stream.XMLStreamReader;
32  import javax.xml.transform.TransformerException;
33  import javax.xml.transform.dom.DOMSource;
34  import javax.xml.transform.stream.StreamResult;
35  
36  import org.apache.wss4j.common.ext.WSSecurityException;
37  import org.apache.wss4j.dom.handler.RequestData;
38  import org.apache.wss4j.dom.handler.WSHandlerConstants;
39  import org.apache.wss4j.stax.ext.WSSConstants;
40  import org.apache.wss4j.stax.ext.WSSSecurityProperties;
41  import org.apache.wss4j.stax.setup.InboundWSSec;
42  import org.apache.wss4j.stax.setup.WSSec;
43  import org.apache.wss4j.stax.test.utils.StAX2DOM;
44  import org.junit.jupiter.api.Test;
45  import org.w3c.dom.Document;
46  import org.w3c.dom.NodeList;
47  
48  import static org.junit.jupiter.api.Assertions.assertEquals;
49  import static org.junit.jupiter.api.Assertions.assertTrue;
50  import static org.junit.jupiter.api.Assertions.fail;
51  
52  /**
53   * A set of test-cases for signing and verifying SOAP requests, where the certificate used to
54   * verify the signature is validated against a set of cert constraints.
55   */
56  public class SignatureIssuerCertConstaintsTest extends AbstractTestBase {
57  
58      @Test
59      public void testBSTSignature() throws Exception {
60          ByteArrayOutputStream baos = new ByteArrayOutputStream();
61          {
62              InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml");
63              String action = WSHandlerConstants.SIGNATURE;
64              Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, new Properties());
65  
66              //some test that we can really sure we get what we want from WSS4J
67              NodeList nodeList = securedDocument.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
68              assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
69  
70              javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
71              transformer.transform(new DOMSource(securedDocument), new StreamResult(baos));
72          }
73  
74          //done signature; now test sig-verification: This should pass with a correct cert constraint check
75          {
76              WSSSecurityProperties securityProperties = new WSSSecurityProperties();
77              securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("keys/wss40CA.jks"), "security".toCharArray());
78              String certConstraint = ".*CN=Werner.*OU=Apache.*";
79              Pattern issuerDNPattern = Pattern.compile(certConstraint.trim());
80              securityProperties.setIssuerDNConstraints(Collections.singletonList(issuerDNPattern));
81  
82              InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
83              XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
84  
85              Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
86  
87              //header element must still be there
88              NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
89              assertEquals(nodeList.getLength(), 1);
90              assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
91          }
92  
93          //done signature; now test sig-verification: This should fail with an incorrect cert constraint check
94          {
95              WSSSecurityProperties securityProperties = new WSSSecurityProperties();
96              securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("keys/wss40CA.jks"), "security".toCharArray());
97              String certConstraint = ".*CN=Werner2.*OU=Apache.*";
98              Pattern issuerDNPattern = Pattern.compile(certConstraint.trim());
99              securityProperties.setIssuerDNConstraints(Collections.singletonList(issuerDNPattern));
100 
101             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties, false, true);
102             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
103 
104             try {
105                 StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
106                 fail("Expected failure on a incorrect cert constraint check");
107             } catch (Exception ex) {
108                 String errorMessage = "The security token could not be authenticated or authorized";
109                 assertTrue(ex.getMessage().contains(errorMessage));
110             }
111         }
112     }
113 
114     @Test
115     public void testBSTSignaturePKIPath() throws Exception {
116         ByteArrayOutputStream baos = new ByteArrayOutputStream();
117         {
118             InputStream sourceDocument = this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml");
119             String action = WSHandlerConstants.SIGNATURE;
120             Properties properties = new Properties();
121             properties.put(WSHandlerConstants.USE_SINGLE_CERTIFICATE, "false");
122             Document securedDocument = doOutboundSecurityWithWSS4J(sourceDocument, action, properties);
123 
124             //some test that we can really sure we get what we want from WSS4J
125             NodeList nodeList = securedDocument.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
126             assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
127 
128             javax.xml.transform.Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
129             transformer.transform(new DOMSource(securedDocument), new StreamResult(baos));
130         }
131 
132         //done signature; now test sig-verification: This should pass with a correct cert constraint check
133         {
134             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
135             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("keys/wss40CA.jks"), "security".toCharArray());
136             String certConstraint = ".*CN=Werner.*OU=Apache.*";
137             Pattern issuerDNPattern = Pattern.compile(certConstraint.trim());
138             securityProperties.setIssuerDNConstraints(Collections.singletonList(issuerDNPattern));
139 
140             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties);
141             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
142 
143             Document document = StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
144 
145             //header element must still be there
146             NodeList nodeList = document.getElementsByTagNameNS(WSSConstants.TAG_dsig_Signature.getNamespaceURI(), WSSConstants.TAG_dsig_Signature.getLocalPart());
147             assertEquals(nodeList.getLength(), 1);
148             assertEquals(nodeList.item(0).getParentNode().getLocalName(), WSSConstants.TAG_WSSE_SECURITY.getLocalPart());
149         }
150 
151         //done signature; now test sig-verification: This should fail with an incorrect cert constraint check
152         {
153             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
154             securityProperties.loadSignatureVerificationKeystore(this.getClass().getClassLoader().getResource("keys/wss40CA.jks"), "security".toCharArray());
155             String certConstraint = ".*CN=Werner2.*OU=Apache.*";
156             Pattern issuerDNPattern = Pattern.compile(certConstraint.trim());
157             securityProperties.setIssuerDNConstraints(Collections.singletonList(issuerDNPattern));
158 
159             InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties, false, true);
160             XMLStreamReader xmlStreamReader = wsSecIn.processInMessage(xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(baos.toByteArray())));
161 
162             try {
163                 StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(), xmlStreamReader);
164                 fail("Expected failure on a incorrect cert constraint check");
165             } catch (Exception ex) {
166                 String errorMessage = "The security token could not be authenticated or authorized";
167                 assertTrue(ex.getMessage().contains(errorMessage));
168             }
169         }
170     }
171 
172     @Override
173     protected Map<String, Object> doOutboundSecurityWithWSS4J_1(
174         InputStream sourceDocument, String action, final Properties properties
175     ) throws WSSecurityException, TransformerException, IOException {
176         CustomWSS4JHandler wss4JHandler = new CustomWSS4JHandler();
177         final Map<String, Object> messageContext = getMessageContext(sourceDocument);
178         messageContext.put(WSHandlerConstants.ACTION, action);
179         messageContext.put(WSHandlerConstants.USER, "wss40");
180         messageContext.put(WSHandlerConstants.SIG_KEY_ID, "DirectReference");
181 
182         Properties sigProperties = new Properties();
183         sigProperties.setProperty("org.apache.wss4j.crypto.provider", "org.apache.wss4j.common.crypto.Merlin");
184         sigProperties.setProperty("org.apache.wss4j.crypto.merlin.keystore.file", "keys/wss40.jks");
185         sigProperties.setProperty("org.apache.wss4j.crypto.merlin.keystore.password", "security");
186         sigProperties.setProperty("org.apache.wss4j.crypto.merlin.keystore.alias", "wss40");
187         wss4JHandler.setPassword(messageContext, "security");
188         messageContext.put(WSHandlerConstants.SIG_PROP_REF_ID, "" + sigProperties.hashCode());
189         messageContext.put("" + sigProperties.hashCode(), sigProperties);
190 
191         Enumeration<?> enumeration = properties.propertyNames();
192         while (enumeration.hasMoreElements()) {
193             String s = (String) enumeration.nextElement();
194             messageContext.put(s, properties.get(s));
195         }
196 
197         RequestData requestData = new RequestData();
198         requestData.setMsgContext(messageContext);
199 
200         wss4JHandler.doSender(messageContext, requestData, true);
201 
202         return messageContext;
203     }
204 
205 }