Anil Saldhana is the Lead Identity Management Architect at JBoss. He blogs at http://anil-identity.blogspot.com Anil has posted 16 posts at DZone. You can read more from them at their website. View Full User Profile

Fine Grained Web Authorization in Java Using XACML

02.12.2009
| 15990 views |
  • submit to reddit

Servlet Containers such as Tomcat are required to support container security that includes coarse grained authorization based on roles. The servlet specification defines web resources in the form of URL patterns and can provide access control to these resources using roles. This in itself can either be a boon or a bane to web developers depending on their use cases. The positive aspect is that developers can isolate security code from their business logic and delegate security to the web containers. The limiting aspect is that web container authorization does not scale well to fine grained access control needs of business/enterprise applications. Oasis XACML v2.0 is a specification that exclusively caters to access control and is an excellent specification to incorporate fine grained access control into your enterprise web applications. In this article, we will look at incorporating fine grained authorization into your web application.

 

Fine Grained Access Control

Unlike coarse grained access control, fine grained access control is complex with changing requirements and multiple variables involved in the decision making process. Access control decisions such as the following:

  • Allow employees access to a section of the portal on normal business days from 9am to 5pm and not on weekends.
  • Disallow requests from a particular subnet.
  • Junior traders need approval from managers for trades above $1 million in value.
  • Employees should not modify their own salary information. Only managers can change salary information of their subordinates.


cannot be mapped to the access control rules specified in the servlet specification.  These advanced access control questions are based on context and business needs. While it makes sense to utilize web container security for authentication and coarse grained authorixation, it is certainly unfortunate that container security falls short for fine grained authorization. One possible solution is to externalize the access control policy such that the policy engine that does the evaluation remains the same and the external policies can change as per the business requirements. Given this, it is customary for web developers to develop security as part of their application. It does make sense for them to utilize servlet filters to introduce security to their applications such that the application does business code and the filter takes care of security.

 

Access Control Lists


ACLs have historically allowed developers and administrators to incorporate fine grained authorization into their business applications. A disadvantage of this approach is that it is non-portable and propreitory with no standards involved.  XACML provides a standards based solution to this problem.

 

XACML

XACML defines a policy language and an architecture for decision making. The following diagram shows a basic XACML architecture that includes a Policy Enforcement Point (PEP) which intercepts any requests in a normal program flow, then asks a Policy Decision Point (PDP) to make an access decision based on the policies associated with the PDP.  The PDP evaluates the XACML request created by the PEP and runs through the policies to make one of the 4 access decisions, namely

  • PERMIT - approve,
  • DENY - access denied,
  • INDETERMINATE - error at the PDP,
  • NOTAPPLICABLE - some attribute missing in the request or no policy match.































Java based XACML Implementations

In this article, we will use JBossXACML, a LGPL licensed library for developing the PEP and PDP for our fine grained authorization. JBossXACML is a standalone open source library that has dependence on a JAXB2 implementation alone (either you can use the Sun JAXB2 RI for JDK5 or it is provided by JDK6 onwards).

XACML Policy

Let us take a look at the XACML policy that will drive the a simple use case in this article. The use case is to control access to a web resource denoted by an URL "http://test/developer-guide.html" to a subject with a role of a "developer".

 

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Policy xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:permit-overrides"
Version="2.0" PolicyId="ExamplePolicy">
<Target>
<Resources>
<Resource>
<ResourceMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:anyURI-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#anyURI">http://test/developer-guide.html</AttributeValue>
<ResourceAttributeDesignator DataType="http://www.w3.org/2001/XMLSchema#anyURI" AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"/>
</ResourceMatch>
</Resource>
</Resources>
</Target>
<Rule Effect="Permit" RuleId="ReadRule">
<Target>
<Actions>
<Action>
<ActionMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">read</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>
<Condition>
<Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-is-in">
<AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">developer</AttributeValue>
<SubjectAttributeDesignator DataType="http://www.w3.org/2001/XMLSchema#string"
AttributeId="urn:oasis:names:tc:xacml:2.0:subject:role" />
</Apply>
</Condition>
</Rule>
<Rule Effect="Deny" RuleId="DenyRule"/>
</Policy>

 

Web Policy Enforcement Point (PEP)

 The main job of a PEP is to intercept requests to any resources and then create an XACML request based on attributes about the Subject (actor accessing the resource), Action, Attributes about the Resource and Environment (time, date, IP address etc) and pass it to a PDP for access decision. Based on the PDP decision, the PEP can either allow access to the resource or not.

package org.jboss.test.security.xacml.bindings.web;

import java.net.URI;
import java.security.Principal;
import java.security.acl.Group;
import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;

