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.saml;
20  
21  import org.apache.wss4j.common.WSS4JConstants;
22  import org.apache.wss4j.common.saml.OpenSAMLUtil;
23  import org.apache.wss4j.common.saml.bean.AttributeBean;
24  import org.apache.wss4j.common.saml.bean.AttributeStatementBean;
25  import org.apache.wss4j.common.saml.bean.SubjectConfirmationDataBean;
26  import org.apache.wss4j.common.saml.bean.Version;
27  import org.apache.wss4j.dom.handler.WSHandlerConstants;
28  import org.apache.wss4j.stax.ext.WSSConstants;
29  import org.apache.wss4j.stax.ext.WSSSecurityProperties;
30  import org.apache.wss4j.stax.setup.OutboundWSSec;
31  import org.apache.wss4j.stax.setup.WSSec;
32  import org.apache.wss4j.stax.test.AbstractTestBase;
33  import org.apache.wss4j.stax.test.utils.XmlReaderToWriter;
34  import org.apache.xml.security.stax.securityEvent.SecurityEvent;
35  import org.junit.jupiter.api.Test;
36  import org.opensaml.core.xml.schema.XSAny;
37  import org.opensaml.core.xml.schema.impl.XSAnyBuilder;
38  import org.opensaml.saml.saml2.core.*;
39  import org.w3c.dom.Document;
40  import org.w3c.dom.Element;
41  
42  import javax.xml.namespace.QName;
43  import jakarta.xml.soap.SOAPConstants;
44  import javax.xml.stream.XMLStreamReader;
45  import javax.xml.stream.XMLStreamWriter;
46  import java.io.ByteArrayInputStream;
47  import java.io.ByteArrayOutputStream;
48  import java.nio.charset.StandardCharsets;
49  import java.util.ArrayList;
50  import java.util.Arrays;
51  import java.util.Collections;
52  import java.util.List;
53  
54  import static org.junit.jupiter.api.Assertions.assertEquals;
55  
56  /**
57   * Tests related to handling of custom contents in SAML data structures.
58   */
59  public class CustomContentsTest extends AbstractTestBase {
60  
61      @Test
62      public void testSubjectConfirmationDataExtensibility() throws Exception {
63  
64          OpenSAMLUtil.initSamlEngine();
65  
66          // create a data structure with custom contents
67          SubjectConfirmationDataBean subjectConfirmationDataBean = new SubjectConfirmationDataBean();
68          {
69              XSAny element1 = new XSAnyBuilder().buildObject("http://abc", "Foobar", "abc");
70              element1.getUnknownAttributes().put(new QName(null, "foo"), "123");
71              element1.getUnknownAttributes().put(new QName(null, "bar"), "456");
72              element1.getUnknownXMLObjects().add(new XSAnyBuilder().buildObject("http://cde", "Unknown", "cde"));
73  
74              XSAny element2 = new XSAnyBuilder().buildObject("http://qpr", "Barfuss", "qpr");
75              element2.getUnknownXMLObjects().add(new XSAnyBuilder().buildObject("http://xyz1", "Jacke", "xyz1"));
76              element2.getUnknownXMLObjects().add(new XSAnyBuilder().buildObject("http://xyz2", "Hose", "xyz2"));
77              element2.getUnknownXMLObjects().add(new XSAnyBuilder().buildObject("http://xyz3", "Kappe", "xyz3"));
78  
79              AttributeStatementBean attributeStatementBean1 = new AttributeStatementBean();
80              addAttribute(attributeStatementBean1, "name-1", stringValue("value-1"));
81              addAttribute(attributeStatementBean1, "name-2", stringValue("value-2"));
82  
83              AttributeStatementBean attributeStatementBean2 = new AttributeStatementBean();
84              addAttribute(attributeStatementBean2, "name-3", stringValue("value-3"));
85              addAttribute(attributeStatementBean2, "name-4", stringValue("value-4"));
86  
87              Object unsupported1 = Math.PI;
88              Object unsupported2 = null;
89              Object unsupported3 = "blabla";
90  
91              // From these seven elements, only four shall be present in the resulting token,
92              // because three are of unsupported types or equal to null.
93              subjectConfirmationDataBean.setAny(Arrays.asList(
94                      unsupported1, element1, attributeStatementBean1,
95                      unsupported2, element2, attributeStatementBean2,
96                      unsupported3));
97          }
98  
99          // create assertion
100         ByteArrayOutputStream baos = new ByteArrayOutputStream();
101         {
102             SAMLCallbackHandlerImpl callbackHandler = new SAMLCallbackHandlerImpl();
103             callbackHandler.setStatement(SAMLCallbackHandlerImpl.Statement.ATTR);
104             callbackHandler.setIssuer("www.example.com");
105             callbackHandler.setSignAssertion(false);
106             callbackHandler.setSamlVersion(Version.SAML_20);
107             callbackHandler.setSubjectName("subject123");
108             callbackHandler.setSubjectConfirmationData(subjectConfirmationDataBean);
109 
110             WSSSecurityProperties securityProperties = new WSSSecurityProperties();
111             List<WSSConstants.Action> actions = new ArrayList<>();
112             actions.add(WSSConstants.SAML_TOKEN_UNSIGNED);
113             securityProperties.setActions(actions);
114             securityProperties.setSamlCallbackHandler(callbackHandler);
115 
116             OutboundWSSec wsSecOut = WSSec.getOutboundWSSec(securityProperties);
117             XMLStreamWriter xmlStreamWriter = wsSecOut.processOutMessage(baos, StandardCharsets.UTF_8.name(), new ArrayList<SecurityEvent>());
118             XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml"));
119             XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
120             xmlStreamWriter.close();
121 
122 //            System.out.println(baos.toString());
123             Document document = documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray()));
124             Element elem = document.getDocumentElement();
125             elem = (Element) elem.getElementsByTagNameNS(SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE, "Header").item(0);
126             elem = (Element) elem.getElementsByTagNameNS(WSS4JConstants.WSSE_NS, WSS4JConstants.WSSE_LN).item(0);
127             elem = (Element) elem.getElementsByTagNameNS(WSS4JConstants.SAML2_NS, Assertion.DEFAULT_ELEMENT_LOCAL_NAME).item(0);
128             elem = (Element) elem.getElementsByTagNameNS(WSS4JConstants.SAML2_NS, Subject.DEFAULT_ELEMENT_LOCAL_NAME).item(0);
129             elem = (Element) elem.getElementsByTagNameNS(WSS4JConstants.SAML2_NS, SubjectConfirmation.DEFAULT_ELEMENT_LOCAL_NAME).item(0);
130             elem = (Element) elem.getElementsByTagNameNS(WSS4JConstants.SAML2_NS, SubjectConfirmationData.DEFAULT_ELEMENT_LOCAL_NAME).item(0);
131             assertEquals(4, elem.getChildNodes().getLength());
132 
133             // Extensibility element 1 -- XMLObject
134             elem = (Element) elem.getFirstChild();
135             assertEquals("Foobar", elem.getLocalName());
136             assertEquals("http://abc", elem.getNamespaceURI());
137             assertEquals(3, elem.getAttributes().getLength());
138             assertEquals(1, elem.getChildNodes().getLength());
139 
140             // Extensibility element 2 -- AttributeStatement
141             elem = (Element) elem.getNextSibling();
142             assertEquals(AttributeStatement.DEFAULT_ELEMENT_LOCAL_NAME, elem.getLocalName());
143             assertEquals(2, elem.getChildNodes().getLength());
144             assertEquals(Attribute.DEFAULT_ELEMENT_LOCAL_NAME, elem.getFirstChild().getLocalName());
145             assertEquals(Attribute.DEFAULT_ELEMENT_LOCAL_NAME, elem.getFirstChild().getNextSibling().getLocalName());
146 
147             // Extensibility element 3 -- XMLObject
148             elem = (Element) elem.getNextSibling();
149             assertEquals("Barfuss", elem.getLocalName());
150             assertEquals("http://qpr", elem.getNamespaceURI());
151             assertEquals(1, elem.getAttributes().getLength());
152             assertEquals(3, elem.getChildNodes().getLength());
153 
154             // Extensibility element 4 -- AttributeStatement
155             elem = (Element) elem.getNextSibling();
156             assertEquals(AttributeStatement.DEFAULT_ELEMENT_LOCAL_NAME, elem.getLocalName());
157             assertEquals(2, elem.getChildNodes().getLength());
158             assertEquals(Attribute.DEFAULT_ELEMENT_LOCAL_NAME, elem.getFirstChild().getLocalName());
159             assertEquals(Attribute.DEFAULT_ELEMENT_LOCAL_NAME, elem.getFirstChild().getNextSibling().getLocalName());
160         }
161 
162         // done signature; now test sig-verification:
163         {
164             String action = WSHandlerConstants.SAML_TOKEN_UNSIGNED;
165             doInboundSecurityWithWSS4J(documentBuilderFactory.newDocumentBuilder().parse(new ByteArrayInputStream(baos.toByteArray())), action);
166         }
167     }
168 
169 
170     private static void addAttribute(AttributeStatementBean attributeStatement, String attributeName, Object value) {
171         AttributeBean attribute = new AttributeBean(null, attributeName, Collections.singletonList(value));
172         attribute.setNameFormat(Attribute.UNSPECIFIED);
173         attributeStatement.getSamlAttributes().add(attribute);
174     }
175 
176     private static XSAny stringValue(String s) {
177         XSAny value = new XSAnyBuilder().buildObject(AttributeValue.DEFAULT_ELEMENT_NAME);
178         value.setTextContent(s);
179         return value;
180     }
181 
182 }