blob: 6402ca67ec2f46d035f3638c8ad045ef5d2ec33e [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.wss4j.policy.stax.enforcer;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.wsdl.Binding;
import javax.wsdl.BindingOperation;
import javax.wsdl.Definition;
import javax.wsdl.Operation;
import javax.wsdl.Port;
import javax.wsdl.PortType;
import javax.wsdl.Service;
import javax.wsdl.WSDLElement;
import javax.wsdl.WSDLException;
import javax.wsdl.extensions.ExtensibilityElement;
import javax.wsdl.extensions.UnknownExtensibilityElement;
import javax.wsdl.extensions.soap.SOAPOperation;
import javax.wsdl.extensions.soap12.SOAP12Operation;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.xml.namespace.QName;
import org.apache.neethi.AssertionBuilderFactory;
import org.apache.neethi.Policy;
import org.apache.neethi.PolicyBuilder;
import org.apache.neethi.builders.AssertionBuilder;
import org.apache.wss4j.common.WSSPolicyException;
import org.apache.wss4j.policy.builders.AlgorithmSuiteBuilder;
import org.apache.wss4j.policy.builders.AsymmetricBindingBuilder;
import org.apache.wss4j.policy.builders.BootstrapPolicyBuilder;
import org.apache.wss4j.policy.builders.ContentEncryptedElementsBuilder;
import org.apache.wss4j.policy.builders.EncryptedElementsBuilder;
import org.apache.wss4j.policy.builders.EncryptedPartsBuilder;
import org.apache.wss4j.policy.builders.EncryptionTokenBuilder;
import org.apache.wss4j.policy.builders.HttpsTokenBuilder;
import org.apache.wss4j.policy.builders.InitiatorEncryptionTokenBuilder;
import org.apache.wss4j.policy.builders.InitiatorSignatureTokenBuilder;
import org.apache.wss4j.policy.builders.InitiatorTokenBuilder;
import org.apache.wss4j.policy.builders.IssuedTokenBuilder;
import org.apache.wss4j.policy.builders.KerberosTokenBuilder;
import org.apache.wss4j.policy.builders.KeyValueTokenBuilder;
import org.apache.wss4j.policy.builders.LayoutBuilder;
import org.apache.wss4j.policy.builders.ProtectionTokenBuilder;
import org.apache.wss4j.policy.builders.RecipientEncryptionTokenBuilder;
import org.apache.wss4j.policy.builders.RecipientSignatureTokenBuilder;
import org.apache.wss4j.policy.builders.RecipientTokenBuilder;
import org.apache.wss4j.policy.builders.RelTokenBuilder;
import org.apache.wss4j.policy.builders.RequiredElementsBuilder;
import org.apache.wss4j.policy.builders.RequiredPartsBuilder;
import org.apache.wss4j.policy.builders.SamlTokenBuilder;
import org.apache.wss4j.policy.builders.SecureConversationTokenBuilder;
import org.apache.wss4j.policy.builders.SecurityContextTokenBuilder;
import org.apache.wss4j.policy.builders.SignatureTokenBuilder;
import org.apache.wss4j.policy.builders.SignedElementsBuilder;
import org.apache.wss4j.policy.builders.SignedPartsBuilder;
import org.apache.wss4j.policy.builders.SpnegoContextTokenBuilder;
import org.apache.wss4j.policy.builders.SupportingTokensBuilder;
import org.apache.wss4j.policy.builders.SymmetricBindingBuilder;
import org.apache.wss4j.policy.builders.TransportBindingBuilder;
import org.apache.wss4j.policy.builders.TransportTokenBuilder;
import org.apache.wss4j.policy.builders.Trust10Builder;
import org.apache.wss4j.policy.builders.Trust13Builder;
import org.apache.wss4j.policy.builders.UsernameTokenBuilder;
import org.apache.wss4j.policy.builders.WSS10Builder;
import org.apache.wss4j.policy.builders.WSS11Builder;
import org.apache.wss4j.policy.builders.X509TokenBuilder;
import org.apache.wss4j.policy.stax.OperationPolicy;
import org.apache.wss4j.stax.ext.WSSConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* PolicyEnforcerFactory builds a map of all the possible effective Policies
* and caches them for reuse
*/
public class PolicyEnforcerFactory {
protected static final org.slf4j.Logger LOG =
org.slf4j.LoggerFactory.getLogger(PolicyEnforcerFactory.class);
private final List<AssertionBuilder<Element>> assertionBuilders;
private Definition wsdlDefinition;
private List<OperationPolicy> operationPolicies;
private final Map<Element, Policy> elementPolicyCache;
protected PolicyEnforcerFactory(List<AssertionBuilder<Element>> customAssertionBuilders) {
elementPolicyCache = new HashMap<>();
assertionBuilders = new ArrayList<>();
assertionBuilders.add(new AlgorithmSuiteBuilder());
assertionBuilders.add(new AsymmetricBindingBuilder());
assertionBuilders.add(new ContentEncryptedElementsBuilder());
assertionBuilders.add(new EncryptedElementsBuilder());
assertionBuilders.add(new EncryptedPartsBuilder());
assertionBuilders.add(new EncryptionTokenBuilder());
assertionBuilders.add(new HttpsTokenBuilder());
assertionBuilders.add(new InitiatorEncryptionTokenBuilder());
assertionBuilders.add(new InitiatorSignatureTokenBuilder());
assertionBuilders.add(new InitiatorTokenBuilder());
assertionBuilders.add(new IssuedTokenBuilder());
assertionBuilders.add(new KerberosTokenBuilder());
assertionBuilders.add(new KeyValueTokenBuilder());
assertionBuilders.add(new LayoutBuilder());
assertionBuilders.add(new ProtectionTokenBuilder());
assertionBuilders.add(new RecipientEncryptionTokenBuilder());
assertionBuilders.add(new RecipientSignatureTokenBuilder());
assertionBuilders.add(new RecipientTokenBuilder());
assertionBuilders.add(new RelTokenBuilder());
assertionBuilders.add(new RequiredElementsBuilder());
assertionBuilders.add(new RequiredPartsBuilder());
assertionBuilders.add(new SamlTokenBuilder());
assertionBuilders.add(new SecureConversationTokenBuilder());
assertionBuilders.add(new BootstrapPolicyBuilder());
assertionBuilders.add(new SecurityContextTokenBuilder());
assertionBuilders.add(new SignatureTokenBuilder());
assertionBuilders.add(new SignedElementsBuilder());
assertionBuilders.add(new SignedPartsBuilder());
assertionBuilders.add(new SpnegoContextTokenBuilder());
assertionBuilders.add(new SupportingTokensBuilder());
assertionBuilders.add(new SymmetricBindingBuilder());
assertionBuilders.add(new TransportBindingBuilder());
assertionBuilders.add(new TransportTokenBuilder());
assertionBuilders.add(new Trust10Builder());
assertionBuilders.add(new Trust13Builder());
assertionBuilders.add(new UsernameTokenBuilder());
assertionBuilders.add(new WSS10Builder());
assertionBuilders.add(new WSS11Builder());
assertionBuilders.add(new X509TokenBuilder());
if (customAssertionBuilders != null) {
for (int i = 0; i < customAssertionBuilders.size(); i++) {
AssertionBuilder<Element> customAssertionBuilder = customAssertionBuilders.get(i);
assertionBuilders.add(customAssertionBuilder);
}
}
}
public static PolicyEnforcerFactory newInstance(URL wsdlUrl) throws WSSPolicyException {
return newInstance(wsdlUrl, null);
}
public static PolicyEnforcerFactory newInstance(URL wsdlUrl,
List<AssertionBuilder<Element>> customAssertionBuilders)
throws WSSPolicyException {
PolicyEnforcerFactory policyEnforcerFactory = new PolicyEnforcerFactory(customAssertionBuilders);
policyEnforcerFactory.parseWsdl(wsdlUrl);
return policyEnforcerFactory;
}
public static PolicyEnforcerFactory newInstance(Document document) throws WSSPolicyException {
return newInstance(document, null);
}
public static PolicyEnforcerFactory newInstance(Document document,
List<AssertionBuilder<Element>> customAssertionBuilders)
throws WSSPolicyException {
PolicyEnforcerFactory policyEnforcerFactory = new PolicyEnforcerFactory(customAssertionBuilders);
policyEnforcerFactory.parseWsdl(document);
return policyEnforcerFactory;
}
//todo enforce uniqueness of operation names to prevent SOAPAction spoofing.
private void parseWsdl(URL wsdlUrl) throws WSSPolicyException {
try {
WSDLFactory wsdlFactory = WSDLFactory.newInstance();
WSDLReader reader = wsdlFactory.newWSDLReader();
reader.setFeature("javax.wsdl.verbose", false);
wsdlDefinition = reader.readWSDL(wsdlUrl.toString());
operationPolicies = findPoliciesByOperation(wsdlDefinition);
} catch (WSDLException e) {
throw new WSSPolicyException(e.getMessage(), e);
}
}
//todo enforce uniqueness of operation names to prevent SOAPAction spoofing.
private void parseWsdl(Document document) throws WSSPolicyException {
try {
WSDLFactory wsdlFactory = WSDLFactory.newInstance();
WSDLReader reader = wsdlFactory.newWSDLReader();
reader.setFeature("javax.wsdl.verbose", false);
wsdlDefinition = reader.readWSDL(document.getDocumentURI(), document);
operationPolicies = findPoliciesByOperation(wsdlDefinition);
} catch (WSDLException e) {
throw new WSSPolicyException(e.getMessage(), e);
}
}
private List<OperationPolicy> findPoliciesByOperation(Definition wsdlDefinition) throws WSSPolicyException {
List<OperationPolicy> operationPolicyList = new ArrayList<>();
@SuppressWarnings({"unchecked", "rawtypes"})
Iterator<Map.Entry> services = wsdlDefinition.getAllServices().entrySet().iterator();
while (services.hasNext()) {
@SuppressWarnings("unchecked")
Map.Entry<QName, Service> serviceEntry = services.next();
Service service = serviceEntry.getValue();
@SuppressWarnings({"unchecked", "rawtypes"})
Iterator<Map.Entry> ports = service.getPorts().entrySet().iterator();
while (ports.hasNext()) {
@SuppressWarnings("unchecked")
Map.Entry<QName, Port> portEntry = ports.next();
Port port = portEntry.getValue();
Binding binding = port.getBinding();
@SuppressWarnings("unchecked")
List<BindingOperation> bindingOperations = binding.getBindingOperations();
for (int i = 0; i < bindingOperations.size(); i++) {
BindingOperation bindingOperation = bindingOperations.get(i);
Operation operation = bindingOperation.getOperation();
OperationPolicy operationPolicy =
new OperationPolicy(new QName(null, operation.getName()));
operationPolicyList.add(operationPolicy);
@SuppressWarnings("unchecked")
List<ExtensibilityElement> extensibilityElements = bindingOperation.getExtensibilityElements();
for (int j = 0; j < extensibilityElements.size(); j++) {
ExtensibilityElement extensibilityElement = extensibilityElements.get(j);
if (extensibilityElement instanceof SOAPOperation) {
SOAPOperation soapOperation = (SOAPOperation) extensibilityElement;
String soapActionUri = soapOperation.getSoapActionURI();
operationPolicy.setOperationAction(soapActionUri);
operationPolicy.setSoapMessageVersionNamespace(WSSConstants.NS_SOAP11);
} else if (extensibilityElement instanceof SOAP12Operation) {
SOAP12Operation soap12Operation = (SOAP12Operation) extensibilityElement;
String soapActionUri = soap12Operation.getSoapActionURI();
operationPolicy.setOperationAction(soapActionUri);
operationPolicy.setSoapMessageVersionNamespace(WSSConstants.NS_SOAP12);
}
}
Policy policy = getPolicy(service, port, binding, bindingOperation, operation);
operationPolicy.setPolicy(policy.normalize(true));
}
}
}
return operationPolicyList;
}
private Policy getPolicy(Service service, Port port, Binding binding,
BindingOperation bindingOperation, Operation operation) throws WSSPolicyException {
List<Policy> policies = new ArrayList<>();
Policy servicePolicy = findPolicies(service);
if (servicePolicy != null) {
policies.add(servicePolicy);
}
Policy portPolicy = findPolicies(port);
if (portPolicy != null) {
policies.add(portPolicy);
}
Policy bindingPolicy = findPolicies(binding);
if (bindingPolicy != null) {
policies.add(bindingPolicy);
}
Policy bindingOperationPolicy = findPolicies(bindingOperation);
if (bindingOperationPolicy != null) {
policies.add(bindingOperationPolicy);
}
Policy bindingOperationInputPolicy = findPolicies(bindingOperation.getBindingInput());
if (bindingOperationInputPolicy != null) {
policies.add(bindingOperationInputPolicy);
}
Policy portTypePolicy = findPortTypePolicy(binding, operation);
if (portTypePolicy != null) {
policies.add(portTypePolicy);
}
if (policies.isEmpty()) {
return new Policy();
}
Policy mergedPolicy = policies.get(0);
for (int i = 1; i < policies.size(); i++) {
Policy policy = policies.get(i);
mergedPolicy = mergedPolicy.merge(policy);
}
return mergedPolicy;
}
private Policy findPortTypePolicy(Binding binding, Operation operation) throws WSSPolicyException {
List<Policy> policies = new ArrayList<>();
PortType portType = binding.getPortType();
Policy portTypePolicy = findPolicies(portType);
if (portTypePolicy != null) {
policies.add(portTypePolicy);
}
@SuppressWarnings("unchecked")
List<Operation> operations = portType.getOperations();
for (int i = 0; i < operations.size(); i++) {
Operation portTypeOperation = operations.get(i);
if (portTypeOperation.getName().equals(operation.getName())) {
Policy operationPolicy = findPolicies(portTypeOperation);
if (operationPolicy != null) {
policies.add(operationPolicy);
}
Policy inputPolicy = findPolicies(portTypeOperation.getInput());
if (inputPolicy != null) {
policies.add(inputPolicy);
}
Policy messagePolicy = findPolicies(portTypeOperation.getInput().getMessage());
if (messagePolicy != null) {
policies.add(messagePolicy);
}
}
}
if (policies.isEmpty()) {
return new Policy();
}
Policy mergedPolicy = policies.get(0);
for (int i = 1; i < policies.size(); i++) {
Policy policy = policies.get(i);
mergedPolicy = mergedPolicy.merge(policy);
}
return mergedPolicy;
}
private Policy findPolicies(WSDLElement wsdlElement) throws WSSPolicyException {
if (wsdlElement == null) {
return new Policy();
}
List<Policy> policies = new ArrayList<>();
@SuppressWarnings("unchecked")
List<ExtensibilityElement> extensibilityElements = wsdlElement.getExtensibilityElements();
for (int i = 0; i < extensibilityElements.size(); i++) {
ExtensibilityElement extensibilityElement = extensibilityElements.get(i);
if (extensibilityElement instanceof UnknownExtensibilityElement) {
UnknownExtensibilityElement unknownExtensibilityElement =
(UnknownExtensibilityElement) extensibilityElement;
if (unknownExtensibilityElement.getElementType().getLocalPart().equals("PolicyReference")) {
String uri = unknownExtensibilityElement.getElement().getAttributeNS(null, "URI").substring(1);
NodeList policyNodeList =
unknownExtensibilityElement.getElement().getOwnerDocument().getElementsByTagNameNS("*",
"Policy");
boolean found = false;
for (int j = 0; j < policyNodeList.getLength(); j++) {
Element element = (Element) policyNodeList.item(j);
String refUri = element.getAttributeNS(WSSConstants.NS_WSU10, "Id");
if (refUri != null && refUri.equals(uri)) {
found = true;
Policy policy = parsePolicy(element);
policies.add(policy);
break;
}
}
if (!found) {
throw new WSSPolicyException("Referenced Policy not found " + uri);
}
} else if (unknownExtensibilityElement.getElementType().getLocalPart().equals("Policy")) {
Element element = unknownExtensibilityElement.getElement();
Policy policy = parsePolicy(element);
policies.add(policy);
}
}
}
if (policies.isEmpty()) {
return new Policy();
}
Policy mergedPolicy = policies.get(0);
for (int i = 1; i < policies.size(); i++) {
Policy policy = policies.get(i);
mergedPolicy = mergedPolicy.merge(policy);
}
return mergedPolicy;
}
private Policy parsePolicy(Element element) throws WSSPolicyException {
if (elementPolicyCache.containsKey(element)) {
return elementPolicyCache.get(element);
}
PolicyBuilder policyBuilder = new PolicyBuilder();
registerDefaultBuilders(policyBuilder.getAssertionBuilderFactory());
Policy policy = policyBuilder.getPolicy(element);
elementPolicyCache.put(element, policy);
return policy;
}
private void registerDefaultBuilders(AssertionBuilderFactory assertionBuilderFactory) {
for (int i = 0; i < assertionBuilders.size(); i++) {
AssertionBuilder<Element> assertionBuilder = assertionBuilders.get(i);
assertionBuilderFactory.registerBuilder(assertionBuilder);
}
}
/**
* creates a new PolicyEnforcer instance
* @param soapAction The requested soapAction of the actual request
* @param initiator Boolean flag to tell the engine if it is running in client or server mode
* @param roleOrActor The actor or role of the security processing. Must be set to the same value
* as WSSSecurityProperties#setActor()
* @param attachmentCount The number of Attachments received in the message
* @param soap12 Whether we are using SOAP 1.2 or not
* @return the newly created PolicyEnforcer instance
* @throws WSSPolicyException
*/
public PolicyEnforcer newPolicyEnforcer(String soapAction, boolean initiator,
String roleOrActor, int attachmentCount,
boolean soap12) throws WSSPolicyException {
return new PolicyEnforcer(this.operationPolicies, soapAction, initiator, roleOrActor, attachmentCount, null, soap12);
}
}