14 October 2014

Using the Talend PDP ouside of an OSGi Container

In a previous post I've explained how to setup a demo application using SAML token for authentication and XACML for authorization in context of REST services.
In this blog I'm going to explain how to setup the Talend PDP ouside of the OSGi container in which it is usually located, so that you are able to use the PDP co-located to your demo application in any JavaEE container. This is especially helpful if your application cannot easily being deployed into the Talend runtime, but requires lots of authorization requests. In these cases it will be best to have the PDP co-located with your app, completely avoiding expensive network calls.

This post continues with the demo application described in my previous post. To follow this post you should first read my other post.

All you need to do to get the PDP dependencies into your demo application war file is to add the following dependency to your to your pom.xml file:
<dependency>
    <groupId>org.talend.esb.authorization</groupId>
    <artifactId>tesb-xacml-pdp-rt</artifactId>
    <version>5.4.1</version>
</dependency> 

This dependency is available to Talend Enterprise Edition only!
If you do not want to use Talend EE you could also use the HERAS-AF implementation directly. But in this case you will be missing some of the extensions which are only provided by Talend.

Standalone PDP

Next you can setup the PDP as a REST service, taking XACML requests in and returning XACML responses in your /src/main/webapp/WEB-INF/beans.xml file. In this case the demo service will use the localhost network interface to comunicate with the PDP.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cxf="http://cxf.apache.org/core" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

    <import resource="classpath:META-INF/cxf/cxf.xml" />

    <context:property-placeholder />
    <context:annotation-config />
    <bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer" />
    <bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer" />

    <jaxrs:server id="services" address="/">
        <jaxrs:serviceBeans>
            <bean id="helloWorldService" class="org.talend.example.rest.HelloWorld" />
        </jaxrs:serviceBeans>
        <jaxrs:providers>
            <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
            <bean id="samlHandler" class="org.apache.cxf.rs.security.saml.SamlHeaderInHandler" />
        </jaxrs:providers>
        <jaxrs:properties>
            <entry key="ws-security.signature.properties" value="alice.properties" />
        </jaxrs:properties>
        <jaxrs:inInterceptors>
            <bean class="org.talend.esb.authorization.xacml.rt.pep.CXFXACMLAuthorizingInterceptor" id="XACMLInterceptor">
                <property name="pdpAddress" value="http://localhost:8080/pdp/authorize" />
                <property name="requireRoles" value="false" />
            </bean>
        </jaxrs:inInterceptors>
    </jaxrs:server>

    <bean id="prpBean" class="org.talend.esb.authorization.xacml.pdp.herasaf.FilePolicyRetrievalPoint">
        <property name="policyURL" value="WEB-INF/pdp-policy.xml" />
    </bean>
    
    <bean id="pdpBean" class="org.talend.esb.authorization.xacml.pdp.herasaf.HerasAFPolicyDecisionPoint">
        <property name="policyRetrievalPoint" ref="prpBean" />
    </bean>

    <bean id="pdpServiceBean" class="org.talend.esb.authorization.xacml.pdp.service.PolicyDecisionPointService">
        <property name="policyDecisionPoint" ref="pdpBean" />
    </bean>

    <jaxrs:server address="/pdp/">
        <jaxrs:serviceBeans>
            <ref bean="pdpServiceBean" />
        </jaxrs:serviceBeans>
    </jaxrs:server>
   
</beans> 

In the above sample the PDP uses a file policy retrieval point to load its authorization policies. The policy file could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<Policy PolicyId="ExamplePolicy"
          RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:permit-overrides"
          xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os" >
    <Target>
      <Resources>
        <Resource>
          <ResourceMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-regexp-match">
            <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">/hello/echo/Sierra.*</AttributeValue>
            <ResourceAttributeDesignator DataType="http://www.w3.org/2001/XMLSchema#string"
                                         AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"/>
          </ResourceMatch>
        </Resource>
      </Resources>
    </Target>
    <Rule RuleId="ExecuteRule" Effect="Permit">
      <Target>
        <Actions>
          <Action>
            <ActionMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
              <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">GET</AttributeValue>
              <ActionAttributeDesignator DataType="http://www.w3.org/2001/XMLSchema#string"
                                         AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"/>
            </ActionMatch>
          </Action>
        </Actions>
      </Target>
    </Rule>
  </Policy>

The above policies only allows GET request to the echo service which are starting with Sierra. This makes it easy to test your PDP endpoint. Calling the first URL should be successfull whereas the second should fail:
  1.  http://localhost:8080/hello/echo/SierraTangoNevada
  2. http://localhost:8080/hello/echo/TangoNevada

Co-Located Setup

To switch from network connection to direct PDP invocation you need to modify your beans.xml as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:cxf="http://cxf.apache.org/core" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
        http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">

    <import resource="classpath:META-INF/cxf/cxf.xml" />

    <context:property-placeholder />
    <context:annotation-config />
    <bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer" />
    <bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer" />

    <jaxrs:server id="services" address="/">
        <jaxrs:serviceBeans>
            <bean id="helloWorldService" class="org.talend.example.rest.HelloWorld" />
        </jaxrs:serviceBeans>
        <jaxrs:providers>
            <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
            <bean id="samlHandler" class="org.apache.cxf.rs.security.saml.SamlHeaderInHandler" />
        </jaxrs:providers>
        <jaxrs:properties>
            <entry key="ws-security.signature.properties" value="alice.properties" />
        </jaxrs:properties>
        <jaxrs:inInterceptors>
            <bean class="org.talend.esb.authorization.xacml.rt.pep.CXFXACMLAuthorizingInterceptor" id="XACMLInterceptor">
                <property name="policyDecisionPoint" ref="pdpBean"/>
                <property name="requireRoles" value="false" />
            </bean>
        </jaxrs:inInterceptors>
    </jaxrs:server>
    
    <bean id="prpBean" class="org.talend.esb.authorization.xacml.pdp.herasaf.RBACRegistryAtomPolicyRetrievalPoint">
       <property name="registryAtomUrl" value = "http://localhost:8040/services/XacmlRegistryAtom"/>
       <property name="policyCachingStrategy" value ="InMemory"/>
       <property name="cacheConfiguration" value="pdp-ehcache.xml"/>
       <property name="loadPermissionPoliciesOnInit" value="true"/>
       <property name="policyReloadInterval" value="10"/>
       <property name="validatePolicies" value="false"/>
       <property name="authentication" value="NO"/>
       <!--property name="username" value="tesb"/>
       <property name="password" value="tesb"/-->
    </bean>

    <bean id="pdpBean" class="org.talend.esb.authorization.xacml.pdp.herasaf.HerasAFPolicyDecisionPoint">
        <property name="policyRetrievalPoint" ref="prpBean" />
    </bean>

</beans>

In the above sample I replaced the file policy retrieval point with the Talend policy store retrieval point, thus being able to fetch authorization policies from a central server location. Since these policies will be cached in the PDP the network overhead will be quite low.I also removed the code to setup a remote accessible PDP endpoint but instead I injected the PDP instance directly to the XACML PEP interceptor of the demo application.

3 comments:

  1. Nice blog very well defined stuff you given thanks for sharing.
    Interested in learning Talend Training
    Talend Online Training

    ReplyDelete
  2. This is seriously good, you have really highlighted some of the great points one should know. Awesome work Wonderful suggestions and guidance
    Talend Online Training Classes

    ReplyDelete
  3. It is very good information and useful topics. Thanks for sharing a good information .... Talend ETL Online Training

    ReplyDelete