/**
* 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.coheigea.cxf.sts.xacml.authorization.xacml3;
import java.security.Principal;
import java.util.List;
import javax.xml.namespace.QName;
import org.apache.cxf.message.Message;
import org.apache.cxf.rt.security.saml.xacml.CXFMessageParser;
import org.apache.cxf.rt.security.saml.xacml.XACMLConstants;
import org.apache.openaz.xacml.api.Request;
import org.apache.openaz.xacml.api.RequestAttributes;
import org.apache.openaz.xacml.std.IdentifierImpl;
import org.apache.openaz.xacml.std.StdAttributeValue;
import org.apache.openaz.xacml.std.StdMutableAttribute;
import org.apache.openaz.xacml.std.StdMutableRequest;
import org.apache.openaz.xacml.std.StdMutableRequestAttributes;
import org.joda.time.DateTime;
/**
* This class constructs an XACML 3.0 Request given a Principal, list of roles and MessageContext,
* following the SAML 2.0 profile of XACML 3.0. The principal name is inserted as the Subject ID,
* and the list of roles associated with that principal are inserted as Subject roles. The action
* to send defaults to "execute".
*
* For a SOAP Service, the resource-id Attribute refers to the
* "{serviceNamespace}serviceName#{operationNamespace}operationName" String (shortened to
* "{serviceNamespace}serviceName#operationName" if the namespaces are identical). The
* "{serviceNamespace}serviceName", "{operationNamespace}operationName" and resource URI are also
* sent to simplify processing at the PDP side.
*
* For a REST service the request URL is the resource. You can also configure the ability to
* send the truncated request URI instead for a SOAP or REST service. The current DateTime is
* also sent in an Environment, however this can be disabled via configuration.
*/
public class DefaultXACML3RequestBuilder implements XACML3RequestBuilder {
private boolean sendDateTime = true;
private String action = "execute";
private boolean sendFullRequestURL = true;
/**
* Create an XACML Request given a Principal, list of roles and Message.
*/
public Request createRequest(Principal principal, List<String> roles, Message message)
throws Exception {
CXFMessageParser messageParser = new CXFMessageParser(message);
String issuer = messageParser.getIssuer();
String actionToUse = messageParser.getAction(action);
RequestAttributes subject = createSubject(principal, roles, issuer);
RequestAttributes resource = createResource(messageParser);
RequestAttributes action = createAction(actionToUse);
RequestAttributes environment = createEnvironment();
StdMutableRequest request = new StdMutableRequest();
request.add(subject);
request.add(resource);
request.add(action);
request.add(environment);
return request;
}
private RequestAttributes createResource(CXFMessageParser messageParser) {
StdMutableRequestAttributes resourceAttributes = new StdMutableRequestAttributes();
resourceAttributes.setCategory(new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource"));
// Resource-id
String resourceId = null;
boolean isSoapService = messageParser.isSOAPService();
if (isSoapService) {
QName serviceName = messageParser.getWSDLService();
QName operationName = messageParser.getWSDLOperation();
if (serviceName != null) {
resourceId = serviceName.toString() + "#";
if (serviceName.getNamespaceURI() != null
&& serviceName.getNamespaceURI().equals(operationName.getNamespaceURI())) {
resourceId += operationName.getLocalPart();
} else {
resourceId += operationName.toString();
}
} else {
resourceId = operationName.toString();
}
} else {
resourceId = messageParser.getResourceURI(sendFullRequestURL);
}
StdMutableAttribute resourceAttribute = new StdMutableAttribute();
resourceAttribute.setCategory(new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource"));
resourceAttribute.setAttributeId(new IdentifierImpl(XACMLConstants.RESOURCE_ID));
StdAttributeValue<String> resourceAttributeValue =
new StdAttributeValue<String>(new IdentifierImpl(XACMLConstants.XS_STRING), resourceId);
resourceAttribute.addValue(resourceAttributeValue);
resourceAttributes.add(resourceAttribute);
if (isSoapService) {
// WSDL Service
QName wsdlService = messageParser.getWSDLService();
if (wsdlService != null) {
StdMutableAttribute wsdlServiceAttribute = new StdMutableAttribute();
wsdlServiceAttribute.setCategory(new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource"));
wsdlServiceAttribute.setAttributeId(new IdentifierImpl(XACMLConstants.RESOURCE_WSDL_SERVICE_ID));
StdAttributeValue<String> wsdlServiceAttributeValue =
new StdAttributeValue<String>(new IdentifierImpl(XACMLConstants.XS_STRING), wsdlService.toString());
wsdlServiceAttribute.addValue(wsdlServiceAttributeValue);
resourceAttributes.add(wsdlServiceAttribute);
}
// WSDL Operation
QName wsdlOperation = messageParser.getWSDLOperation();
StdMutableAttribute wsdlOperationAttribute = new StdMutableAttribute();
wsdlOperationAttribute.setCategory(new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource"));
wsdlOperationAttribute.setAttributeId(new IdentifierImpl(XACMLConstants.RESOURCE_WSDL_OPERATION_ID));
StdAttributeValue<String> wsdlOperationAttributeValue =
new StdAttributeValue<String>(new IdentifierImpl(XACMLConstants.XS_STRING), wsdlOperation.toString());
wsdlOperationAttribute.addValue(wsdlOperationAttributeValue);
resourceAttributes.add(wsdlOperationAttribute);
// WSDL Endpoint
String endpointURI = messageParser.getResourceURI(sendFullRequestURL);
StdMutableAttribute wsdlEndpointAttribute = new StdMutableAttribute();
wsdlEndpointAttribute.setCategory(new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:resource"));
wsdlEndpointAttribute.setAttributeId(new IdentifierImpl(XACMLConstants.RESOURCE_WSDL_ENDPOINT));
StdAttributeValue<String> wsdlEndpointAttributeValue =
new StdAttributeValue<String>(new IdentifierImpl(XACMLConstants.XS_STRING), endpointURI);
wsdlEndpointAttribute.addValue(wsdlEndpointAttributeValue);
resourceAttributes.add(wsdlEndpointAttribute);
}
return resourceAttributes;
}
private RequestAttributes createEnvironment() {
if (sendDateTime) {
StdMutableRequestAttributes environmentAttributes = new StdMutableRequestAttributes();
environmentAttributes.setCategory(new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:environment"));
StdMutableAttribute environmentAttribute = new StdMutableAttribute();
environmentAttribute.setAttributeId(new IdentifierImpl(XACMLConstants.CURRENT_DATETIME));
StdAttributeValue<String> environmentAttributeValue =
new StdAttributeValue<String>(new IdentifierImpl(XACMLConstants.XS_DATETIME), new DateTime().toString());
environmentAttribute.addValue(environmentAttributeValue);
environmentAttributes.add(environmentAttribute);
return environmentAttributes;
}
return null;
}
private RequestAttributes createSubject(Principal principal, List<String> roles, String issuer) {
// Add Subject
StdMutableRequestAttributes subjectRequestAttributes = new StdMutableRequestAttributes();
subjectRequestAttributes.setCategory(new IdentifierImpl("urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"));
// Subject Id
StdMutableAttribute subjectIdAttribute = new StdMutableAttribute();
subjectIdAttribute.setCategory(new IdentifierImpl("urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"));
subjectIdAttribute.setAttributeId(new IdentifierImpl(XACMLConstants.SUBJECT_ID));
StdAttributeValue<String> subjectIdAttributeValue =
new StdAttributeValue<String>(new IdentifierImpl(XACMLConstants.XS_STRING), principal.getName());
subjectIdAttribute.setIssuer(issuer);
subjectIdAttribute.addValue(subjectIdAttributeValue);
subjectRequestAttributes.add(subjectIdAttribute);
// Subject role
if (roles != null) {
StdMutableAttribute subjectRoleAttribute = new StdMutableAttribute();
subjectRoleAttribute.setCategory(new IdentifierImpl("urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"));
subjectRoleAttribute.setAttributeId(new IdentifierImpl(XACMLConstants.SUBJECT_ROLE));
subjectRoleAttribute.setIssuer(issuer);
for (String role : roles) {
StdAttributeValue<String> subjectRoleAttributeValue =
new StdAttributeValue<String>(new IdentifierImpl(XACMLConstants.XS_ANY_URI), role);
subjectRoleAttribute.addValue(subjectRoleAttributeValue);
}
subjectRequestAttributes.add(subjectRoleAttribute);
}
return subjectRequestAttributes;
}
private RequestAttributes createAction(String actionToUse) {
StdMutableRequestAttributes actionAttributes = new StdMutableRequestAttributes();
actionAttributes.setCategory(new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:action"));
StdMutableAttribute actionAttribute = new StdMutableAttribute();
actionAttribute.setCategory(new IdentifierImpl("urn:oasis:names:tc:xacml:3.0:attribute-category:action"));
actionAttribute.setAttributeId(new IdentifierImpl(XACMLConstants.ACTION_ID));
StdAttributeValue<String> actionAttributeValue =
new StdAttributeValue<String>(new IdentifierImpl(XACMLConstants.XS_STRING), actionToUse);
actionAttribute.addValue(actionAttributeValue);
actionAttributes.add(actionAttribute);
return actionAttributes;
}
/**
* Set a new Action String to use
*/
public void setAction(String action) {
this.action = action;
}
public void setSendDateTime(boolean sendDateTime) {
this.sendDateTime = sendDateTime;
}
/**
* Whether to send the full Request URL as the resource or not. If set to true,
* the full Request URL will be sent for both a JAX-WS and JAX-RS service. If set
* to false (the default), a JAX-WS service will send the "{namespace}operation" QName,
* and a JAX-RS service will send the RequestURI (i.e. minus the initial https:<ip> prefix).
*/
public void setSendFullRequestURL(boolean sendFullRequestURL) {
this.sendFullRequestURL = sendFullRequestURL;
}
}