Friday, July 23, 2010

Oracle Entitlements Server and Spring Integration Running on JBOSS 5.1

This post is a continuation of the discussion of how to get the "hypothetical" OES+SPRING integration working on an actual platform - in this case JBOSS. This post assumes that you've already got the Java SM running inside of JBOSS 5.1. This post will focus on the technical details of the OES Spring integration and how to extend the JBOSS environment to run a sample application.

Identifying the User


In the "hypothetical" OES-Spring integrtaion post, I said that it was a fairly solved problem to figure out who the user is making the request, and this largely turned out to be true for the OES-Spring integration. I decied to make this part of the model "pluggable" and extended the AuthorizationAspect to use Spring to find an instance of the ISecurityContext interface. This is the ISecurityContext interface:

package com.oracle.oes.springaop.aspect.spi;

import com.bea.security.*;

public interface ISecurityContext {

public AuthenticIdentity getAuthenticIdentity() throws Exception;
public AuthorizationService getAuthorizationService() throws Exception;
public AuthenticationService getAuthenticationService() throws Exception;

}


It seemed logical to bundle the AuthenticIdentity and the Authorization/Authentication Services of the Java SM together. In theory, I guess you could have separarte provides of the AuthorizationService and AuthenticIdentity, but simpler is better.

Now when it came down to providing an implemenation for JBOSS, I tried the standarda Java Security - Subject.getSubject(AccessController.getAccessControllContext()) - but that didn't seem to work. Instead, the JACC Policy Context seemed to do the trick. The JBOSS Security FAQ reveals that you can use the key javax.security.auth.Subject.container to get the current subject. Very nice. Unfortunately, this subject is not acceptable by the default WLS.Subject identity asserter, so I needed a way to get an identity from the subject. Here, I went with my good friend the UsernameIdentityAsserter that ships with the product. I pull the name from the Subject and assert it. I think that a "better" implementation would be one that takes the Subject as the token. Under the covers it could still just assert the username, but it could also make use of the JBOSS roles that are included. This is a pretty simple excercise, but again for simplicity and time sake, I just went with the UsernameIdentityAsserter.

This covered the case where there actually was a user, but what about when the Spring Context is getting loaded by the container? This method returns null. I decided that the simplest thing to do was to configure the implementation of the JBOSS ISecurityContext with a username/password of a user and use that user. There are probably better implementations like - to not have the OES Authorization aspect make any calls when the container is initializing OR use something more like a run-as identity, but this was simple to do. I encourage people to try other alternatives.

Here's the relevant code:

public AuthenticIdentity getAuthenticIdentity() throws Exception {

Subject subject = (Subject)javax.security.jacc.PolicyContext.getContext("javax.security.auth.Subject.container");
System.out.println("Subject="+subject);


if (subject==null) {


System.out.println("I'll try to login with "+this.defaultUser+" "+this.defaultPassword);
AuthenticationHandler handler = new AuthenticationHandler(this.defaultUser,this.defaultPassword);

return this.getAuthenticationService().authenticate(handler);

}

//Just get the 1st principal's name

String name = ((Principal)subject.getPrincipals().iterator().next()).getName();

return this.getAuthenticationService().assertIdentity("USERID_TOKEN", name );

}

I pulled all of this together into a separate POM (oes.jboss.spring.securitycontext) that also includes the Spring configuration. The only thing interesting is that this is is where the username and password for the administration user are specified

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

<bean name="securityContext" class="com.oracle.security.entitlements.jbosssecuritycontext.JBOSSSecurityContext">
<property name="defaultUser">
<value>admin</value>
</property>
<property name="defaultPassword">
<value>password</value>
</property>
</bean>

</beans>

Since we're using the OES API, this user is going to be authenticated by OES (not JBOSS).

Adding Spring AOP to JBOSS Web Application


I don't want to dwell on this too much, but in pulling this sample together, I did stumble in getting the LTW to work. With eough googling, you find that you need project Snowdrop. So, instead of using the default loadtime weaver, you use the one from Snowdrop

<context:load-time-weaver weaver-class="org.jboss.instrument.classloading.JBoss5LoadTimeWeaver"/>

Building the oes-spring project


