Fine Grained Web Authorization in Java Using XACML
Join the DZone community and get the full member experience.
Join For FreeServlet 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
Opinions expressed by DZone contributors are their own.
Trending
-
Observability Architecture: Financial Payments Introduction
-
How to LINQ Between Java and SQL With JPAStreamer
-
File Upload Security and Malware Protection
-
Top 10 Pillars of Zero Trust Networks
Comments