站内搜索: 请输入搜索关键词
当前页面: 在线文档首页 > JBoss Portal 2.2 Reference Guide 英文版参考指南文档

Chapter 5. Security - JBoss Portal 2.2 Reference Guide 英文版参考指南文档

Chapter 5. Security

Thomas Heute

Martin Holzner

New in version 2.2, the portal features role based access control for all portal resources. The definition of security constraints is strait forward and simple. Each portal resource can define zero, one, or more security constraints, each binding a role to the allowed actions for the role and resource. For more details on how to secure portal resources take a look at security section in the user guide.

5.1. Portal Security Configuration

Portal security is governed by a set of portal policy configurations. Policy configurations can be created for different permission types, and accessed via the policy configuration service. The policy configuration maintains a set of security constraints, keyed by permission type and uri of the resource.

5.1.1. org.jboss.portal.security.config.SecurityConstraint

                    // create a new constraint
                    SecurityConstraint constraint = new SecurityConstraint("view,read","Admin");

                    // get the allowed actions as a set of strings
                    Set allowedActions = constraint.getActions();

                    // get the role this constraint is assigned to
                    String allowedRole = constraint.getRole();
                

Security constraints are the state holder of what role is allowed to execute what actions on a given resource. They are managed via a policy configuration. One policy configuration can be defined for each permission type.

Permissions are currently separated into 3 valid types:

  • component
  • instance
  • portalobject

5.1.2. org.jboss.portal.security.config.PortalPolicyConfig

The policy configuration maintains the constraint information for one permission type.

                    PortalPolicyConfig config = null;
                    //.... get the config from the config service (see below)
                    String uri = portalResourceHandle;
                    Set constraints = config.getConstraints(uri);
                

5.1.3. org.jboss.portal.security.config.PortalPolicyConfigService

The policy configuration service is the root access point for configuration information. All active policy configurations are registered with this service, and can be accessed from here via their permission type.

                    import org.jboss.portal.security.config.PortalPolicyConfigService;
                    import org.jboss.portal.security.config.PortalPolicyConfig;
                    import org.jboss.portal.core.security.PermissionTypes;

                    PortalPolicyConfigService configService = null;
                    // configService = ... lookup the configService from the mbean server

                    // get the policy config for all portlet instances
                    PortalPolicyConfig instanceConfig = configService.getConfig(PermissionTypes.INSTANCE);
                    PortalPolicyConfig portalObjectConfig = configService.getConfig(PermissionTypes.PORTAL_OBJECT);
                

5.1.4. org.jboss.portal.security.config.ConfigListener

The policy configuration listener registers with the policy configuration, and listens to added, removed, and modified events. Each change of the security constraints maintained in a policy configuration is propagated to this listener. The listener builds the bridge to any security enforcement infrastructure.

The default implementation of the enforcement infrastructure is based in the Java Authorization Contract for Containers (JACC). It is implemented as a policy configuration listener that reacts to configuration change events, and populates the JACC policy with permissions that are created based on the security constraints propagated by the change events.

5.2. Portal Security Enforcement

5.2.1. org.jboss.portal.security.PortalPermission

The defined security constraints are enforced via portal permissions. The default security implementation that comes with the portal contains a policy configuration listener that converts the constraint information into portal permissions, and populates a JACC (Java Authorization Contract for Containers) based security policy with them.

The configured constraints are enforced via an interceptor in the server invocation stack. For each request to the portal it creates a new portal permission to check access rights. The created permission contains the requested resource and action. The permission is passed to the portal policy, together with the portal subject to check if the permission is implied in the policy. Access will be granted if one of the security constraints in the policy configurations implies the provided check permission.

A factory is provided to create portal permissions. The PortalPermissionFactory is an interface that is implemented as an mbean, and can be injected wherever needed.

                    import org.jboss.portal.security.PortalPermission;
                    import org.jboss.portal.security.PortalPermissionFactory;
                    import org.jboss.portal.core.security.PermissionTypes;

                    PortalPermissionFactory portalPermissionFactory = ...;
                    PortalPermission componentPerm = portalPermissionFactory.createPermission(PermissionTypes.COMPONENT, uri, "view");
                

5.2.2. org.jboss.portal.security.PortalPolicy

The portal policy is the interface that is being used to check if access to a requested resource is granted. It is made available as a thread local property throughout the lifetime of a portal request. The implementation of the policy is injected via a server invocation aspect (PolicyAssociationInterceptor). This interceptor gets the policy via the implementation of the PortalPolicyService. Here is the code to get to the portal policy:

                    import org.jboss.portal.security.PolicyAssociation;
                    import org.jboss.portal.security.PortalPolicy;

                    PortalPolicy policy = PolicyAssociation.getPolicy();
                

