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.policy.stax.enforcer;
20  
21  import java.net.URL;
22  import java.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  
28  import javax.wsdl.Binding;
29  import javax.wsdl.BindingOperation;
30  import javax.wsdl.Definition;
31  import javax.wsdl.Operation;
32  import javax.wsdl.Port;
33  import javax.wsdl.PortType;
34  import javax.wsdl.Service;
35  import javax.wsdl.WSDLElement;
36  import javax.wsdl.WSDLException;
37  import javax.wsdl.extensions.ExtensibilityElement;
38  import javax.wsdl.extensions.UnknownExtensibilityElement;
39  import javax.wsdl.extensions.soap.SOAPOperation;
40  import javax.wsdl.extensions.soap12.SOAP12Operation;
41  import javax.wsdl.factory.WSDLFactory;
42  import javax.wsdl.xml.WSDLReader;
43  import javax.xml.namespace.QName;
44  
45  import org.apache.neethi.AssertionBuilderFactory;
46  import org.apache.neethi.Policy;
47  import org.apache.neethi.PolicyBuilder;
48  import org.apache.neethi.builders.AssertionBuilder;
49  import org.apache.wss4j.common.WSSPolicyException;
50  import org.apache.wss4j.policy.builders.AlgorithmSuiteBuilder;
51  import org.apache.wss4j.policy.builders.AsymmetricBindingBuilder;
52  import org.apache.wss4j.policy.builders.BootstrapPolicyBuilder;
53  import org.apache.wss4j.policy.builders.ContentEncryptedElementsBuilder;
54  import org.apache.wss4j.policy.builders.EncryptedElementsBuilder;
55  import org.apache.wss4j.policy.builders.EncryptedPartsBuilder;
56  import org.apache.wss4j.policy.builders.EncryptionTokenBuilder;
57  import org.apache.wss4j.policy.builders.HttpsTokenBuilder;
58  import org.apache.wss4j.policy.builders.InitiatorEncryptionTokenBuilder;
59  import org.apache.wss4j.policy.builders.InitiatorSignatureTokenBuilder;
60  import org.apache.wss4j.policy.builders.InitiatorTokenBuilder;
61  import org.apache.wss4j.policy.builders.IssuedTokenBuilder;
62  import org.apache.wss4j.policy.builders.KerberosTokenBuilder;
63  import org.apache.wss4j.policy.builders.KeyValueTokenBuilder;
64  import org.apache.wss4j.policy.builders.LayoutBuilder;
65  import org.apache.wss4j.policy.builders.ProtectionTokenBuilder;
66  import org.apache.wss4j.policy.builders.RecipientEncryptionTokenBuilder;
67  import org.apache.wss4j.policy.builders.RecipientSignatureTokenBuilder;
68  import org.apache.wss4j.policy.builders.RecipientTokenBuilder;
69  import org.apache.wss4j.policy.builders.RelTokenBuilder;
70  import org.apache.wss4j.policy.builders.RequiredElementsBuilder;
71  import org.apache.wss4j.policy.builders.RequiredPartsBuilder;
72  import org.apache.wss4j.policy.builders.SamlTokenBuilder;
73  import org.apache.wss4j.policy.builders.SecureConversationTokenBuilder;
74  import org.apache.wss4j.policy.builders.SecurityContextTokenBuilder;
75  import org.apache.wss4j.policy.builders.SignatureTokenBuilder;
76  import org.apache.wss4j.policy.builders.SignedElementsBuilder;
77  import org.apache.wss4j.policy.builders.SignedPartsBuilder;
78  import org.apache.wss4j.policy.builders.SpnegoContextTokenBuilder;
79  import org.apache.wss4j.policy.builders.SupportingTokensBuilder;
80  import org.apache.wss4j.policy.builders.SymmetricBindingBuilder;
81  import org.apache.wss4j.policy.builders.TransportBindingBuilder;
82  import org.apache.wss4j.policy.builders.TransportTokenBuilder;
83  import org.apache.wss4j.policy.builders.Trust10Builder;
84  import org.apache.wss4j.policy.builders.Trust13Builder;
85  import org.apache.wss4j.policy.builders.UsernameTokenBuilder;
86  import org.apache.wss4j.policy.builders.WSS10Builder;
87  import org.apache.wss4j.policy.builders.WSS11Builder;
88  import org.apache.wss4j.policy.builders.X509TokenBuilder;
89  import org.apache.wss4j.policy.stax.OperationPolicy;
90  import org.apache.wss4j.stax.ext.WSSConstants;
91  import org.w3c.dom.Document;
92  import org.w3c.dom.Element;
93  import org.w3c.dom.NodeList;
94  
95  /**
96   * PolicyEnforcerFactory builds a map of all the possible effective Policies
97   * and caches them for reuse
98   */
99  public class PolicyEnforcerFactory {
100 
101     protected static final org.slf4j.Logger LOG =
102         org.slf4j.LoggerFactory.getLogger(PolicyEnforcerFactory.class);
103 
104     private final List<AssertionBuilder<Element>> assertionBuilders;
105 
106     private Definition wsdlDefinition;
107     private List<OperationPolicy> operationPolicies;
108     private final Map<Element, Policy> elementPolicyCache;
109 
110     protected PolicyEnforcerFactory(List<AssertionBuilder<Element>> customAssertionBuilders) {
111         elementPolicyCache = new HashMap<>();
112 
113         assertionBuilders = new ArrayList<>();
114         assertionBuilders.add(new AlgorithmSuiteBuilder());
115         assertionBuilders.add(new AsymmetricBindingBuilder());
116         assertionBuilders.add(new ContentEncryptedElementsBuilder());
117         assertionBuilders.add(new EncryptedElementsBuilder());
118         assertionBuilders.add(new EncryptedPartsBuilder());
119         assertionBuilders.add(new EncryptionTokenBuilder());
120         assertionBuilders.add(new HttpsTokenBuilder());
121         assertionBuilders.add(new InitiatorEncryptionTokenBuilder());
122         assertionBuilders.add(new InitiatorSignatureTokenBuilder());
123         assertionBuilders.add(new InitiatorTokenBuilder());
124         assertionBuilders.add(new IssuedTokenBuilder());
125         assertionBuilders.add(new KerberosTokenBuilder());
126         assertionBuilders.add(new KeyValueTokenBuilder());
127         assertionBuilders.add(new LayoutBuilder());
128         assertionBuilders.add(new ProtectionTokenBuilder());
129         assertionBuilders.add(new RecipientEncryptionTokenBuilder());
130         assertionBuilders.add(new RecipientSignatureTokenBuilder());
131         assertionBuilders.add(new RecipientTokenBuilder());
132         assertionBuilders.add(new RelTokenBuilder());
133         assertionBuilders.add(new RequiredElementsBuilder());
134         assertionBuilders.add(new RequiredPartsBuilder());
135         assertionBuilders.add(new SamlTokenBuilder());
136         assertionBuilders.add(new SecureConversationTokenBuilder());
137         assertionBuilders.add(new BootstrapPolicyBuilder());
138         assertionBuilders.add(new SecurityContextTokenBuilder());
139         assertionBuilders.add(new SignatureTokenBuilder());
140         assertionBuilders.add(new SignedElementsBuilder());
141         assertionBuilders.add(new SignedPartsBuilder());
142         assertionBuilders.add(new SpnegoContextTokenBuilder());
143         assertionBuilders.add(new SupportingTokensBuilder());
144         assertionBuilders.add(new SymmetricBindingBuilder());
145         assertionBuilders.add(new TransportBindingBuilder());
146         assertionBuilders.add(new TransportTokenBuilder());
147         assertionBuilders.add(new Trust10Builder());
148         assertionBuilders.add(new Trust13Builder());
149         assertionBuilders.add(new UsernameTokenBuilder());
150         assertionBuilders.add(new WSS10Builder());
151         assertionBuilders.add(new WSS11Builder());
152         assertionBuilders.add(new X509TokenBuilder());
153 
154         if (customAssertionBuilders != null) {
155             for (int i = 0; i < customAssertionBuilders.size(); i++) {
156                 AssertionBuilder<Element> customAssertionBuilder = customAssertionBuilders.get(i);
157                 assertionBuilders.add(customAssertionBuilder);
158             }
159         }
160     }
161 
162     public static PolicyEnforcerFactory newInstance(URL wsdlUrl) throws WSSPolicyException {
163         return newInstance(wsdlUrl, null);
164     }
165 
166     public static PolicyEnforcerFactory newInstance(URL wsdlUrl,
167                                                     List<AssertionBuilder<Element>> customAssertionBuilders)
168             throws WSSPolicyException {
169 
170         PolicyEnforcerFactory policyEnforcerFactory = new PolicyEnforcerFactory(customAssertionBuilders);
171         policyEnforcerFactory.parseWsdl(wsdlUrl);
172         return policyEnforcerFactory;
173     }
174 
175     public static PolicyEnforcerFactory newInstance(Document document) throws WSSPolicyException {
176         return newInstance(document, null);
177     }
178 
179     public static PolicyEnforcerFactory newInstance(Document document,
180                                                     List<AssertionBuilder<Element>> customAssertionBuilders)
181             throws WSSPolicyException {
182 
183         PolicyEnforcerFactory policyEnforcerFactory = new PolicyEnforcerFactory(customAssertionBuilders);
184         policyEnforcerFactory.parseWsdl(document);
185         return policyEnforcerFactory;
186     }
187 
188     //todo enforce uniqueness of operation names to prevent SOAPAction spoofing.
189     private void parseWsdl(URL wsdlUrl) throws WSSPolicyException {
190         try {
191             WSDLFactory wsdlFactory = WSDLFactory.newInstance();
192             WSDLReader reader = wsdlFactory.newWSDLReader();
193             reader.setFeature("javax.wsdl.verbose", false);
194             wsdlDefinition = reader.readWSDL(wsdlUrl.toString());
195             operationPolicies = findPoliciesByOperation(wsdlDefinition);
196         } catch (WSDLException e) {
197             throw new WSSPolicyException(e.getMessage(), e);
198         }
199     }
200 
201     //todo enforce uniqueness of operation names to prevent SOAPAction spoofing.
202     private void parseWsdl(Document document) throws WSSPolicyException {
203         try {
204             WSDLFactory wsdlFactory = WSDLFactory.newInstance();
205             WSDLReader reader = wsdlFactory.newWSDLReader();
206             reader.setFeature("javax.wsdl.verbose", false);
207             wsdlDefinition = reader.readWSDL(document.getDocumentURI(), document);
208             operationPolicies = findPoliciesByOperation(wsdlDefinition);
209         } catch (WSDLException e) {
210             throw new WSSPolicyException(e.getMessage(), e);
211         }
212     }
213 
214     private List<OperationPolicy> findPoliciesByOperation(Definition wsdlDefinition) throws WSSPolicyException {
215 
216         List<OperationPolicy> operationPolicyList = new ArrayList<>();
217         @SuppressWarnings({"unchecked", "rawtypes"})
218         Iterator<Map.Entry> services = wsdlDefinition.getAllServices().entrySet().iterator();
219         while (services.hasNext()) {
220             @SuppressWarnings("unchecked")
221             Map.Entry<QName, Service> serviceEntry = services.next();
222             Service service = serviceEntry.getValue();
223             @SuppressWarnings({"unchecked", "rawtypes"})
224             Iterator<Map.Entry> ports = service.getPorts().entrySet().iterator();
225             while (ports.hasNext()) {
226                 @SuppressWarnings("unchecked")
227                 Map.Entry<QName, Port> portEntry = ports.next();
228                 Port port = portEntry.getValue();
229                 Binding binding = port.getBinding();
230 
231                 @SuppressWarnings("unchecked")
232                 List<BindingOperation> bindingOperations = binding.getBindingOperations();
233                 for (int i = 0; i < bindingOperations.size(); i++) {
234                     BindingOperation bindingOperation = bindingOperations.get(i);
235 
236                     Operation operation = bindingOperation.getOperation();
237 
238                     OperationPolicy operationPolicy =
239                         new OperationPolicy(new QName(null, operation.getName()));
240                     operationPolicyList.add(operationPolicy);
241 
242                     @SuppressWarnings("unchecked")
243                     List<ExtensibilityElement> extensibilityElements = bindingOperation.getExtensibilityElements();
244                     for (int j = 0; j < extensibilityElements.size(); j++) {
245                         ExtensibilityElement extensibilityElement = extensibilityElements.get(j);
246                         if (extensibilityElement instanceof SOAPOperation) {
247                             SOAPOperation soapOperation = (SOAPOperation) extensibilityElement;
248                             String soapActionUri = soapOperation.getSoapActionURI();
249                             operationPolicy.setOperationAction(soapActionUri);
250                             operationPolicy.setSoapMessageVersionNamespace(WSSConstants.NS_SOAP11);
251                         } else if (extensibilityElement instanceof SOAP12Operation) {
252                             SOAP12Operation soap12Operation = (SOAP12Operation) extensibilityElement;
253                             String soapActionUri = soap12Operation.getSoapActionURI();
254                             operationPolicy.setOperationAction(soapActionUri);
255                             operationPolicy.setSoapMessageVersionNamespace(WSSConstants.NS_SOAP12);
256                         }
257                     }
258 
259                     Policy policy = getPolicy(service, port, binding, bindingOperation, operation);
260                     operationPolicy.setPolicy(policy.normalize(true));
261                 }
262             }
263         }
264         return operationPolicyList;
265     }
266 
267     private Policy getPolicy(Service service, Port port, Binding binding,
268                              BindingOperation bindingOperation, Operation operation) throws WSSPolicyException {
269         List<Policy> policies = new ArrayList<>();
270 
271         Policy servicePolicy = findPolicies(service);
272         if (servicePolicy != null) {
273             policies.add(servicePolicy);
274         }
275         Policy portPolicy = findPolicies(port);
276         if (portPolicy != null) {
277             policies.add(portPolicy);
278         }
279         Policy bindingPolicy = findPolicies(binding);
280         if (bindingPolicy != null) {
281             policies.add(bindingPolicy);
282         }
283 
284         Policy bindingOperationPolicy = findPolicies(bindingOperation);
285         if (bindingOperationPolicy != null) {
286             policies.add(bindingOperationPolicy);
287         }
288 
289         Policy bindingOperationInputPolicy = findPolicies(bindingOperation.getBindingInput());
290         if (bindingOperationInputPolicy != null) {
291             policies.add(bindingOperationInputPolicy);
292         }
293 
294         Policy portTypePolicy = findPortTypePolicy(binding, operation);
295         if (portTypePolicy != null) {
296             policies.add(portTypePolicy);
297         }
298 
299         if (policies.isEmpty()) {
300             return new Policy();
301         }
302 
303         Policy mergedPolicy = policies.get(0);
304         for (int i = 1; i < policies.size(); i++) {
305             Policy policy = policies.get(i);
306             mergedPolicy = mergedPolicy.merge(policy);
307         }
308         return mergedPolicy;
309     }
310 
311     private Policy findPortTypePolicy(Binding binding, Operation operation) throws WSSPolicyException {
312 
313         List<Policy> policies = new ArrayList<>();
314 
315         PortType portType = binding.getPortType();
316         Policy portTypePolicy = findPolicies(portType);
317         if (portTypePolicy != null) {
318             policies.add(portTypePolicy);
319         }
320 
321         @SuppressWarnings("unchecked")
322         List<Operation> operations = portType.getOperations();
323         for (int i = 0; i < operations.size(); i++) {
324             Operation portTypeOperation = operations.get(i);
325             if (portTypeOperation.getName().equals(operation.getName())) {
326                 Policy operationPolicy = findPolicies(portTypeOperation);
327                 if (operationPolicy != null) {
328                     policies.add(operationPolicy);
329                 }
330 
331                 Policy inputPolicy = findPolicies(portTypeOperation.getInput());
332                 if (inputPolicy != null) {
333                     policies.add(inputPolicy);
334                 }
335 
336                 Policy messagePolicy = findPolicies(portTypeOperation.getInput().getMessage());
337                 if (messagePolicy != null) {
338                     policies.add(messagePolicy);
339                 }
340             }
341         }
342 
343         if (policies.isEmpty()) {
344             return new Policy();
345         }
346 
347         Policy mergedPolicy = policies.get(0);
348         for (int i = 1; i < policies.size(); i++) {
349             Policy policy = policies.get(i);
350             mergedPolicy = mergedPolicy.merge(policy);
351         }
352         return mergedPolicy;
353     }
354 
355     private Policy findPolicies(WSDLElement wsdlElement) throws WSSPolicyException {
356         if (wsdlElement == null) {
357             return new Policy();
358         }
359 
360         List<Policy> policies = new ArrayList<>();
361 
362         @SuppressWarnings("unchecked")
363         List<ExtensibilityElement> extensibilityElements = wsdlElement.getExtensibilityElements();
364         for (int i = 0; i < extensibilityElements.size(); i++) {
365             ExtensibilityElement extensibilityElement = extensibilityElements.get(i);
366             if (extensibilityElement instanceof UnknownExtensibilityElement) {
367                 UnknownExtensibilityElement unknownExtensibilityElement =
368                     (UnknownExtensibilityElement) extensibilityElement;
369                 if (unknownExtensibilityElement.getElementType().getLocalPart().equals("PolicyReference")) {
370                     String uri = unknownExtensibilityElement.getElement().getAttributeNS(null, "URI").substring(1);
371                     NodeList policyNodeList =
372                         unknownExtensibilityElement.getElement().getOwnerDocument().getElementsByTagNameNS("*",
373                                                                                                            "Policy");
374 
375                     boolean found = false;
376                     for (int j = 0; j < policyNodeList.getLength(); j++) {
377                         Element element = (Element) policyNodeList.item(j);
378                         String refUri = element.getAttributeNS(WSSConstants.NS_WSU10, "Id");
379                         if (refUri != null && refUri.equals(uri)) {
380                             found = true;
381                             Policy policy = parsePolicy(element);
382                             policies.add(policy);
383                             break;
384                         }
385                     }
386                     if (!found) {
387                         throw new WSSPolicyException("Referenced Policy not found " + uri);
388                     }
389                 } else if (unknownExtensibilityElement.getElementType().getLocalPart().equals("Policy")) {
390                     Element element = unknownExtensibilityElement.getElement();
391                     Policy policy = parsePolicy(element);
392                     policies.add(policy);
393                 }
394             }
395         }
396 
397         if (policies.isEmpty()) {
398             return new Policy();
399         }
400 
401         Policy mergedPolicy = policies.get(0);
402         for (int i = 1; i < policies.size(); i++) {
403             Policy policy = policies.get(i);
404             mergedPolicy = mergedPolicy.merge(policy);
405         }
406         return mergedPolicy;
407     }
408 
409     private Policy parsePolicy(Element element) throws WSSPolicyException {
410         if (elementPolicyCache.containsKey(element)) {
411             return elementPolicyCache.get(element);
412         }
413         PolicyBuilder policyBuilder = new PolicyBuilder();
414         registerDefaultBuilders(policyBuilder.getAssertionBuilderFactory());
415         Policy policy = policyBuilder.getPolicy(element);
416         elementPolicyCache.put(element, policy);
417         return policy;
418     }
419 
420     private void registerDefaultBuilders(AssertionBuilderFactory assertionBuilderFactory) {
421         for (int i = 0; i < assertionBuilders.size(); i++) {
422             AssertionBuilder<Element> assertionBuilder = assertionBuilders.get(i);
423             assertionBuilderFactory.registerBuilder(assertionBuilder);
424         }
425     }
426 
427     /**
428      * creates a new PolicyEnforcer instance
429      * @param soapAction The requested soapAction of the actual request
430      * @param initiator Boolean flag to tell the engine if it is running in client or server mode
431      * @param roleOrActor The actor or role of the security processing. Must be set to the same value
432      * as WSSSecurityProperties#setActor()
433      * @param attachmentCount The number of Attachments received in the message
434      * @param soap12 Whether we are using SOAP 1.2 or not
435      * @return the newly created PolicyEnforcer instance
436      * @throws WSSPolicyException
437      */
438     public PolicyEnforcer newPolicyEnforcer(String soapAction, boolean initiator,
439                                             String roleOrActor, int attachmentCount,
440                                             boolean soap12) throws WSSPolicyException {
441         return new PolicyEnforcer(this.operationPolicies, soapAction, initiator, roleOrActor, attachmentCount, null, soap12);
442     }
443 }