import org.jboss.security.xacml.core.model.context.ActionType;
import org.jboss.security.xacml.core.model.context.AttributeType;
import org.jboss.security.xacml.core.model.context.EnvironmentType;
import org.jboss.security.xacml.core.model.context.RequestType;
import org.jboss.security.xacml.core.model.context.ResourceType;
import org.jboss.security.xacml.core.model.context.SubjectType;
import org.jboss.security.xacml.factories.RequestAttributeFactory;
import org.jboss.security.xacml.factories.RequestResponseContextFactory;
import org.jboss.security.xacml.interfaces.RequestContext;

/**
* PEP for the web layer
* @author Anil Saldhana
*/
public class WebPEP
{
String ACTION_IDENTIFIER = "urn:oasis:names:tc:xacml:1.0:action:action-id";
String CURRENT_TIME_IDENTIFIER = "urn:oasis:names:tc:xacml:1.0:environment:current-time";
String RESOURCE_IDENTIFIER = "urn:oasis:names:tc:xacml:1.0:resource:resource-id";
String SUBJECT_IDENTIFIER = "urn:oasis:names:tc:xacml:1.0:subject:subject-id";
String SUBJECT_ROLE_IDENTIFIER = "urn:oasis:names:tc:xacml:2.0:subject:role";

@SuppressWarnings("unchecked")
public RequestContext createXACMLRequest(HttpServletRequest request,
Principal principal, Group roleGroup) throws Exception
{
RequestContext requestCtx = RequestResponseContextFactory.createRequestCtx();

//Create a subject type
SubjectType subject = new SubjectType();
subject.getAttribute().add(RequestAttributeFactory.createStringAttributeType(
SUBJECT_IDENTIFIER, "jboss.org", principal.getName()));
Enumeration roles = (Enumeration) roleGroup.members();
while(roles.hasMoreElements())
{
Principal rolePrincipal = roles.nextElement();
AttributeType attSubjectID = RequestAttributeFactory.createStringAttributeType(
SUBJECT_ROLE_IDENTIFIER, "jboss.org", rolePrincipal.getName());
subject.getAttribute().add(attSubjectID);
}

//Create a resource type
ResourceType resourceType = new ResourceType();
resourceType.getAttribute().add(RequestAttributeFactory.createAnyURIAttributeType(
RESOURCE_IDENTIFIER, null, new URI(request.getRequestURI())));

//Create an action type
ActionType actionType = new ActionType();
actionType.getAttribute().add(RequestAttributeFactory.createStringAttributeType(
ACTION_IDENTIFIER, "jboss.org", "read"));

//Create an Environment Type (Optional)
EnvironmentType environmentType = new EnvironmentType();
environmentType.getAttribute().add(RequestAttributeFactory.createDateTimeAttributeType(
CURRENT_TIME_IDENTIFIER, null));

//Create a Request Type
RequestType requestType = new RequestType();
requestType.getSubject().add(subject);
requestType.getResource().add(resourceType);
requestType.setAction(actionType);
requestType.setEnvironment(environmentType);

requestCtx.setRequest(requestType);

return requestCtx;
}
}

 

This PEP needs a small change where in you need to figure out the XACML resource action("read","Write") by the http method - get or post.

actionType.getAttribute().add(RequestAttributeFactory.createStringAttributeType(
ACTION_IDENTIFIER, "jboss.org", "read"));

 

Unit Test

As a web developer, you should be creating a servlet filter to incorporate the code I show here as a JUnit test.

package org.jboss.test.security.xacml.bindings.web;



import java.io.InputStream;

import java.security.Principal;

import java.security.acl.Group;



import javax.servlet.http.HttpServletRequest;



import junit.framework.TestCase;



import org.jboss.security.xacml.core.JBossPDP;

import org.jboss.security.xacml.interfaces.PolicyDecisionPoint;

import org.jboss.security.xacml.interfaces.RequestContext;

import org.jboss.security.xacml.interfaces.XACMLConstants;

import org.jboss.test.security.xacml.factories.util.XACMLTestUtil;





/**

* Unit Tests for the Web bindings

*/

public class WebLayerUnitTestCase extends TestCase