5.2.3. org.jboss.portal.security.PortalSubject

The portal subject represents the current user. Similar to the portal policy, it is made available for the lifetime of the portal request as a thread local property, which is injected by a server invocation aspect. Here is the code to get to the portal policy:

                    import org.jboss.portal.security.SubjectAssociation;
                    import org.jboss.portal.security.PortalSubject;

                    PortalSubject subject = SubjectAssociation.getSubject();
                

5.2.4. Portal Policy Enforcement

All the described pieces above taken together make up the security enforcement infrastructure. The remaining call to determine wether access is granted or not is:

                    if (policy.implies(subject, permission)){
                        // ....do something....
                

5.3. Default Security Implementation

The default implementation of the security APIs is based on the Java Authorization Contract for Containers (JACC).

5.3.1. What is JACC

JACC is part of the J2EE specification, and defines a way for the servlet and ejb containers to secure web resources and ejbs with a role based model.

5.3.2. JACC Policy and Policy Configuration

1. javax.security.jacc.PolicyConfigurationFactory

The policy configuration factory is an abstract singleton that serves as the access point for policy configurations. It features a static accessor to get the factory implementation.

                            public static PolicyConfigurationFactory getPolicyConfigurationFactory()
                               throws ClassNotFoundException, PolicyContextException
                            {
                                ....
                            }
                        

The policy configuration factory to load can be specified in a VM system property (-D) "javax.security.jacc.PolicyConfigurationFactory.provider". The default implementation that will be loaded if nothing else is defined, is org.jboss.security.jacc.JBossPolicyConfigurationFactory.

2. javax.security.jacc.PolicyConfiguration

The policy configuration interface is the access point for all configured permissions of one context id. It allows to manipulate the content of the security policy (see below) which is the ultimate policy decission point. In the standard J2EE model, a context id is equivalent to the deployed context: the war or ejb archive. In the case of JBoss portal, this model was extended to allow a more flexible definition of the context id. The default implementation of the portal's JBossSecurityProvider (see below) creates a separate context id for each portal resource. This allows the portal to reload the content of a specific portal resources without having to refresh any of the other resource's security attributes.

3. javax.security.jacc.Policy

The jacc policy is the ultimate policy decission point. It makes the decission wether a permission is implied or not. To make this decission it can do whatever is needed. The default implementation (org.jboss.security.jacc.DelegatingPolicy) delegates the decission to the policy context, which in turn delegates it to the java.security.Permissions that make up all configured permissions for a given role in the requested policy context.

4. org.jboss.portal.security.jacc.SecurityProvider

The portal security provider interface wrapps the functionality in the jacc PolicyConfigurationFactory. It allows access to all available policy configurations. It also offers a method the check wether a particular policy context is in service or not. The jacc policy singleton is also available via this interface.

                            // check if the provided policy context id is available
                            boolean inService(String policyContextID) throws PolicyContextException;
                            // get the policy configuration for the provided policy context id
                            PolicyConfiguration getPolicyConfiguration(String contextID, boolean remove) throws PolicyContextException;
                            // get the jacc policy singleton
                            Policy getPolicy();
                        

5. org.jboss.portal.security.jacc.JBossSecurityProvider

The jboss security provider extends the portal security provider, and adds access to the server configuration. This additional access allows a provider implementation to consider server configuration properties when making a decission about any of the policy context calls.

                            // get the portal server configuration
                            ServerConfig getServerConfig();
                        

5.3.3. Portal Policy and Policy Service

1. org.jboss.portal.security.PortalPolicyService

The portal policy service is the root service from where one can get access to the portal policy. The default implementation of this service interface (org.jboss.portal.security.impl.jacc.PortalPolicyServiceImpl) is an mbean. It uses the implementation of the JBossSecurityProvider interface to get to the jacc policy singleton. The security provider interface is a wrapper of the jacc PolicyConfigurationFactory. It's implementation delegates all calls to the standard jacc PolicyConfigurationFactory.

The PortalPolicyService exposes only one method:

                            PortalPolicy getPolicy();
                        

2. org.jboss.portal.security.PortalPolicy

The portal policy has only one method:

                            boolean implies(PortalSubject subject, PortalPermission permission);
                        

The default implementation of the portal policy, an inner class of the policy service implementation, (org.jboss.portal.security.impl.jacc.PortalPolicyServiceImpl$PortalPolicyImpl), uses the security provider to gain access to the portal policy implementation. It uses the JaccHelper class in the same package to determine the java.security.ProtectionDomain and the policy context id before calling the jacc policy to do the actual permission check.

5.3.4. Who is asking?

The remaining piece in the puzzle is the identity. How does the portal determine what user and ultimately what roles to check the access for?

5.3.4.1. The Jacc Portal Subject

As described above, the portal injects the org.jboss.portal.security.PortalSubject as a thread local property that is available throughout the portal request. The default implementation of this portal subject (org.jboss.portal.security.impl.jacc.JaccPortalSubject) wraps the jacc way of getting to the authenticated java.security.Subject, and reading the role memberships off of it. In other words: the mechanism of getting the subject and the subjects roles is identical to the way the application server id handling this security aspect.

5.4. Write your own Security Implementation

As you can probably see above, there are many ways to plug into this infrastructure and adapt it to your needs. You will encounter the least amount of work if you plugin at the JACC layer. All you need to do is provide your own implementation of the JACC policy. All the rest of the infrastructure can stay as is. If you don't want to stay with JACC as your security provider, it will require you to do some more work, depending on how far you want to get away from JACC. To implement a security layer without any JACC artifacts, you'll need to provide the policy configuration lister, the policy enforcement interceptor and the policy and subject interceptors. Let's look at this in more detail.

5.4.1. Overwriting the JACC policy

5.4.1.1. Write the Policy class

As already mentioned above, the easiest way to get your own behavior for the portal authorization, you can provide your own implementation of the JACC policy. To do so, you'll need to create a class that extends java.security.Policy, and overwrites the implies method. Be aware that the portal goes beyond the JACC specification in that it allows new permission classes, other then the 5 predefined classes from the specification. All permissions used by the portal extend the abstract org.jboss.portal.security.PortalPermission class, which in turn extends java.security.Permission. The currently (as of 2.2) implemented permission classes are ComponentPermission, InstancePermission, and PortalObjectPermission. Your policy implementation can distinguish those permissions, and handle them differently if it so desires.

For an example on how to implement your own, take a look at the portal's default policy implementation. The class is org.jboss.portal.security.impl.jacc.PortalJaccPolicy. This policy is basically a copy of the application servers DelegatingPolicy class. The idea behind it is that the portal policy is stacked ontop of the J2SE policy, configured in the VM. The portal policy will handle authorization checks for all the allowed JACC permissions (for ejb and servlet/jsp calls), In addition to the basic J2SE permission types. It allows to configure external permissions that will be treated just like the basic JACC permissions. If the incoming permission to check is an instance of any of the five JACC permission classes, or one of the configured external permission classes, the policy will handle the implies check, otherwise it will delegate to the J2SE policy that was in place in the VM, before the portal policy was created. Remember that the java security model allows only one policy to be active in the VM at any given time. By stacking the policies there is a way to have several policies active with only one policy configured at the VM level.

It is up to your implementation if you want to copy this behavior of configurable external permissions and stacked policies or not. You could implement a flat policy that treats all permissions the same, but be aware that since your policy will take the place of the only policy in the system, that all policy decissions will be coming into your policy. So all security checks by the J2SE SecurityManager will have to be handled by your policy as well.

One strange anomalie that is currently built into the portal is the fact that your policy needs to adhere to a naming convention. There needs to be a method that is used by the policy service to pick up the policy instance. Your policy needs to provide a method with the following signature: (Note: the method signature is not enforced by any interface or abstract class, since the origin of this requirement is a workaround for an underlying problem with the policy configuration and redeployments of the portal sar):

                        public Policy getPolicyProxy()
                    

You can return 'this' , or any decorator class of your policy that would allow you to restrict the externally available functionality of the policy.

5.4.1.2. Configure the Policy to be used by the Portal

The policy implementation must be an mbean. It is injected into the policy service mbean to make it available to other interested parties. Take a look at the jboss-service.xml in the jboss-portal.sar (in the meta-inf folder). The mbean definition for the "portal:service=SecurityProvider" injects the "jboss.security:service=JaccPolicyProvider" via the PolicyName attribute. In other words: the service that is configured as "jboss.security:service=JaccPolicyProvider" needs to expose a method as described above, that returns an implementation of the java.security.Policy interface (public Policy getPolicyProxy(){...}). This method will be called by the SecurityProvider service at startup to read the configured policy from the mbean server. Here is the section defining the jacc policy from the jboss-service.xml:

                        
                        <mbean
                           code="org.jboss.portal.security.impl.jacc.PortalJaccPolicy"
                           name="jboss.security:service=JaccPolicyProvider"
                           xmbean-dd="org/jboss/portal/security/impl/jacc/PortalJaccPolicy.xml">
                           <attribute name="ExternalPermissionTypes">
                              org.jboss.portal.core.security.PortalObjectPermission,
                              org.jboss.portal.core.security.InstancePermission,
                              org.jboss.portal.core.security.ComponentPermission
                           </attribute>
                        </mbean>
                        
                    

And here is the section defining the jacc security provider service, and injecting the policy via the policy proxy attribute:

                        
                        <mbean
                           code="org.jboss.portal.security.impl.jacc.JBossSecurityProviderImpl"
                           name="portal:service=SecurityProvider"
                           xmbean-dd="">
                              <xmbean>
                                 ...more descriptor info here...
                              </xmbean>
                              <attribute name="PolicyName">jboss.security:service=JaccPolicyProvider</attribute>
                              <attribute name="PolicyAttributeName">PolicyProxy</attribute>
                        </mbean>
                        
                    

Note: If there is no policy mbean active for the defined PolicyName and PolicyAttributeName in the SecurityProvider mbean, the policy currently set in the VM will be used instead. The policy will be determined via:

                        import java.security.Policy;
                        Policy policy = Policy.getPolicy();
                    

If your policy extends PortalJaccPolicy a new instance will be created everytime the portal starts. This instance will not be set as the VM wide policy, leaving the original policy in place. In other words: Policy.getPolicy() will not return your policy. To get to your policy, you'll have to lookup the portal security provider, and get it from there.

                        JBossSecurityProvider provider = ....;
                        Policy policy = provider.getPolicy();
                    

You could of course go even further and replace the implementation of the security provider itself. That way, you can decide how to get to the policy in whatever way.

Note that the current implementation is more complex than it should be. This is due to problems in the application server's JACC policy implementation. Once those problems are fixed, the portal's implementation will be simplified. Effectively: the portal should be able to just get the current policy in the VM, (Policy p = Policy.getPolicy();) and use it. The policy would still have to be configured with the external permissions (PortalPermission classes) to treat them like JACC permissions, and not delegate the permission check to the underlying J2SE policy.

5.4.2. A Security implementation without JACC

As already mentioned before, implementing an authorization solution for the portal without the use of JACC all together is a bit harder. The default implementation relies havily on many of the JACC concepts. You will have to replace all of them, but it is possible.

5.4.2.1. The ConfigListener

To start, you'll need to change the way the security constraint information is converted into permissions. Or perhaps you wouldn't even want to convert them, and use the PortalPolicyConfigService and the PortalPolicyConfig as your one and only store of permission information. If you decide to create your own system of storing and enforcing permissions, you'll have to implement the org.jboss.portal.security.config.ConfigListener interface, and register it with the PortalPolicyConfig(s) you are interested in. Look at the org.jboss.portal.security.impl.JBossPortalPolicyConfigStoreImpl as an example of how this can be done. This is an mbean that injects the ConfigListener via an attribute (depends optional-attribute-name="ConfigListener"). If you take a look at the jboss-service.xml you'll see that this mbean is used three times, and each time a config listener is injected. The three mbeans represent three different policy configurations, and the same service (portal:policy=JaccPortalPolicyConfigurator) registers with all three of them as a ConfigListener. You would have to replace the implementation of the policy configurator (portal:policy=JaccPortalPolicyConfigurator) and configure the three instances of JBossPortalPolicyConfigStoreImpl to register your config listener instead. Your config listener can do whatever you desire. Just keep in mind that the result needs to be accessible for the policy enforcement.

5.4.2.2. Policy Enforcement

Policy enforcement is initiated via the PolicyEnforcementInterceptor in the server invocation stack. This interceptor uses the results of two other interceptors:

  • PolicyAssociationInterceptor
  • SubjectAssociationInterceptor

These two interceptors inject the PortalSubject and the PortalPolicy as thread local properties. The policy enforcement interceptor creates a permission based on the requested resource and action, and checks the portal policy to see if the permission implies for the determined portal subject.

You would probably keep the concept of the subject around since this is what the JAAS login module populates with the authentication information from the login process. The portal policy is what is more interesting. Your ConfigListener will populate some store with the constraint information, and that store needs to be made available to the policy enforcement side. The way to do this is via the portal policy from the PolicyAssociationInterceptor. To inject your own implementation of the PortalPolicy interface, you can provide your own version of the PortalPolicyService interface. The default implementation is an mbean that is injected into the PolicyAssociationInterceptor. Write your own version of the PortalPolicyService and configure it in the jboss-service.xml, replacing the default PortalPolicyServiceImpl. Of course you could go even further and replace the PolicyAssociationInterceptor itself no make it independent from the PortalPolicyService. The important thing is that your implementation of the PortalPolicy needs to utilize what your ConfigListener stored before.

For completeness sake, let's take a look at the SubjectAssociationInterceptor as well. It is responsible for injecting the PortalSubject. The PortalSubleject is a flagging interface (has no methods), and the default implementation (JaccPortalSubject) is simply newed up every time the SubjectAssociationInterceptor is invoked. The PortalSubject is later on used by the PortalPolicy to check if a given PortalPermission implies for the given PortalSubject.