I continue to be very impressed with Maven - (I know - what took me so long), but it really made putting this thing together incredible simple. You can build the project from the version-1.0 tag from the subversion repository. The project is a collection of the following modules:

  • oes_spring_aop - The core annotations and aspects of the Spring/OES/AOP integration
  • oes_spring_aop_test - A test application and "dummy" ISecurityContext that demonstrates the OES annotations
  • oes.jboss.spring.securitycontext - The ISecurityContext implementation for JBOSS
  • jboss-sample-web - A sample web-application that shows the oes_spring_aop_test application run inside of a web-application running on JBOSS

Configuring JBOSS for running jboss-sample-web


There is a little bit of set-up that is required in order to run the jboss-sample-webapplication.

  • Modify run_with_oes.conf - The JBOSS start script needs to be modified to include the -javaagent setting to enable the Spring LTW.

    if [ "x$JAVA_OPTS" = "x" ]; then
    JAVA_OPTS="-Xms128m -Xmx512m -XX:MaxPermSize=256m -Dorg.jboss.resolver.warning=true -Dsun.rmi.dgc.client.gcInterval=3600000 -Dsun.rmi.dgc.server.gcInterval=3600000 -javaagent:/path to spring/spring-framework-2.5.6.SEC02/dist/weaving/spring-agent.jar $JAVA_OPTIONS"
    fi

    You can either reference the spring-agent.jar from the repository or download it from springsource
  • Modify the server/default/conf/login-config.xml - The JBOSS web-app is protected with JEE security. The application requires the user to be in the role oes_users role. You can do this by configuring JBOSS to use simple files to define users and their passwords, and users and their roles.

    <application-policy name="other">
    <!--
    A simple server login module, which can be used when the number
    of users is relatively small. It uses two properties files:
    users.properties, which holds users (key) and their password (value).
    roles.properties, which holds users (key) and a comma-separated list of
    their roles (value).
    The unauthenticatedIdentity property defines the name of the principal
    that will be used when a null username and password are presented as is
    the case for an unuathenticated web client or MDB. If you want to
    allow such users to be authenticated add the property, e.g.,
    unauthenticatedIdentity="nobody"
    -->
    <authentication>
    <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule"
    flag="optional">
    <module-option name="usersProperties">oes-users.properties</module-option>
    <module-option name="rolesProperties">oes-roles.properties</module-option>
    <module-option name="unauthenticatedIdentity">anonymous</module-option>
    </login-module>
    </authentication>
    </application-policy>

    Put the oes-users.properties and oes-roles.properties in the same directory as login-config.xml. For example:
    oes-users.properties
    josh=password
    oes-roles.properties
    josh=oes_user
  • Deploy the application - Start JBOSS and goto servername:8080/admin-console. Log in with username admin password admin. You can deploy the web-application by simply uploading the .war. Alternatively, if JBOSS is running on the same machine, simply copy the .war to server/default/deploy

Testing the application with OES


Here is the policyIX export for the sample application

