JBoss.orgCommunity Documentation
If a security domain does not define an authorization module, the default jboss-web-policy
and jboss-ejb-policy
authorization configured in security-policies-jboss-beans.xml
is used. If you specify an authorization module, or create a custom deployment descriptor file with valid authorization configuration, these settings override the default settings in security-policies-jboss-beans.xml
.
Overriding the default authorization for EJB or Web components is provided for JACC and XACML, apart from the default modules that implement the specification behavior. Users can provide authorization modules that implement custom behavior. Configuring this functionality allows access control stacks to be pluggable for a particular component, overriding the default authorization contained in jboss.xml
(for EJBs) and jboss-web.xml
(for WAR).
You can override authorization for all EJBs and Web components, or for a particular component.
Procedure 8.1. Set authorization policies for all EJB and WAR components
This procedure describes how to define JACC Authorization control for all EJB and WAR components. The example defines application policy modules for Web and EJB applications: jboss-web-policy
, and jboss-ejb-policy
.
Open the security policy bean
Navigate to $JBOSS_HOME/server/$PROFILE/deploy/security
Open the security-policies-jboss-beans.xml
file.
By default, the security-policies-jboss-beans.xml file contains the configuration in Example 8.1, “security-policies default configuration”
Example 8.1. security-policies default configuration
<?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="jboss-web-policy" extends="other">
<authorization>
<policy-module code="org.jboss.security.authorization.modules.DelegatingAuthorizationModule"
flag="required"/>
</authorization>
</application-policy>
<application-policy xmlns="urn:jboss:security-beans:1.0" name="jboss-ejb-policy" extends="other">
<authorization>
<policy-module code="org.jboss.security.authorization.modules.DelegatingAuthorizationModule"
flag="required"/>
</authorization>
</application-policy>
</deployment>
Change the application-policy definitions
To set a single authorization policy for each component using JACC, amend each <policy-module>
code
attribute with the name of the JACC authorization module.
<?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="jboss-web-policy" extends="other">
<authorization>
<policy-module code="org.jboss.security.authorization.modules.JACCAuthorizationModule" flag="required"/>
</authorization>
</application-policy>
<application-policy xmlns="urn:jboss:security-beans:1.0" name="jboss-ejb-policy" extends="other">
<authorization>
<policy-module code="org.jboss.security.authorization.modules.JACCAuthorizationModule" flag="required"/>
</authorization>
</application-policy>
<application-policy xmlns="urn:jboss:security-beans:1.0" name="jacc-test" extends="other">
<authorization>
<policy-module code="org.jboss.security.authorization.modules.JACCAuthorizationModule" flag="required"/>
</authorization>
</application-policy>
</deployment>
Restart server
You have now configured the security-policy-jboss-beans.xml
file with JACC authorization enabled for each application policy.
Restart the server to ensure the new security policy takes effect.
If applications require more granular security policies, you can declare multiple authorization security policies for each application policy. New security domains can inherit base settings from another application policy, and override specific settings such as the authorization policy module.
Procedure 8.2. Set authorization policies for specific security domains
This procedure describes how to inherit settings from other application policy definitions, and specify different authorization policies per security domain.
In this procedure, two security domains are defined. The test-domain
security domain uses the UsersRolesLoginModule login module and uses JACC authorization. The
test-domain-inherited
security domain inherits the login module information from test-domain
, and specifies XACML authorization must be used.
Open the security policy
You can specify the security domain settings in the login-config.xml
file, or create a deployment descriptor file containing the settings. Choose the deployment
descriptor if you want to package the security domain settings with your application.
Locate and open login-config.xml
Navigate to the login-config.xml
file for the server profile you are using and open the file for editing. For example:
$JBOSS_HOME
/jboss-as/server/$PROFILE/conf/login.config.xml
Create a jboss-beans.xml descriptor
Create a
descriptor, replacing [prefix]
-jboss-beans.xml[prefix]
with a meaningful name (for example, test-war-jboss-beans.xml
)
Save this file in the deploy directory of the server profile you are configuring. For example:
$JBOSS_HOME
/jboss-as/server/$PROFILE/deploy/test-war-jboss-beans.xml
Specify the test-domain security domain
In the target file chosen in step 1, specify the test-domain
security domain. This domain contains the authentication information, including the <login-module>
definition, and the JACC authorization policy module definition.
<?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="test-domain">
<authentication>
<login-module code = "org.jboss.security.auth.spi.UsersRolesLoginModule"
flag = "required">
<module-option name = "unauthenticatedIdentity">anonymous</module-option>
<module-option name="usersProperties">u.properties</module-option>
<module-option name="rolesProperties">r.properties</module-option>
</login-module>
</authentication>
<authorization>
<policy-module code="org.jboss.security.authorization.modules.JACCAuthorizationModule" flag="required"/>
</authorization>
</application-policy>
</deployment>
Append the test-domain-inherited security domain
Append the test-domain-inherited
application policy definition after the test-domain
application policy. Set the extends
attribute to other
, so the login module information is inherited. Specify the XACML authorization module in the <policy.module>
element.
<?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="test-domain">
<authentication>
<login-module code = "org.jboss.security.auth.spi.UsersRolesLoginModule"
flag = "required">
<module-option name = "unauthenticatedIdentity">anonymous</module-option>
<module-option name="usersProperties">u.properties</module-option>
<module-option name="rolesProperties">r.properties</module-option>
</login-module>
</authentication>
<authorization>
<policy-module code="org.jboss.security.authorization.modules.JACCAuthorizationModule" flag="required"/>
</authorization>
</application-policy>
<application-policy xmlns="urn:jboss:security-beans:1.0" name="test-domain-inherited" extends="other">
<authorization>
<policy-module code="org.jboss.security.authorization.modules.XACMLAuthorizationModule" flag="required"/>
</authorization>
</application-policy>
</deployment>
Restart server
You have now configured the target file with two security domains that use different authorization methods.
Restart the server to ensure the new security policy takes effect.
Set authorization policies for all EJB and WAR components and Set authorization policies for specific security domains describe simplistic examples that show how authentication and authorization can be configured in security domains.
Because authorization relates to the type of component (not the layer) you want to protect, you can use delegation within a deployment descriptor to specify different authorization policies to the standard authentication in your implementation.
The delegates must be a subclass of AuthorizationModuleDelegate
. Example 8.2, “AuthorizationModuleDelegate class” describes the base AuthorizationModuleDelegate
interface.
Example 8.2. AuthorizationModuleDelegate class
package org.jboss.security.authorization.modules;
import javax.security.auth.Subject;
import org.jboss.logging.Logger;
import org.jboss.security.authorization.AuthorizationModule;
import org.jboss.security.authorization.PolicyRegistration;
import org.jboss.security.authorization.Resource;
import org.jboss.security.identity.RoleGroup;
//$Id$
/**
* Delegate for Authorization Module
* @author <a href="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a>
* @since Jun 19, 2006
* @version $Revision$
*/
public abstract class AuthorizationModuleDelegate
{
protected static Logger log = Logger.getLogger(AuthorizationModuleDelegate.class);
protected boolean trace = false;
/**
* Policy Registration Manager Injected
*/
protected PolicyRegistration policyRegistration = null;
/**
* @see AuthorizationModule#authorize(Resource)
* @param resource
* @param subject Authenticated Subject
* @param role RoleGroup
* @return
*/
public abstract int authorize(Resource resource, Subject subject, RoleGroup role);
/**
* Set the PolicyRegistration manager
* Will be used to query for the policies
* @param authzManager
*/
public void setPolicyRegistrationManager(PolicyRegistration pm)
{
this.policyRegistration = pm;
}
}
Some examples of authorization delegation are included for reference. Example 8.3, “EJBJACCPolicyModuleDelegate.java” describes an authorization module responsible for authorization decisions for the EJB layer. Example 8.4, “WebJACCPolicyModuleDelegate.java” describes a JACC-based authorization module helper that controls web layer authorization decisions.
Example 8.3. EJBJACCPolicyModuleDelegate.java
package org.jboss.security.authorization.modules.ejb;
import java.lang.reflect.Method;
import java.security.CodeSource;
import java.security.Permission;
import java.security.Policy;
import java.security.Principal;
import java.security.ProtectionDomain;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.jacc.EJBMethodPermission;
import javax.security.jacc.EJBRoleRefPermission;
import org.jboss.logging.Logger;
import org.jboss.security.authorization.AuthorizationContext;
import org.jboss.security.authorization.PolicyRegistration;
import org.jboss.security.authorization.Resource;
import org.jboss.security.authorization.ResourceKeys;
import org.jboss.security.authorization.modules.AbstractJACCModuleDelegate;
import org.jboss.security.authorization.modules.AuthorizationModuleDelegate;
import org.jboss.security.authorization.resources.EJBResource;
import org.jboss.security.identity.Role;
import org.jboss.security.identity.RoleGroup;
//$Id$
/**
* Authorization Module delegate that deals with the authorization decisions
* for the EJB Layer
* @author <a href="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a>
* @since Jul 6, 2006
* @version $Revision$
*/
public class EJBJACCPolicyModuleDelegate extends AbstractJACCModuleDelegate
{
private String ejbName = null;
private Method ejbMethod = null;
private String methodInterface = null;
private CodeSource ejbCS = null;
private String roleName = null;
private Boolean roleRefCheck = Boolean.FALSE;
public EJBJACCPolicyModuleDelegate()
{
log = Logger.getLogger(getClass());
trace = log.isTraceEnabled();
}
/**
* @see AuthorizationModuleDelegate#authorize(Resource)
*/
public int authorize(Resource resource, Subject callerSubject, RoleGroup role)
{
if(resource instanceof EJBResource == false)
throw new IllegalArgumentException("resource is not an EJBResource");
EJBResource ejbResource = (EJBResource) resource;
//Get the context map
Map<String,Object> map = resource.getMap();
if(map == null)
throw new IllegalStateException("Map from the Resource is null");
this.policyRegistration = (PolicyRegistration) map.get(ResourceKeys.POLICY_REGISTRATION);
this.ejbCS = ejbResource.getCodeSource();
this.ejbMethod = ejbResource.getEjbMethod();
this.ejbName = ejbResource.getEjbName();
this.methodInterface = ejbResource.getEjbMethodInterface();
//isCallerInRole checks
this.roleName = (String)map.get(ResourceKeys.ROLENAME);
this.roleRefCheck = (Boolean)map.get(ResourceKeys.ROLEREF_PERM_CHECK);
if(this.roleRefCheck == Boolean.TRUE)
return checkRoleRef(callerSubject, role);
else
return process(callerSubject, role);
}
//Private Methods
/**
* Process the request
* @param request
* @param sc
* @return
*/
private int process(Subject callerSubject, Role role)
{
EJBMethodPermission methodPerm =
new EJBMethodPermission(ejbName, methodInterface, ejbMethod);
boolean policyDecision = checkWithPolicy(methodPerm, callerSubject, role);
if( policyDecision == false )
{
String msg = "Denied: "+methodPerm+", caller=" + callerSubject+", role="+role;
if(trace)
log.trace("EJB Jacc Delegate:"+msg);
}
return policyDecision ? AuthorizationContext.PERMIT : AuthorizationContext.DENY;
}
private int checkRoleRef(Subject callerSubject, RoleGroup callerRoles)
{
//This has to be the EJBRoleRefPermission
EJBRoleRefPermission ejbRoleRefPerm = new EJBRoleRefPermission(ejbName,roleName);
boolean policyDecision = checkWithPolicy(ejbRoleRefPerm, callerSubject, callerRoles);
if( policyDecision == false )
{
String msg = "Denied: "+ejbRoleRefPerm+", caller=" + callerSubject;
if(trace)
log.trace("EJB Jacc Delegate:"+msg);
}
return policyDecision ? AuthorizationContext.PERMIT : AuthorizationContext.DENY;
}
private boolean checkWithPolicy(Permission ejbPerm, Subject subject, Role role)
{
Principal[] principals = this.getPrincipals(subject, role);
ProtectionDomain pd = new ProtectionDomain (ejbCS, null, null, principals);
return Policy.getPolicy().implies(pd, ejbPerm);
}
}
Example 8.4. WebJACCPolicyModuleDelegate.java
package org.jboss.security.authorization.modules.web;
import java.io.IOException;
import java.security.CodeSource;
import java.security.Permission;
import java.security.Policy;
import java.security.Principal;
import java.security.ProtectionDomain;
import java.util.Map;
import java.util.Set;
import javax.security.auth.Subject;
import javax.security.jacc.WebResourcePermission;
import javax.security.jacc.WebRoleRefPermission;
import javax.security.jacc.WebUserDataPermission;
import javax.servlet.http.HttpServletRequest;
import org.jboss.logging.Logger;
import org.jboss.security.authorization.AuthorizationContext;
import org.jboss.security.authorization.PolicyRegistration;
import org.jboss.security.authorization.Resource;
import org.jboss.security.authorization.ResourceKeys;
import org.jboss.security.authorization.modules.AbstractJACCModuleDelegate;
import org.jboss.security.authorization.modules.AuthorizationModuleDelegate;
import org.jboss.security.authorization.resources.WebResource;
import org.jboss.security.identity.Role;
import org.jboss.security.identity.RoleGroup;
//$Id: WebJACCPolicyModuleDelegate.java 62923 2007-05-09 03:08:14Z anil.saldhana@jboss.com $
/**
* JACC based authorization module helper that deals with the web layer
* authorization decisions
* @author <a href="mailto:Anil.Saldhana@jboss.org">Anil Saldhana</a>
* @since July 7, 2006
* @version $Revision: 62923 $
*/
public class WebJACCPolicyModuleDelegate extends AbstractJACCModuleDelegate
{
private Policy policy = Policy.getPolicy();
private HttpServletRequest request = null;
private CodeSource webCS = null;
private String canonicalRequestURI = null;
public WebJACCPolicyModuleDelegate()
{
log = Logger.getLogger(WebJACCPolicyModuleDelegate.class);
trace = log.isTraceEnabled();
}
/**
* @see AuthorizationModuleDelegate#authorize(Resource)
*/
@SuppressWarnings("unchecked")
public int authorize(Resource resource, Subject callerSubject, RoleGroup role)
{
if(resource instanceof WebResource == false)
throw new IllegalArgumentException("resource is not a WebResource");
WebResource webResource = (WebResource) resource;
//Get the context map
Map<String,Object> map = resource.getMap();
if(map == null)
throw new IllegalStateException("Map from the Resource is null");
//Get the Request Object
request = (HttpServletRequest) webResource.getServletRequest();
webCS = webResource.getCodeSource();
this.canonicalRequestURI = webResource.getCanonicalRequestURI();
String roleName = (String)map.get(ResourceKeys.ROLENAME);
Principal principal = (Principal)map.get(ResourceKeys.HASROLE_PRINCIPAL);
Set<Principal> roles = (Set<Principal>)map.get(ResourceKeys.PRINCIPAL_ROLES);
String servletName = webResource.getServletName();
Boolean resourceCheck = checkBooleanValue((Boolean)map.get(ResourceKeys.RESOURCE_PERM_CHECK));
Boolean userDataCheck = checkBooleanValue((Boolean)map.get(ResourceKeys.USERDATA_PERM_CHECK));
Boolean roleRefCheck = checkBooleanValue((Boolean)map.get(ResourceKeys.ROLEREF_PERM_CHECK));
validatePermissionChecks(resourceCheck,userDataCheck,roleRefCheck);
boolean decision = false;
try
{
if(resourceCheck)
decision = this.hasResourcePermission(callerSubject, role);
else
if(userDataCheck)
decision = this.hasUserDataPermission();
else
if(roleRefCheck)
decision = this.hasRole(principal, roleName, roles, servletName);
else
if(trace)
log.trace("Check is not for resourcePerm, userDataPerm or roleRefPerm.");
}
catch(IOException ioe)
{
if(trace)
log.trace("IOException:",ioe);
}
return decision ? AuthorizationContext.PERMIT : AuthorizationContext.DENY;
}
/**
* @see AuthorizationModuleDelegate#setPolicyRegistrationManager(PolicyRegistration)
*/
public void setPolicyRegistrationManager(PolicyRegistration authzM)
{
this.policyRegistration = authzM;
}
//****************************************************************************
// PRIVATE METHODS
//****************************************************************************
/** See if the given JACC permission is implied using the caller as
* obtained from either the
* PolicyContext.getContext(javax.security.auth.Subject.container) or
* the info associated with the requestPrincipal.
*
* @param perm - the JACC permission to check
* @param requestPrincpal - the http request getPrincipal
* @param caller the authenticated subject obtained by establishSubjectContext
* @return true if the permission is allowed, false otherwise
*/
private boolean checkPolicy(Permission perm, Principal requestPrincpal,
Subject caller, Role role)
{
// Get the caller principals, its null if there is no caller
Principal[] principals = getPrincipals(caller,role);
return checkPolicy(perm, principals);
}
/** See if the given permission is implied by the Policy. This calls
* Policy.implies(pd, perm) with the ProtectionDomain built from the
* active CodeSource set by the JaccContextValve, and the given
* principals.
*
* @param perm - the JACC permission to evaluate
* @param principals - the possibly null set of principals for the caller
* @return true if the permission is allowed, false otherwise
*/
private boolean checkPolicy(Permission perm, Principal[] principals)
{
ProtectionDomain pd = new ProtectionDomain(webCS, null, null, principals);
boolean allowed = policy.implies(pd, perm);
if( trace )
{
String msg = (allowed ? "Allowed: " : "Denied: ") +perm;
log.trace(msg);
}
return allowed;
}
/**
* Ensure that the bool is a valid value
* @param bool
* @return bool or Boolean.FALSE (when bool is null)
*/
private Boolean checkBooleanValue(Boolean bool)
{
if(bool == null)
return Boolean.FALSE;
return bool;
}
/**
* Perform hasResourcePermission Check
* @param request
* @param response
* @param securityConstraints
* @param context
* @param caller
* @return
* @throws IOException
*/
private boolean hasResourcePermission(Subject caller, Role role)
throws IOException
{
Principal requestPrincipal = request.getUserPrincipal();
WebResourcePermission perm = new WebResourcePermission(this.canonicalRequestURI,
request.getMethod());
boolean allowed = checkPolicy(perm, requestPrincipal, caller, role );
if( trace )
log.trace("hasResourcePermission, perm="+perm+", allowed="+allowed);
return allowed;
}
/**
* Perform hasRole check
* @param principal
* @param role
* @param roles
* @return
*/
private boolean hasRole(Principal principal, String roleName,
Set<Principal> roles, String servletName)
{
if(servletName == null)
throw new IllegalArgumentException("servletName is null");
WebRoleRefPermission perm = new WebRoleRefPermission(servletName, roleName);
Principal[] principals = {principal};
if( roles != null )
{
principals = new Principal[roles.size()];
roles.toArray(principals);
}
boolean allowed = checkPolicy(perm, principals);
if( trace )
log.trace("hasRole, perm="+perm+", allowed="+allowed);
return allowed;
}
/**
* Perform hasUserDataPermission check for the realm.
* If this module returns false, the base class (Realm) will
* make the decision as to whether a redirection to the ssl
* port needs to be done
* @param request
* @param response
* @param constraints
* @return
* @throws IOException
*/
private boolean hasUserDataPermission() throws IOException
{
WebUserDataPermission perm = new WebUserDataPermission(this.canonicalRequestURI,
request.getMethod());
if( trace )
log.trace("hasUserDataPermission, p="+perm);
boolean ok = false;
try
{
Principal[] principals = null;
ok = checkPolicy(perm, principals);
}
catch(Exception e)
{
if( trace )
log.trace("Failed to checkSecurityAssociation", e);
}
return ok;
}
/**
* Validate that the access check is made only for one of the
* following
* @param resourceCheck
* @param userDataCheck
* @param roleRefCheck
*/
private void validatePermissionChecks(Boolean resourceCheck,
Boolean userDataCheck, Boolean roleRefCheck)
{
if(trace)
log.trace("resourceCheck="+resourceCheck + " : userDataCheck=" + userDataCheck
+ " : roleRefCheck=" + roleRefCheck);
if((resourceCheck == Boolean.TRUE && userDataCheck == Boolean.TRUE && roleRefCheck == Boolean.TRUE )
|| (resourceCheck == Boolean.TRUE && userDataCheck == Boolean.TRUE)
|| (userDataCheck == Boolean.TRUE && roleRefCheck == Boolean.TRUE))
throw new IllegalStateException("Permission checks must be different");
}
}