{

//Ensure that a subject with the role of developer can access the resource
public void testWebBinding() throws Exception

{

PolicyDecisionPoint pdp = getPDP();

assertNotNull("JBossPDP is != null", pdp);



Principal p = new Principal()

{

public String getName()

{

return "testuser";

}

};



//Create Role Group

Group grp = XACMLTestUtil.getRoleGroup("developer");



String requestURI = "http://test/developer-guide.html";

HttpRequestUtil util = new HttpRequestUtil();

HttpServletRequest req = util.createRequest(p, requestURI);



//Check PERMIT condition

WebPEP pep = new WebPEP();

RequestContext request = pep.createXACMLRequest(req, p, grp);



assertEquals("Access Allowed?", XACMLConstants.DECISION_PERMIT, XACMLTestUtil.getDecision(pdp, request));

}



//Ensure that a subject with a role of "imposter" cannot access the resource
public void testNegativeAccessWebBinding() throws Exception

{

PolicyDecisionPoint pdp = getPDP();

assertNotNull("JBossPDP is != null", pdp);

Principal p = new Principal()

{

public String getName()

{

return "testuser";

}

};



//Create Role Group

Group grp = XACMLTestUtil.getRoleGroup("imposter");

String requestURI = "http://test/developer-guide.html";

HttpRequestUtil util = new HttpRequestUtil();

HttpServletRequest req = util.createRequest(p, requestURI);



//Check DENY condition

WebPEP pep = new WebPEP();

RequestContext request = pep.createXACMLRequest(req, p, grp);



assertEquals("Access Disallowed?", XACMLConstants.DECISION_DENY, XACMLTestUtil.getDecision(pdp, request));

}



private PolicyDecisionPoint getPDP()

{

ClassLoader tcl = Thread.currentThread().getContextClassLoader();

InputStream is = tcl.getResourceAsStream("test/config/webConfig.xml");

assertNotNull("InputStream != null", is);



return new JBossPDP(is);

}

}

 

HTTPRequestUtil is just a dummy util class that creates a test HttpServletRequest object. Your
web application will have access to the request object from the web container.

 

Even though the XACML policy is quite simple, you should be able make modifications to the policy file(s) without changing the PEP or PDP.

 

JBossXACML Configuration File

If you look at the method getPDP(), you will a reference to a webConfig.xml.  This is a configuration file
used by JBossXACML to indicate where the XACML policies are located.

 

<ns:jbosspdp xmlns:ns="urn:jboss:xacml:2.0">
<ns:Policies>
<ns:Policy>
<ns:Location>test/policies/bindings/web/web-policy.xml</ns:Location>
</ns:Policy>
</ns:Policies>
<ns:Locators>
<ns:Locator Name="org.jboss.security.xacml.locators.JBossPolicyLocator">
</ns:Locator>
</ns:Locators>
</ns:jbosspdp>

 

Conclusion

In this article, we have seen an implementation of a fine grained authorization mechanism using XACML.

 

References

XACML on Wikipedia: http://en.wikipedia.org/wiki/XACML
JBossXACML: https://www.jboss.org/community/docs/DOC-10840

User Guide: http://www.jboss.org/file-access/default/members/jbosssecurity/freezone/releases/jbossxacml/2.0.2.GA/guide/html/jbossxacml.html
 

About the Author:

Anil Saldhana is the Lead Security Architect at JBoss. He blogs at http://anil-identity.blogspot.com

AttachmentSize
xacml_arch.png29.67 KB
Published at DZone with permission of its author, Anil Saldhana.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Romen Law replied on Wed, 2009/02/18 - 12:10am

Looks interesting and very useful. I have a couple of questions: 1. does the library/framework have constants or enums to provide a shorthand for the long namespace strings ("urn:oasis:name...")? 2. all those xml flies (e.g. policy) seem quite complex to be written by hand, even with editors (e.g. UMU XACML editor). How do people actually create these files? I'd imagine these files are huge in a real application. cheers romen

Anil Saldhana replied on Thu, 2009/02/19 - 5:34pm in response to: Romen Law

For the constants, please look for org.jboss.security.xacml.interfaces.XACMLConstants

Regarding policy construction, there is a lack of good open source editors for constructing policies. For enterprises, you would typically go with the policy editor that comes with your xacml solution.

Anil Saldhana replied on Wed, 2009/03/04 - 11:15am

Pick the consolidated jbossxacml jar from this location:

http://repository.jboss.org/maven2/org/jboss/security/jbossxacml/2.0.3.CR1/

 

You will need the JAXB libraries as dependencies (which are part of JDK6+).  If you need the JAXB API and IMPL jars, you can get it from java.net or download from:

http://repository.jboss.org/maven2/sun-jaxb/

Anil Saldhana replied on Thu, 2009/06/11 - 5:50am

Always pick the latest released version of JBossXACML from http://www.jboss.org/auth/jbosssecurity/downloads/

yuri negocio replied on Mon, 2012/11/19 - 8:13am

I think the XACML specification fantastic, however, very complex and costly to build access control policies for large systems. For our customers we prefer to implement an intermediate language interchangeably with XACML. This effort has made it possible to reduce approximately 60% the size of the xml's.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.