<?xml version="1.0" encoding="UTF-8"?>
<xb:policy_propagation xmlns:xb="http://policypropagation.ales.com/xmlbean">
<xb:policy_propagation_data_v2>
<xb:scopes>
<xb:application_entry value="RootOrg!MyOrg!jboss" boundSSM="jboss">
<xb:application_attributes>
<xb:application_attribute_entry name="sys_obj_allow_virtual" ASIType="boolean">
<xb:single_value_entry value="true"/>
</xb:application_attribute_entry>
</xb:application_attributes>
<xb:admin_roles>
<xb:admin_role_entry value="AppAdmin" isPrimary="true" description="Primary Application Admin Role of current Application">
<xb:admin_role_privileges>
<xb:admin_role_privilege_entry object="action" action="adminmanage"/>
<xb:admin_role_privilege_entry object="authorizationPolicy" action="adminmanage"/>
<xb:admin_role_privilege_entry object="authorizationPolicyReport" action="adminmanage"/>
<xb:admin_role_privilege_entry object="directory" action="adminview"/>
<xb:admin_role_privilege_entry object="extension" action="adminmanage"/>
<xb:admin_role_privilege_entry object="group" action="adminview"/>
<xb:admin_role_privilege_entry object="policyDistribution" action="adminmanage"/>
<xb:admin_role_privilege_entry object="policySimulator" action="adminmanage"/>
<xb:admin_role_privilege_entry object="resource" action="adminmanage"/>
<xb:admin_role_privilege_entry object="role" action="adminmanage"/>
<xb:admin_role_privilege_entry object="rolePolicy" action="adminmanage"/>
<xb:admin_role_privilege_entry object="rolePolicyReport" action="adminmanage"/>
<xb:admin_role_privilege_entry object="user" action="adminview"/>
</xb:admin_role_privileges>
</xb:admin_role_entry>
</xb:admin_roles>
<xb:resources>
<xb:resource_entry value="//resources/Person" isVirtualResoureAllowed="true"/>
</xb:resources>
<xb:actions>
<xb:action_entry value="any"/>
<xb:action_entry value="readConfidential"/>
<xb:action_entry value="txfer"/>
</xb:actions>
<xb:dynamic_attributes>
<xb:dynamic_attribute_entry name="amount" type="integer"/>
</xb:dynamic_attributes>
<xb:roles>
<xb:role_entry value="Anonymous" parent=""/>
<xb:role_entry value="Everyone" parent=""/>
</xb:roles>
<xb:policies>
<xb:authorization_policy_entry>
<xb:policy_effect value="grant"/>
<xb:policy_actions>
<xb:policy_action_entry value="any"/>
</xb:policy_actions>
<xb:policy_resources>
<xb:policy_resource_entry value="//resources"/>
</xb:policy_resources>
<xb:policy_subjects>
<xb:policy_user_entry name="weblogic" directory="jboss_dir" scope="RootOrg!MyOrg"/>
</xb:policy_subjects>
</xb:authorization_policy_entry>
<xb:authorization_policy_entry>
<xb:policy_effect value="grant"/>
<xb:policy_actions>
<xb:policy_action_entry value="readConfidential"/>
</xb:policy_actions>
<xb:policy_resources>
<xb:policy_resource_entry value="//resources/Person"/>
</xb:policy_resources>
<xb:policy_subjects>
<xb:policy_user_entry name="josh" directory="jboss_dir" scope="RootOrg!MyOrg"/>
</xb:policy_subjects>
</xb:authorization_policy_entry>
<xb:authorization_policy_entry>
<xb:policy_effect value="grant"/>
<xb:policy_actions>
<xb:policy_action_entry value="any"/>
</xb:policy_actions>
<xb:policy_resources>
<xb:policy_resource_entry value="//resources"/>
</xb:policy_resources>
<xb:policy_subjects>
<xb:policy_user_entry name="admin" directory="AdminDir" scope="RootOrg"/>
</xb:policy_subjects>
</xb:authorization_policy_entry>
<xb:authorization_policy_entry>
<xb:policy_effect value="grant"/>
<xb:policy_actions>
<xb:policy_action_entry value="txfer"/>
</xb:policy_actions>
<xb:policy_resources>
<xb:policy_resource_entry value="//resources/Person"/>
</xb:policy_resources>
<xb:policy_subjects>
<xb:policy_user_entry name="josh" directory="jboss_dir" scope="RootOrg!MyOrg"/>
</xb:policy_subjects>
<xb:policy_constraint value="sys_defined ( amount ) and amount &lt; 75"/>
</xb:authorization_policy_entry>
</xb:policies>
</xb:application_entry>
</xb:scopes>
<xb:security_configuration_data>
<xb:scms>
<xb:scm_entry name="adminconfig">
<xb:ssms>
<xb:ssm_entry name="asiadmin"/>
<xb:ssm_entry name="jboss"/>
<xb:ssm_entry name="oes10gR3cp4wlsssm"/>
</xb:ssms>
</xb:scm_entry>
</xb:scms>
</xb:security_configuration_data>
</xb:policy_propagation_data_v2>
</xb:policy_propagation>


  • Load this policy into OES.
  • Test the application, by going to http://servername:8080/jboss-sample-web-1.0/OESTest.jsp
  • Login with the username and password you added to the oes_user.properties (josh/password)
  • You get access to the sample application

Summary


This is a working example of the runtime aspects of the OES Spring integration working in an actual environment. The code is now available at https://oes-spring.samplecode.oracle.com. I'm really happy (with the help of Maven) how easy is was to pull all of this together. The admin story, still needs some work. Even though the annotations are generating data in a flat file format that OES can understand, its not integrated into the build process. As you saw from the example, I had to give you the export of the policies I worked with....not part of the maven process. I'd be interested in getting people's feedback on this issue - how do think that OES policy should be tied into the overall lifecycle in a scenario like this? I'll share with you my thoughts shortly

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.