Omaha #3509 Aded support for custom XACML policies
Change-Id: I37c0aac34cbcc30be2a48876cef27cdf97c35a33 Former-commit-id:5b6104a8ad
[formerlyb68b812dbc
] [formerly1410dc479e
] [formerly5b6104a8ad
[formerlyb68b812dbc
] [formerly1410dc479e
] [formerlye9c310b4d8
[formerly1410dc479e
[formerly 1b1cd7789f835fd73dbc0d939df03f6417600154]]]] Former-commit-id:e9c310b4d8
Former-commit-id:8414c8f4f4
[formerly4d0be5a4a7
] [formerly 69004a1babf3d4a301c432798ba3167ccc2b6016 [formerly26c6571bc3
]] Former-commit-id: 4c6653e1ca6eec9fe33324068d274e49379e1d94 [formerly3c49e1c336
] Former-commit-id:124f7429ad
This commit is contained in:
parent
78f80b3057
commit
2f5b754076
5 changed files with 651 additions and 130 deletions
|
@ -36,7 +36,8 @@ Require-Bundle: com.raytheon.uf.common.registry.schemas.ebxml;bundle-version="1.
|
|||
org.eclipse.jetty;bundle-version="7.6.14",
|
||||
com.raytheon.uf.edex.security;bundle-version="1.14.0",
|
||||
org.opensaml;bundle-version="1.0.0",
|
||||
com.raytheon.uf.common.security;bundle-version="1.14.0"
|
||||
com.raytheon.uf.common.security;bundle-version="1.14.0",
|
||||
org.joda.time;bundle-version="1.6.2"
|
||||
Export-Package: com.raytheon.uf.edex.registry.ebxml,
|
||||
com.raytheon.uf.edex.registry.ebxml.acp,
|
||||
com.raytheon.uf.edex.registry.ebxml.dao,
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
|
||||
|
||||
<bean id="xacmlInterceptor" class="com.raytheon.uf.edex.registry.acp.xacml.XACMLInterceptor">
|
||||
<bean id="xacmlInterceptor" class="com.raytheon.uf.edex.registry.acp.xacml.interceptor.XACMLInterceptor">
|
||||
<constructor-arg ref="XACMLPolicyAdministrator"/>
|
||||
<constructor-arg ref="XACMLPolicyDecisionPoint"/>
|
||||
<constructor-arg ref="registryObjectDao"/>
|
||||
</bean>
|
||||
|
||||
<bean id="XACMLPolicyDecisionPoint" class="com.raytheon.uf.edex.registry.acp.xacml.XACMLPolicyDecisionPoint"/>
|
||||
|
|
|
@ -1,128 +0,0 @@
|
|||
package com.raytheon.uf.edex.registry.acp.xacml;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.security.Principal;
|
||||
|
||||
import oasis.names.tc.ebxml.regrep.wsdl.registry.services.v4.MsgRegistryException;
|
||||
|
||||
import org.apache.cxf.message.Message;
|
||||
import org.apache.cxf.rt.security.xacml.AbstractXACMLAuthorizingInterceptor;
|
||||
import org.opensaml.xacml.ctx.RequestType;
|
||||
import org.opensaml.xacml.ctx.ResponseType;
|
||||
import org.opensaml.xacml.ctx.ResultType;
|
||||
import org.opensaml.xacml.policy.ObligationType;
|
||||
import org.opensaml.xacml.policy.ObligationsType;
|
||||
import org.opensaml.xacml.policy.PolicySetType;
|
||||
import org.opensaml.xml.XMLObject;
|
||||
import org.opensaml.xml.io.Marshaller;
|
||||
import org.opensaml.xml.io.MarshallerFactory;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
|
||||
import org.w3c.dom.ls.DOMImplementationLS;
|
||||
import org.w3c.dom.ls.LSOutput;
|
||||
import org.w3c.dom.ls.LSSerializer;
|
||||
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.common.status.UFStatus.Priority;
|
||||
import com.raytheon.uf.edex.registry.acp.xacml.engine.obligation.XACMLObligationEvaluator;
|
||||
import com.raytheon.uf.edex.registry.acp.xacml.exception.XACMLException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Policy enforcement point (PEP) - The system entity that performs access
|
||||
* control, by making decision requests and enforcing authorization decisions.
|
||||
* This term is defined in a joint effort by the IETF Policy Framework Working
|
||||
* Group and the Distributed Management Task Force (DMTF)/Common Information
|
||||
* Model (CIM) in [RFC3198]. This term corresponds to "Access Enforcement
|
||||
* Function" (AEF) in [ISO10181-3].
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* 7/09/2014 724 bphillip Initial Coding
|
||||
* </pre>
|
||||
*
|
||||
* @author bphillip
|
||||
* @version 1
|
||||
*/
|
||||
public class XACMLInterceptor extends AbstractXACMLAuthorizingInterceptor {
|
||||
|
||||
/** The logger */
|
||||
private static final IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(XACMLInterceptor.class);
|
||||
|
||||
private XACMLPolicyAdministrator xacmlPolicyAdmin;
|
||||
|
||||
private XACMLPolicyDecisionPoint pdp;
|
||||
|
||||
public XACMLInterceptor(XACMLPolicyAdministrator xacmlPolicyAdmin,
|
||||
XACMLPolicyDecisionPoint pdp) throws MsgRegistryException {
|
||||
this.xacmlPolicyAdmin = xacmlPolicyAdmin;
|
||||
this.pdp = pdp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseType performRequest(RequestType request, Message message)
|
||||
throws Exception {
|
||||
|
||||
if(statusHandler.isPriorityEnabled(Priority.DEBUG)){
|
||||
statusHandler.debug(outputRequest(request));
|
||||
}
|
||||
PolicySetType defaultPolicy = xacmlPolicyAdmin
|
||||
.getPolicySet("urn:oasis:names:tc:xacml:2.0:data-delivery:default-policySet");
|
||||
ResponseType response = pdp.evaluate(defaultPolicy, request);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle any Obligations returned by the PDP
|
||||
*
|
||||
* @throws XACMLException
|
||||
*/
|
||||
protected void handleObligations(RequestType request, Principal principal,
|
||||
Message message, ResultType result) throws XACMLException {
|
||||
ObligationsType obligationObject = result.getObligations();
|
||||
if (obligationObject != null
|
||||
&& !obligationObject.getObligations().isEmpty()) {
|
||||
statusHandler.info("Evaluating "
|
||||
+ obligationObject.getObligations().size()
|
||||
+ " obligations!");
|
||||
for (ObligationType obligation : result.getObligations()
|
||||
.getObligations()) {
|
||||
XACMLObligationEvaluator.getInstance().evaluate(obligation,
|
||||
request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String outputRequest(XMLObject xmlObject) throws Exception {
|
||||
try {
|
||||
System.setProperty("javax.xml.parsers.DocumentBuilderFactory",
|
||||
"org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
|
||||
|
||||
MarshallerFactory marshallerFactory = org.opensaml.xml.Configuration
|
||||
.getMarshallerFactory();
|
||||
Marshaller marshaller = marshallerFactory.getMarshaller(xmlObject);
|
||||
Element element = marshaller.marshall(xmlObject);
|
||||
|
||||
ByteArrayOutputStream byteArrayOutputStrm = new ByteArrayOutputStream();
|
||||
DOMImplementationRegistry registry = DOMImplementationRegistry
|
||||
.newInstance();
|
||||
DOMImplementationLS impl = (DOMImplementationLS) registry
|
||||
.getDOMImplementation("LS");
|
||||
LSSerializer writer = impl.createLSSerializer();
|
||||
LSOutput output = impl.createLSOutput();
|
||||
output.setByteStream(byteArrayOutputStrm);
|
||||
writer.write(element, output);
|
||||
return byteArrayOutputStrm.toString();
|
||||
} catch (Exception e) {
|
||||
throw new Exception("Error Serializing the SAML Response", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.edex.registry.acp.xacml.interceptor;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.RemoveObjectsRequest;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.SubmitObjectsRequest;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.UpdateObjectsRequest;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.query.v4.QueryRequest;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectType;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.rs.v4.RegistryRequestType;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.spi.v4.CatalogObjectsRequest;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.spi.v4.FilterObjectsRequest;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.spi.v4.ValidateObjectsRequest;
|
||||
|
||||
import org.apache.cxf.binding.soap.SoapMessage;
|
||||
import org.apache.cxf.interceptor.security.SAMLSecurityContext;
|
||||
import org.apache.cxf.message.Message;
|
||||
import org.apache.cxf.message.MessageContentsList;
|
||||
import org.apache.cxf.rt.security.xacml.RequestComponentBuilder;
|
||||
import org.apache.cxf.rt.security.xacml.XACMLConstants;
|
||||
import org.apache.cxf.security.SecurityContext;
|
||||
import org.apache.ws.security.WSSecurityException;
|
||||
import org.apache.ws.security.saml.ext.AssertionWrapper;
|
||||
import org.joda.time.DateTime;
|
||||
import org.opensaml.xacml.ctx.ActionType;
|
||||
import org.opensaml.xacml.ctx.AttributeType;
|
||||
import org.opensaml.xacml.ctx.AttributeValueType;
|
||||
import org.opensaml.xacml.ctx.EnvironmentType;
|
||||
import org.opensaml.xacml.ctx.RequestType;
|
||||
import org.opensaml.xacml.ctx.ResourceType;
|
||||
import org.opensaml.xacml.ctx.SubjectType;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class generates XACML authorization requests from SOAP and REST requests.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* 8/11/201r 1712 bphillip Initial Creation
|
||||
* </pre>
|
||||
*
|
||||
* @author bphillip
|
||||
* @version 1
|
||||
*/
|
||||
public class RegistryXACMLRequestBuilder {
|
||||
|
||||
/**
|
||||
* Creates and empty XACMLRequestBuilder
|
||||
*/
|
||||
public RegistryXACMLRequestBuilder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a list of requests for the given resources. A request per
|
||||
* resource is created due to the fact that individual registry objects may
|
||||
* have specific access control policies assigned to them.
|
||||
*
|
||||
* @param isSoapCall
|
||||
* True if this is a SOAP request
|
||||
* @param principal
|
||||
* The principal on the request
|
||||
* @param roles
|
||||
* The role of the requesting user
|
||||
* @param message
|
||||
* The actual message
|
||||
* @param resources
|
||||
* The resources involved with the request
|
||||
* @return A list of
|
||||
* @throws Exception
|
||||
*/
|
||||
public List<RequestType> createRequestList(boolean isSoapCall,
|
||||
Principal principal, List<String> roles, Message message,
|
||||
List<RegistryObjectType> resources) throws Exception {
|
||||
|
||||
// Gets the issuer of the message if one is specified
|
||||
String issuer = getIssuer(message);
|
||||
// Gets the action being executed
|
||||
String actionToUse = getAction(message, isSoapCall);
|
||||
List<RequestType> requests = new ArrayList<RequestType>(
|
||||
resources.size());
|
||||
|
||||
/*
|
||||
* Create a request per resource
|
||||
*/
|
||||
for (RegistryObjectType registryObject : resources) {
|
||||
requests.add(createRequest(principal, roles, issuer, actionToUse,
|
||||
registryObject, isSoapCall));
|
||||
}
|
||||
return requests;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an XACML request for the given resource
|
||||
* @param principal The principal on the message
|
||||
* @param roles The role(s) of the user making the request
|
||||
* @param issuer The issuer of the message
|
||||
* @param actionToUse The action being executed by the request
|
||||
* @param registryObject The registry object involved with the request
|
||||
* @param isSoapCall True if this is a soap call
|
||||
* @return An XACML request using the given resource
|
||||
*/
|
||||
private RequestType createRequest(Principal principal, List<String> roles,
|
||||
String issuer, String actionToUse,
|
||||
RegistryObjectType registryObject, boolean isSoapCall) {
|
||||
|
||||
// Build the Subject
|
||||
List<AttributeType> attributes = new ArrayList<AttributeType>();
|
||||
AttributeValueType subjectIdAttributeValue = RequestComponentBuilder
|
||||
.createAttributeValueType(principal.getName());
|
||||
AttributeType subjectIdAttribute = RequestComponentBuilder
|
||||
.createAttributeType(XACMLConstants.SUBJECT_ID,
|
||||
XACMLConstants.XS_STRING, issuer,
|
||||
Collections.singletonList(subjectIdAttributeValue));
|
||||
attributes.add(subjectIdAttribute);
|
||||
|
||||
if (roles != null) {
|
||||
List<AttributeValueType> roleAttributes = new ArrayList<AttributeValueType>(roles.size());
|
||||
for (String role : roles) {
|
||||
if (role != null) {
|
||||
AttributeValueType subjectRoleAttributeValue = RequestComponentBuilder
|
||||
.createAttributeValueType(role);
|
||||
roleAttributes.add(subjectRoleAttributeValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (!roleAttributes.isEmpty()) {
|
||||
AttributeType subjectRoleAttribute = RequestComponentBuilder
|
||||
.createAttributeType(XACMLConstants.SUBJECT_ROLE,
|
||||
XACMLConstants.XS_ANY_URI, issuer,
|
||||
roleAttributes);
|
||||
attributes.add(subjectRoleAttribute);
|
||||
}
|
||||
}
|
||||
SubjectType subjectType = RequestComponentBuilder.createSubjectType(
|
||||
attributes, null);
|
||||
|
||||
attributes.clear();
|
||||
|
||||
// Build the Resource
|
||||
attributes.add(RequestComponentBuilder.createAttributeType(
|
||||
XACMLConstants.RESOURCE_ID, XACMLConstants.XS_STRING, null,
|
||||
Collections.singletonList(RequestComponentBuilder
|
||||
.createAttributeValueType(registryObject.getId()))));
|
||||
ResourceType resourceType = RequestComponentBuilder.createResourceType(
|
||||
attributes, null);
|
||||
|
||||
// Build the Action
|
||||
AttributeValueType actionAttributeValue = RequestComponentBuilder
|
||||
.createAttributeValueType(actionToUse);
|
||||
AttributeType actionAttribute = RequestComponentBuilder
|
||||
.createAttributeType(XACMLConstants.ACTION_ID,
|
||||
XACMLConstants.XS_STRING, null,
|
||||
Collections.singletonList(actionAttributeValue));
|
||||
attributes.clear();
|
||||
attributes.add(actionAttribute);
|
||||
ActionType actionType = RequestComponentBuilder
|
||||
.createActionType(attributes);
|
||||
|
||||
// Environment
|
||||
attributes.clear();
|
||||
DateTime dateTime = new DateTime();
|
||||
AttributeValueType environmentAttributeValue = RequestComponentBuilder
|
||||
.createAttributeValueType(dateTime.toString());
|
||||
AttributeType environmentAttribute = RequestComponentBuilder
|
||||
.createAttributeType(XACMLConstants.CURRENT_DATETIME,
|
||||
XACMLConstants.XS_DATETIME, null,
|
||||
Collections.singletonList(environmentAttributeValue));
|
||||
attributes.add(environmentAttribute);
|
||||
|
||||
EnvironmentType environmentType = RequestComponentBuilder
|
||||
.createEnvironmentType(attributes);
|
||||
|
||||
// Build the Request
|
||||
RequestType request = RequestComponentBuilder.createRequestType(
|
||||
Collections.singletonList(subjectType),
|
||||
Collections.singletonList(resourceType), actionType,
|
||||
environmentType);
|
||||
|
||||
return request;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registry request object from the soap message
|
||||
* @param message The message to get the registry request object from
|
||||
* @return The registry request message extracted from the received xml message
|
||||
*/
|
||||
private RegistryRequestType getRequestFromSoapMessage(Message message) {
|
||||
if (message instanceof SoapMessage) {
|
||||
MessageContentsList content = (MessageContentsList) ((SoapMessage) message)
|
||||
.getContent(List.class);
|
||||
if (!content.isEmpty()) {
|
||||
Object obj = content.get(0);
|
||||
if (obj instanceof RegistryRequestType) {
|
||||
return (RegistryRequestType) obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the issuer from the message
|
||||
* @param message The message to get the issuer from
|
||||
* @return The issuer of the message
|
||||
* @throws WSSecurityException If errors occur while extracting the issuer
|
||||
*/
|
||||
private String getIssuer(Message message) throws WSSecurityException {
|
||||
SecurityContext sc = message.get(SecurityContext.class);
|
||||
|
||||
if (sc instanceof SAMLSecurityContext) {
|
||||
Element assertionElement = ((SAMLSecurityContext) sc)
|
||||
.getAssertionElement();
|
||||
if (assertionElement != null) {
|
||||
AssertionWrapper wrapper = new AssertionWrapper(
|
||||
assertionElement);
|
||||
return wrapper.getIssuerString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the action from the message
|
||||
* @param message The message to get the action from
|
||||
* @param isSoapCall True if this is a soap call
|
||||
* @return The action contained in the message
|
||||
*/
|
||||
private String getAction(Message message, boolean isSoapCall) {
|
||||
String actionToUse = null;
|
||||
RegistryRequestType request = getRequestFromSoapMessage(message);
|
||||
|
||||
if (isSoapCall) {
|
||||
if (request instanceof CatalogObjectsRequest) {
|
||||
actionToUse = "catalog";
|
||||
} else if (request instanceof FilterObjectsRequest) {
|
||||
actionToUse = "filter";
|
||||
} else if (request instanceof QueryRequest) {
|
||||
actionToUse = "read";
|
||||
} else if (request instanceof RemoveObjectsRequest) {
|
||||
actionToUse = "delete";
|
||||
} else if (request instanceof SubmitObjectsRequest) {
|
||||
actionToUse = "create";
|
||||
} else if (request instanceof UpdateObjectsRequest) {
|
||||
actionToUse = "update";
|
||||
} else if (request instanceof ValidateObjectsRequest) {
|
||||
actionToUse = "validate";
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported request type: "
|
||||
+ request.getClass());
|
||||
}
|
||||
} else {
|
||||
// For REST use the HTTP Verb
|
||||
if (message.get(Message.WSDL_OPERATION) == null
|
||||
&& message.get(Message.HTTP_REQUEST_METHOD) != null) {
|
||||
actionToUse = (String) message.get(Message.HTTP_REQUEST_METHOD);
|
||||
}
|
||||
}
|
||||
return actionToUse;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,358 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.edex.registry.acp.xacml.interceptor;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.RemoveObjectsRequest;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.SubmitObjectsRequest;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.lcm.v4.UpdateObjectsRequest;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.query.v4.QueryRequest;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.query.v4.QueryResponse;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.ObjectRefListType;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.ObjectRefType;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectListType;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.rim.v4.RegistryObjectType;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.rs.v4.RegistryRequestType;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.spi.v4.CatalogObjectsRequest;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.spi.v4.FilterObjectsRequest;
|
||||
import oasis.names.tc.ebxml.regrep.xsd.spi.v4.ValidateObjectsRequest;
|
||||
|
||||
import org.apache.cxf.binding.soap.SoapMessage;
|
||||
import org.apache.cxf.interceptor.Fault;
|
||||
import org.apache.cxf.interceptor.security.AccessDeniedException;
|
||||
import org.apache.cxf.message.Message;
|
||||
import org.apache.cxf.message.MessageContentsList;
|
||||
import org.apache.cxf.phase.AbstractPhaseInterceptor;
|
||||
import org.apache.cxf.phase.Phase;
|
||||
import org.apache.cxf.security.LoginSecurityContext;
|
||||
import org.apache.cxf.security.SecurityContext;
|
||||
import org.apache.ws.security.saml.ext.OpenSAMLUtil;
|
||||
import org.opensaml.xacml.XACMLObject;
|
||||
import org.opensaml.xacml.ctx.DecisionType;
|
||||
import org.opensaml.xacml.ctx.RequestType;
|
||||
import org.opensaml.xacml.ctx.ResponseType;
|
||||
import org.opensaml.xacml.ctx.ResultType;
|
||||
import org.opensaml.xacml.policy.ObligationType;
|
||||
import org.opensaml.xacml.policy.ObligationsType;
|
||||
|
||||
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||
import com.raytheon.uf.common.status.UFStatus;
|
||||
import com.raytheon.uf.common.util.CollectionUtil;
|
||||
import com.raytheon.uf.edex.registry.acp.xacml.XACMLPolicyAdministrator;
|
||||
import com.raytheon.uf.edex.registry.acp.xacml.XACMLPolicyDecisionPoint;
|
||||
import com.raytheon.uf.edex.registry.acp.xacml.engine.obligation.XACMLObligationEvaluator;
|
||||
import com.raytheon.uf.edex.registry.acp.xacml.exception.XACMLException;
|
||||
import com.raytheon.uf.edex.registry.ebxml.dao.RegistryObjectDao;
|
||||
import com.raytheon.uf.edex.registry.ebxml.exception.EbxmlRegistryException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* Policy enforcement point (PEP) - The system entity that performs access
|
||||
* control, by making decision requests and enforcing authorization decisions.
|
||||
* This term is defined in a joint effort by the IETF Policy Framework Working
|
||||
* Group and the Distributed Management Task Force (DMTF)/Common Information
|
||||
* Model (CIM) in [RFC3198]. This term corresponds to "Access Enforcement
|
||||
* Function" (AEF) in [ISO10181-3].
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* 7/09/2014 724 bphillip Initial Coding
|
||||
* 8/08/2014 1720 bphillip Implemented support for custom XACML access policies
|
||||
* </pre>
|
||||
*
|
||||
* @author bphillip
|
||||
* @version 1
|
||||
*/
|
||||
public class XACMLInterceptor extends AbstractPhaseInterceptor<Message> {
|
||||
|
||||
/** The logger */
|
||||
private static final IUFStatusHandler statusHandler = UFStatus
|
||||
.getHandler(XACMLInterceptor.class);
|
||||
|
||||
/** The slot containing the id of the custom XACML policy */
|
||||
private static final String POLICY_SLOT_NAME = "urn:oasis:names:tc:ebxml-regrep:rim:RegistryObject:accessControlPolicy";
|
||||
|
||||
/** The id of the default XACML policy set */
|
||||
private static final String DEFAULT_POLICY = "urn:oasis:names:tc:xacml:2.0:data-delivery:default-policySet";
|
||||
|
||||
/** XACML Policy Administrator object which manages XACML policies */
|
||||
private XACMLPolicyAdministrator xacmlPolicyAdmin;
|
||||
|
||||
/** The XACML Policy Decision point */
|
||||
private XACMLPolicyDecisionPoint pdp;
|
||||
|
||||
/** Registry object data access object used for registry objects */
|
||||
private RegistryObjectDao registryObjectDao;
|
||||
|
||||
/**
|
||||
* Builder object that builds XACML authorization requests from the registry
|
||||
* requests
|
||||
*/
|
||||
private RegistryXACMLRequestBuilder requestBuilder;
|
||||
|
||||
/**
|
||||
* Constructs a new XACMLInterceptor
|
||||
*
|
||||
* @param xacmlPolicyAdmin
|
||||
* The policy admin
|
||||
* @param pdp
|
||||
* The policy decision point
|
||||
* @param registryObjectDao
|
||||
* The registry object data access object
|
||||
*/
|
||||
public XACMLInterceptor(XACMLPolicyAdministrator xacmlPolicyAdmin,
|
||||
XACMLPolicyDecisionPoint pdp, RegistryObjectDao registryObjectDao) {
|
||||
super(Phase.POST_INVOKE);
|
||||
OpenSAMLUtil.initSamlEngine();
|
||||
this.xacmlPolicyAdmin = xacmlPolicyAdmin;
|
||||
this.pdp = pdp;
|
||||
this.registryObjectDao = registryObjectDao;
|
||||
requestBuilder = new RegistryXACMLRequestBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message message) throws Fault {
|
||||
SecurityContext sc = message.get(SecurityContext.class);
|
||||
|
||||
boolean isSoapCall = (message != null && message
|
||||
.get(Message.WSDL_OPERATION) != null);
|
||||
|
||||
if (sc instanceof LoginSecurityContext) {
|
||||
LoginSecurityContext loginSecurityContext = (LoginSecurityContext) sc;
|
||||
Principal principal = sc.getUserPrincipal();
|
||||
Set<Principal> principalRoles = loginSecurityContext.getUserRoles();
|
||||
List<String> roles = new ArrayList<String>();
|
||||
if (principalRoles != null) {
|
||||
for (Principal p : principalRoles) {
|
||||
if (p != principal) {
|
||||
roles.add(p.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<RequestType> requestList = null;
|
||||
List<RegistryObjectType> resources = null;
|
||||
try {
|
||||
resources = getResources(message, isSoapCall);
|
||||
requestList = requestBuilder.createRequestList(isSoapCall,
|
||||
principal, roles, message, resources);
|
||||
} catch (Exception e1) {
|
||||
throw new SecurityException("Error generating XACML requests!",
|
||||
e1);
|
||||
}
|
||||
try {
|
||||
boolean accessPermitted = true;
|
||||
for (int i = 0; i < requestList.size() && accessPermitted; i++) {
|
||||
ResponseType response = performRequest(requestList.get(i),
|
||||
resources.get(i));
|
||||
ResultType result = response.getResult();
|
||||
|
||||
// Handle any Obligations returned by the PDP
|
||||
handleObligations(requestList.get(i), principal, message,
|
||||
result);
|
||||
|
||||
if (result != null
|
||||
&& (result.getDecision().getDecision() == DecisionType.DECISION.Permit)
|
||||
&& (result.getResourceId() == null)) {
|
||||
continue;
|
||||
}
|
||||
statusHandler.warn("XACML authorization not permitted:");
|
||||
accessPermitted = false;
|
||||
}
|
||||
if (accessPermitted) {
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
statusHandler.error("An error occurred during XACML authorization. Defaulting to Unauthorized", e);
|
||||
throw new AccessDeniedException("Unauthorized");
|
||||
}
|
||||
} else {
|
||||
statusHandler
|
||||
.error("The SecurityContext was not an instance of LoginSecurityContext. No authorization "
|
||||
+ "is possible as a result");
|
||||
}
|
||||
|
||||
throw new AccessDeniedException("Unauthorized");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the XACML authorization request
|
||||
*
|
||||
* @param request
|
||||
* The authorization request
|
||||
* @param resource
|
||||
* The resource contained in the request
|
||||
* @return The XACML authorization response
|
||||
* @throws EbxmlRegistryException
|
||||
* If errors occur retrieving the XACML policy object
|
||||
*/
|
||||
private ResponseType performRequest(RequestType request,
|
||||
RegistryObjectType resource) throws EbxmlRegistryException {
|
||||
ResponseType response = null;
|
||||
XACMLObject policy = null;
|
||||
String policyName = resource.getSlotValue(POLICY_SLOT_NAME);
|
||||
if (policyName == null) {
|
||||
policy = xacmlPolicyAdmin.getPolicyObject(DEFAULT_POLICY);
|
||||
} else {
|
||||
policy = xacmlPolicyAdmin.getPolicyObject(policyName);
|
||||
if (policy == null) {
|
||||
statusHandler
|
||||
.warn("Policy ["
|
||||
+ policyName
|
||||
+ "] does not exist. Using default access control policy!");
|
||||
policy = xacmlPolicyAdmin.getPolicyObject(DEFAULT_POLICY);
|
||||
}
|
||||
}
|
||||
|
||||
response = pdp.evaluate(policy, request);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the resources from the message and retrieves them from the registry
|
||||
* database if possible
|
||||
*
|
||||
* @param message
|
||||
* The message to get the resources from
|
||||
* @param isSoapCall
|
||||
* True if this is a SOAP call
|
||||
* @return The list of registry object resources referenced by the message
|
||||
* @throws EbxmlRegistryException
|
||||
* If errors occur while querying for the objects from the
|
||||
* registry database
|
||||
*/
|
||||
private List<RegistryObjectType> getResources(Message message,
|
||||
boolean isSoapCall) throws EbxmlRegistryException {
|
||||
List<RegistryObjectType> registryObjects = Collections.emptyList();
|
||||
|
||||
List<String> ids = getResourceIds(message, isSoapCall);
|
||||
if (!CollectionUtil.isNullOrEmpty(ids)) {
|
||||
registryObjects = registryObjectDao.getById(ids);
|
||||
}
|
||||
|
||||
return registryObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the ids of the resources from the message
|
||||
*
|
||||
* @param message
|
||||
* The message to get the resource ids from
|
||||
* @param isSoapCall
|
||||
* True if this is a SOAP call
|
||||
* @return The list of resources ids extracted from the message
|
||||
* @throws EbxmlRegistryException
|
||||
* If an invalid message is submitted
|
||||
*/
|
||||
private List<String> getResourceIds(Message message, boolean isSoapCall)
|
||||
throws EbxmlRegistryException {
|
||||
List<String> ids = new ArrayList<String>();
|
||||
ObjectRefListType refList = null;
|
||||
RegistryObjectListType objList = null;
|
||||
|
||||
if (isSoapCall) {
|
||||
RegistryRequestType request = null;
|
||||
MessageContentsList content = (MessageContentsList) ((SoapMessage) message)
|
||||
.getContent(List.class);
|
||||
|
||||
if (!content.isEmpty()) {
|
||||
Object obj = content.get(0);
|
||||
if (obj instanceof RegistryRequestType) {
|
||||
request = (RegistryRequestType) obj;
|
||||
}
|
||||
}
|
||||
if (request == null) {
|
||||
throw new EbxmlRegistryException(
|
||||
"Could not determine request type!");
|
||||
}
|
||||
|
||||
if (request instanceof CatalogObjectsRequest) {
|
||||
refList = ((CatalogObjectsRequest) request).getObjectRefList();
|
||||
objList = ((CatalogObjectsRequest) request)
|
||||
.getOriginalObjects();
|
||||
} else if (request instanceof FilterObjectsRequest) {
|
||||
objList = ((FilterObjectsRequest) request).getOriginalObjects();
|
||||
} else if (request instanceof QueryRequest) {
|
||||
QueryResponse queryResponse = (QueryResponse) ((SoapMessage) message
|
||||
.getExchange().getOutMessage()).getContent(List.class)
|
||||
.get(0);
|
||||
refList = queryResponse.getObjectRefList();
|
||||
objList = queryResponse.getRegistryObjectList();
|
||||
} else if (request instanceof RemoveObjectsRequest) {
|
||||
refList = ((RemoveObjectsRequest) request).getObjectRefList();
|
||||
} else if (request instanceof SubmitObjectsRequest) {
|
||||
objList = ((SubmitObjectsRequest) request)
|
||||
.getRegistryObjectList();
|
||||
} else if (request instanceof UpdateObjectsRequest) {
|
||||
refList = ((UpdateObjectsRequest) request).getObjectRefList();
|
||||
} else if (request instanceof ValidateObjectsRequest) {
|
||||
refList = ((ValidateObjectsRequest) request).getObjectRefList();
|
||||
objList = ((ValidateObjectsRequest) request)
|
||||
.getOriginalObjects();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported request type: "
|
||||
+ request.getClass());
|
||||
}
|
||||
if (refList != null) {
|
||||
for (ObjectRefType ref : refList.getObjectRef()) {
|
||||
ids.add(ref.getId());
|
||||
}
|
||||
}
|
||||
if (objList != null) {
|
||||
for (RegistryObjectType regObj : objList.getRegistryObject()) {
|
||||
ids.add(regObj.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle any Obligations returned by the PDP
|
||||
*
|
||||
* @throws XACMLException
|
||||
*/
|
||||
protected void handleObligations(RequestType request, Principal principal,
|
||||
Message message, ResultType result) throws XACMLException {
|
||||
ObligationsType obligationObject = result.getObligations();
|
||||
if (obligationObject != null
|
||||
&& !obligationObject.getObligations().isEmpty()) {
|
||||
statusHandler.info("Evaluating "
|
||||
+ obligationObject.getObligations().size()
|
||||
+ " obligations!");
|
||||
for (ObligationType obligation : result.getObligations()
|
||||
.getObligations()) {
|
||||
XACMLObligationEvaluator.getInstance().evaluate(obligation,
|
||||
request);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue