Security Features of JBoss AS 5.1 - Part 4 - XACML authorization for Web Applications
Join the DZone community and get the full member experience.
Join For FreeOasis XACML v2.0 is a robust open standard catering to access control. Starting JBoss Application Server v5.0, users have the opportunity to use XACML as container authorization mechanism for Web applications similar to JACC or the servlet container role based access control.
This article will focus on JBoss Application Server v5.1.0
In this article, we will take a look at a web application and use XACML as the authorization mechanism.
Assumptions
This article assumes that the reader is familiar with Web Container security and the deployment descriptors such as web.xml. This article is catered toward advanced users of JBoss AS.
Why is there a need for XACML in Java EE?
The Java EE specifications offer coarse grained security that is based on roles. If an user wishes to apply fine grained access control to Java EE components such as the web or EJB applications, then he needs to look at non-standard ways of doing it. JACC (JSR-115) is an authorization specification that is mandated in the Java EE world, since v1.4 but it is a specification that is tied to the web and ejb standard deployment descriptors, to provide the authorization support.
If the users wish to provide fine grained authorization in the containers, that may be tied to some context, then they will probably have to get away from container security and write their own via servlet filters or some type of server interceptors.
Some examples of container authorization that can be tied to business context are:
- Allow access to this web resource to employees who are active and between the business hours of 9am-5pm on Mondays through Thursday and 9am -2pm on Fridays and no access on weekends.
- Do not allow access to this EJB application from this particular subnet.
Limitations of application of XACML in Java EE
- The feature is an extension of security provided by JavaEE. So in some ways, it is a non-standard behavior.
- There are no standard xacml attributes for some of the components such as EJBs. So there is a need for custom schema from the vendor.
We will have two web applications with two different use cases. The packaged war files are attached to this article.
- jduke can read or write resource information when the request parameter "status" in Action has a value "employed"
- jduke can read or write resource information when he has a role of ServletUserRole
The web applications will be named "xacml-requestattrib.war" and "xacml-subjectrole.war" with WEB-INF containing the same web.xml, jboss-web.xml and jbossxacml-config.xml. The only differentiator would be the xacml policy file "jboss-xacml-policy.xml"
Use Case 1
Step 1: Let us take a look at the web.xml deployment descriptor.
<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<description>Web Application that tests XACML Integration with the web container
- access granted if a specific request parameter exists</description>
<servlet>
<servlet-name>test</servlet-name>
<jsp-file>/test.jsp</jsp-file>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
<security-constraint>
<web-resource-collection>
<web-resource-name>test</web-resource-name>
<description></description>
<url-pattern>/test/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>AuthorizedUser</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>JBoss XACML Test</realm-name>
</login-config>
<security-role>
<role-name>AuthorizedUser</role-name>
</security-role>
</web-app>
The jboss-web.xml will basically define the security domain to be used by this web application.
<!DOCTYPE jboss-web PUBLIC
"-//JBoss//DTD Web Application 2.4//EN"
"http://www.jboss.org/j2ee/dtd/jboss-web_4_0.dtd">
<jboss-web>
<security-domain>java:/jaas/xacml-domain</security-domain>
</jboss-web>
Step 2: Define the security domain configuration in a xxx-jboss-beans.xml (In our case, we will call the file webxacml-jboss-beans.xml)
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="urn:jboss:bean-deployer:2.0">
<application-policy xmlns="urn:jboss:security-beans:1.0" name="xacml-test">
<authentication>
<login-module code = "org.jboss.security.auth.spi.UsersRolesLoginModule"
flag = "required">
</authentication>
<authorization>
<policy-module code="org.jboss.security.authorization.modules.XACMLAuthorizationModule" flag="required" />
</authorization>
</application-policy>
</deployment>
Step 3: Define the JBossXACML configuration file
<ns:jbosspdp xmlns:ns="urn:jboss:xacml:2.0">
<ns:Policies>
<ns:Policy>
<ns:Location>META-INF/jboss-xacml-policy.xml</ns:Location>
</ns:Policy>
</ns:Policies>
<ns:Locators>
<ns:Locator Name="org.jboss.security.xacml.locators.JBossPolicySetLocator"/>
<ns:Locator Name="org.jboss.security.xacml.locators.JBossPolicyLocator"/>
</ns:Locators>
</ns:jbosspdp>
Step 4: Define a standard XACML policy file (jboss-xacml-policy.xml) governing your web application.
<?xml version="1.0" encoding="UTF-8"?>
<Policy xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:oasis:names:tc:xacml:2.0:policy:schema:os
access_control-xacml-2.0-policy-schema-os.xsd"
PolicyId="urn:oasis:names:tc:xacml:2.0:jboss-test:XV:policy"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:deny-overrides">
<Description> Policy for Test XVII. </Description>
<Target/>
<Rule RuleId="urn:oasis:names:tc:xacml:2.0:jboss-test:XVI:rule"
Effect="Permit">
<Description>
jduke can read or write resource information when the request parameter "status"
in Action has a value "employed"
</Description>
<Target>
<Subjects>
<Subject>
<SubjectMatch
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">jduke</AttributeValue>
<SubjectAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id"
DataType="http://www.w3.org/2001/XMLSchema#string"/>
</SubjectMatch>
</Subject>
</Subjects>
<Resources>
<Resource>
<ResourceMatch
MatchId="urn:oasis:names:tc:xacml:1.0:function:anyURI-equal">
<AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#anyURI">/xacml-requestattrib/test</AttributeValue>
<ResourceAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"
DataType="http://www.w3.org/2001/XMLSchema#anyURI"/>
</ResourceMatch>
</Resource>
</Resources>
<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
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
DataType="http://www.w3.org/2001/XMLSchema#string"/>
</ActionMatch>
<ActionMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">employed</AttributeValue>
<ActionAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:2.0:request-param:attribute:status"
DataType="http://www.w3.org/2001/XMLSchema#string"/>
</ActionMatch>
</Action>
<Action>
<ActionMatch
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">write</AttributeValue>
<ActionAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
DataType="http://www.w3.org/2001/XMLSchema#string"/>
</ActionMatch>
<ActionMatch MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">employed</AttributeValue>
<ActionAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:2.0:request-param:attribute:status"
DataType="http://www.w3.org/2001/XMLSchema#string"/>
</ActionMatch>
</Action>
</Actions>
</Target>
</Rule>
</Policy>
Generation of XACML policy files is a tough task in the absence of good xacml policy editors (which unfortunately is the current status in the open source world). Hopefully the future should be better with open source tools propping up for xacml policy editing.
Step 5: Package your web application
Mainly the xml configuration files go into WEB-INF of the web archive (war file).
Step 6: Take a look at the test java code. It is straight web client code (of course, disguised as a JUnit test case). No sign of any xacml related code.
package org.jboss.test.web.security.authorization;
import java.net.HttpURLConnection;
import java.net.URL;
import junit.extensions.TestSetup;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.jboss.test.JBossTestCase;
import org.jboss.test.JBossTestSetup;
import org.jboss.test.util.web.HttpUtils;
/**
* Test the XACML Integration in the Web layer
*/
public class XACMLWebIntegrationUnitTestCase extends JBossTestCase
{
public XACMLWebIntegrationUnitTestCase(String name)
{
super(name);
}
public static Test suite() throws Exception
{
TestSuite suite = new TestSuite();
suite.addTest(new TestSuite(XACMLWebIntegrationUnitTestCase.class));
// Create an initializer for the test suite
TestSetup wrapper = new JBossTestSetup(suite)
{
protected void setUp() throws Exception
{
super.setUp();
deploy("xacml-requestattrib.war");
deploy("xacml-subjectrole.war");
String url = getResourceURL("web/xacml/app-policy-service.xml");
deploy(url);
}
protected void tearDown() throws Exception
{
String url = getResourceURL("web/xacml/app-policy-service.xml");
undeploy(url);
undeploy("xacml-requestattrib.war");
undeploy("xacml-subjectrole.war");
super.tearDown();
}
};
return wrapper;
}
public void testRequestAttributePresence() throws Throwable
{
doTestRequestAttributePresence();
}
public void testSubjectRBAC() throws Throwable
{
doTestSubjectRBAC();
}
/**
* Tests if redeploying causes any side effects.
* It runs the tests again after a redeploy.
*/
public void testRedeploy() throws Throwable
{
//undeploy
String url = getResourceURL("web/xacml/app-policy-service.xml");
undeploy(url);
undeploy("xacml-requestattrib.war");
undeploy("xacml-subjectrole.war");
//deploy again
deploy("xacml-requestattrib.war");
deploy("xacml-subjectrole.war");
deploy(url);
doTestRequestAttributePresence();
doTestSubjectRBAC();
}
private void doTestRequestAttributePresence() throws Throwable
{
URL url = new URL(HttpUtils.getBaseURL()+"xacml-requestattrib/test?status=employed");
HttpUtils.accessURL(url, "JBoss XACML Test", HttpURLConnection.HTTP_OK);
url = new URL(HttpUtils.getBaseURL()+"xacml-requestattrib/test");
HttpUtils.accessURL(url, "JBoss XACML Test", HttpURLConnection.HTTP_FORBIDDEN);
}
private void doTestSubjectRBAC() throws Throwable
{
URL url = new URL(HttpUtils.getBaseURL()+"xacml-subjectrole/test");
HttpUtils.accessURL(url, "JBoss XACML Test", HttpURLConnection.HTTP_OK);
}
}
Use Case 2:
Please reuse the web.xml, jboss-web.xml and jbossxacml-config.xml from use case 1. The test code is the same as above.
<?xml version="1.0" encoding="UTF-8"?>
<Policy xmlns="urn:oasis:names:tc:xacml:2.0:policy:schema:os"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:oasis:names:tc:xacml:2.0:policy:schema:os
access_control-xacml-2.0-policy-schema-os.xsd"
PolicyId="urn:oasis:names:tc:xacml:2.0:jboss-test:XV:policy"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:deny-overrides">
<Description> Policy for Subject RBAC</Description>
<Target/>
<Rule RuleId="urn:oasis:names:tc:xacml:2.0:jboss-test:XVI:rule"
Effect="Permit">
<Description>
jduke can read or write resource information when he has a role of ServletUserRole
</Description>
<Target>
<Subjects>
<Subject>
<SubjectMatch
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">jduke</AttributeValue>
<SubjectAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:1.0:subject:subject-id"
DataType="http://www.w3.org/2001/XMLSchema#string"/>
</SubjectMatch>
<SubjectMatch
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">ServletUserRole</AttributeValue>
<SubjectAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:2.0:subject:role"
DataType="http://www.w3.org/2001/XMLSchema#string"/>
</SubjectMatch>
</Subject>
</Subjects>
<Resources>
<Resource>
<ResourceMatch
MatchId="urn:oasis:names:tc:xacml:1.0:function:anyURI-equal">
<AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#anyURI">/xacml-subjectrole/test</AttributeValue>
<ResourceAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:1.0:resource:resource-id"
DataType="http://www.w3.org/2001/XMLSchema#anyURI"/>
</ResourceMatch>
</Resource>
</Resources>
<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
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
DataType="http://www.w3.org/2001/XMLSchema#string"/>
</ActionMatch>
</Action>
<Action>
<ActionMatch
MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">write</AttributeValue>
<ActionAttributeDesignator
AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
DataType="http://www.w3.org/2001/XMLSchema#string"/>
</ActionMatch>
</Action>
</Actions>
</Target>
</Rule>
</Policy>
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.
Comments