Saturday, September 4, 2010

Hands-on WSRP Security in Oracle Fusion Middleware

Introduction

This article shows how to securely propagate a user identity to a portlet, have this identity asserted and authorized to view the portlet.

WSRP (Web Services Remote Portlets) are web services. In Oracle Fusion Middleware, the way of enabling identity propagation and authentication is via OWSM (Oracle Web Services Manager) policies. The concept is no different that securing any regular web service.

Portlets authorization is handled by the OPSS (Oracle Platform Security Services) layer once authentication is done.


Note: What follows has been implemented in Oracle Fusion Middleware 11g PS1 stack (JDeveloper, WLS, Web Center, OWSM and OPSS)

OWSM policies

OWSM  is the component that implements web services security and allows for runtime enforcement and declarative policy attachment within Oracle Fusion Middleware.

OWSM provides policies for different types of use case scenarios. For example, there are policies supporting SAML token profile, kerberos, WSS1.0, SSL, etc. I will soon write an article covering OWSM in detail.

For WSRP, let’s pick a SAML token profile with WSS1.0. It basically means that the portlet will require a SAML token in the incoming SOAP header and the whole message will be digitally signed and encrypted according to WSS1.0 standards.

On the portlet producer side, we’ll attach wss10_saml_token_with_message_protection_service_policy. And on the consumer side, we’ll attach wss10_saml_token_with_message_protection_client_policy.

The policy attached to the consumer adds the SAML token to the SOAP header and performs message signing/encryption. The policy attached to the provider verifies the signature, decrypts the message, retrieve the SAML token and delegates the assertion to the OPSS layer, which verifies its validity against the configured identity store.

Securing the Producer

Authentication

The policy wss10_saml_token_with_message_protection_service_policy needs to be attached to the portlet producer. Here I will show how to do it by updating oracle-webservices.xml. Do notice this can also be accomplished via Oracle Enterprise Manager.

oracle-webservices.xml is a packaging-time artifact, meaning it is not available in JDeveloper during design-time. Therefore, to edit the file, first deploy your application to an ear file, extract the file, update it and repackage it into the ear file.

The update itself is very simple. Look for port-component name=”WSRP_v2_Markup_Service” and add the highlighted snippet shown below:

<port-component name="WSRP_v2_Markup_Service" style="document"
                                  bindingQName="{urn:oasis:names:tc:wsrp:v2:bind WSRP_v2_Markup_Binding_SOAP"
                                  enabled="true"
                                  schemaValidateInput="false">
   
<policy-references>
     <policy-reference enabled="true" 
                                       uri="oracle/wss10_saml_token_with_message_protection_service_policy"
                                       category="security"/>
   </policy-references>

   <operations>
     ...
   </operations>
   <!-- start:deployment time generated info -->
   <deployment>
    <tie-class-name>oasis.names.tc.wsrp.v2.bind.runtime.WSRP_v2_Markup_Binding_SOAP_Tie</tie-class-name>
    <service-qname namespaceURI="urn:oasis:names:tc:wsrp:v2:wsdl"
localpart="WSRP_v2_Service"/>
    <soap-version>soap1.1</soap-version>
   </deployment>
   <!-- end:deployment time generated info   -->
   <servlet-link>WSRP_v2_Markup_Service</servlet-link>
 </port-component>



Note: The portlet producer application needs to be deployed in order to be called by consumers. You cannot “Click & Run” a secured portlet application from JDeveloper.


Key store and Credential store configuration

This is a necessary step only because the OWSM policies we’re using require message-level protection.

Both key store and credential store are WLS domain wide artifacts and WLS expects them to be found under $DOMAIN_HOME/config/fmwconfig folder.

In a nutshell, the key store contains the signing and encryption keys used to sign/encrypt/decrypt messages. Each key and the key store itself are password protected. They are also referred by an alias. These aliases and the corresponding passwords are stored in the credential store. When access to key store is required, the credential store is first queried for the necessary aliases and passwords.


Key store contents

The key store is created by using JDK’s keytool command. Assuming JDK is on your $PATH, type keytool in a command prompt and you will see the command options.

To list the contents of the key store, type:

keytool –list –v –keystore <keystore_filename> -storepass <keystore password>


How to create a certificate key

In order to protect the symmetric key used to actually encrypt the SOAP message, we need a PKI certificate in the key store. For the sake of this example, let's have this certificate under an alias called “orakey”, with password equals to “welcome1”.

keytool -genkeypair -keyalg RSA -alias orakey -keypass welcome1 -keystore default-keystore.jks -storepass welcome1 -validity 3600


Note: JDK 6 is required to generate a key store compatible with OWSM in FMW 11g.


Credential store contents

A credential store is split into maps. Each map contains a set of keys. Each key points to the actual credential. The aliases created in the key store must have a corresponding credential in the credential store. For example, if we have named our alias as “orakey” in the key store, there must be a credential named “orakey” in the credential store. Such credential is pointed by a predefined key names.

For OWSM, these key names are sign-csf-key and enc-csf-key, which are used to sign and encrypt/decrypt messages. Another important key is keystore-csf-key, which holds the key store alias and password and is used to open the key store.

OWSM uses a predefined credential map named oracle.wsm.security.


How to populate the credential store

The credential store can be populated through WLST or Oracle Enterprise Manager.

In WLST, execute these online commands:

wls:/DefaultDomain/serverConfig> createCred(map="oracle.wsm.security", key="keystore-csf-key", user="owsm", password="welcome1", desc="Keystore key")
wls:/DefaultDomain/serverConfig> createCred(map="oracle.wsm.security", key="enc-csf-key", user="orakey", password="welcome1", desc="Encryption key")
wls:/DefaultDomain/serverConfig> createCred(map="oracle.wsm.security", key="sign-csf-key", user="orakey", password="welcome1", desc="Signing key")

Such commands update your domain level credential store. Normally, it corresponds to cwallet.sso under $DOMAIN_HOME/config/fmwconfig.


Verifying key store and credential store configuration in jps-config.xml

Open jps-config.xml located at $DOMAIN_HOME/config/fmwconfig and check whether the following entry exists. This should be out of box configured.

<serviceInstance location="./" provider="credstoressp" name="credstore"> 
  <description>File Based Credential Store Service Instance</description>
 </serviceInstance>
 <serviceInstance name="keystore" provider="keystore.provider" location="./default-keystore.jks">
   <description>Default JPS Keystore Service</description>
   <property name="keystore.type" value="JKS"/>
   <property name="keystore.csf.map" value="oracle.wsm.security"/>
   <property name="keystore.pass.csf.key" value="keystore-csf-key"/>
   <property name="keystore.sig.csf.key" value="sign-csf-key"/>
   <property name="keystore.enc.csf.key" value="enc-csf-key"/>
 </serviceInstance>


Also, make sure the “default” context references the key store and credential store service instances above:

<jpsContext name="default">
   <serviceInstanceRef ref="credstore"/>
   <serviceInstanceRef ref="policystore.xml"/>
   <serviceInstanceRef ref="audit"/>
   <serviceInstanceRef ref="idstore.ldap"/>
   <serviceInstanceRef ref="keystore"/>
 </jpsContext>




Note: If this configuration is already in place, you don’t need to restart your WLS domain. Otherwise, make the changes and restart your WLS domain.


Authorization


Portlets authorization is delegated to OPSS layer, i.e., the decision whether or not a portlet is available to a user is done against the OPSS policy store. Portlets are just one way of exposing local ADF task flows to remote applications. There’s a component called portlet brigde that is responsible for providing the glue between portlets and task flows. It basically makes possible exposing a task flow as a portlet.

In the example below, the policy store is file-based. Normally it is represented by system-jazn-data.xml located under $DOMAIN_HOME/config/fmwconfig folder. That can be easily changed to be and LDAP-based one.

Once the right task flow permissions are already in place in the policy store, there’s only one more permission that needs to be added, and it should be granted to the authenticated-role:

<permission> 
  <class>oracle.adf.controller.security.TaskFlowPermission</class>
   <name>/WEB-INF/adfp-portlet-bridge-container.xml#adfp-portlet-bridge-container</name>
   <actions>view</actions>
 </permission>


Here’s an example of a complete set of grants required for portlet authorization. In the example, the propagated user must be granted approle1 application role in order to view the portlet (assuming /WEB-INF/my-task-flow.xml#my-task-flow is taskflow exposed as a portlet).

<jazn-policy> 
  <grant>
     <grantee>
       <principals>
         <principal>
           <class>oracle.security.jps.internal.core.principals.JpsAuthenticatedRoleImpl</class>
           <name>authenticated-role</name>
         </principal>
       </principals>
     </grantee>
     <permissions>
       <permission>
         <class>oracle.adf.controller.security.TaskFlowPermission</class>
         <name>/WEB-INF/adfp-portlet-bridge-container.xml#adfp-portlet-bridge-container</name>
         <actions>view</actions>
       </permission>
     </permissions>
   </grant>
   <grant>
     <grantee>
       <principals>
         <principal>
           <class>oracle.security.jps.service.policystore.ApplicationRole</class>
           <name>approle1</name>
         </principal>
       </principals>
     </grantee>
     <permissions>
       <permission>
         <class>oracle.adf.controller.security.TaskFlowPermission</class>
         <name>/WEB-INF/my-task-flow.xml#my-task-flow</name>
         <actions>view</actions>
       </permission>
     </permissions>
   </grant>
 </jazn-policy>


Securing the Consumer


Securing a portlet consumer basically means enabling identity propagation. This is done during portlet producer registration in JDeveloper. When doing it, make sure you select/enter the right information in step 5 at WSRP Portlet Producer Registration wizard, as shown below:





Note: the configuration made here is written to connections.xml


Key store and Credential store configuration


Within the portlet consumer WLS domain, both key store and credential store can be the same used by the portlet producer. Have them at $DOMAIN_HOME/config/fmwconfig, as explained previously.

It is true we have a potential security issue here, since the certificates used by WSS are the same across WLS domains, and I’ll cover how to harden it in a next article.

Tuesday, August 17, 2010

Kerberos and WebLogic Server - decisions, decisions

I've been away from the blog for a while - I took some vacation time and I've been working on a customer that I can't really talk about. Have you missed me?

No? I didn't think so.


I got a call yesterday asking me to help a customer trying to get SPNEGO/Kerberos working between Windows desktops and WebLogic server. Yes, Kerberos again. After talking through what they're trying to accomplish today I found that they may have started out on the wrong foot to begin with.

Here's (more or less) what they told me they're trying to accomplish:
We have an app deployed in WebLogic and we want users that are in the domain to be able to access that app without being prompted for credentials.
That's it.

There are three ways that I can think of right away to address that requirement:
  1. Use WebLogic's SPNEGO Identity Asserter to have WebLogic verify the Kerberos ticket
  2. Use IIS to do the Kerberos bits and then use a simple HTTP header Identity Asserter to get the identity into WebLogic
  3. Use Oracle Access Manager
Each of the solutions have their own plusses and minuses. The point of this post is to try to get them written down to help you (or someone else) make a sensible decision about which one to pick.

Before I get into it let me just say that Kerberos/SPNEGO is one of those technologies that when it works it's awesome, and when it doesn't it's incredibly frustrating to figure out what's gone wrong. Add to the mix the fact that so much of what's happening is automatic and so few people actually understand what's really happening under the covers/on the wire and you have a recipe for pain, frustration, annoyance and lots of hair being pulled out.

With that said...

WLS + SPNEGO Identity Asserter
WebLogic includes an the necessary bits that allow WebLogic to verify a Kerberos ticket if you want. I've blogged about it before and there are official docs as well as oodles of threads on Oracle forums where people are struggling to get it working. It definitely works and it has gotten easier over the years, but it's still harder than flipping a switch and being done.

The requirements basically amount to getting a Kerberos service principal registered, getting the necessary secret key onto the box running WebLogic and then getting WebLogic and IE to agree to do SPNEGO. Each of those steps is manual and it's easy to make a mistake.

Plusses: baked into WebLogic so there are no dependencies on any other software, Kerberos ticket is verified inside WebLogic itself and is thus about as secure as possible.
Minuses: can be difficult to setup & troubleshoot

Use IIS to do the hard stuff

One of the great things about Microsoft embracing Kerberos is that some very difficult, very complicated things have been reduced to a checkbox. To enable Kerberos in IIS you add the web server to the domain, then you go into the IIS console, edit the Security properties of a directory or of the server and check one box - "Integrated Windows Authentication". Windows and IIS do all the hard stuff for you including setting up the Kerberos principal.

Yes, I'm glossing over a few things, but not many.

Once you've got IE and IIS doing the Kerberos/SPNEGO dance two things remain: (1) getting IIS to proxy requests over to WebLogic and (2) getting WebLogic to trust IIS' say so on the user's identity. The former is address by the IIS WebLogic Plug-in. The latter is a simple Identity Asserter like the one I discussed back in January (I really need to put that code up somewhere on the Internets!).

Plusses: One checkbox to enable Kerberos in IIS
Minuses: You have to deploy Windows & IIS in front of every WebLogic server. The security issues I mention in my older post

Use OAM

OAM provides two relevant things - SSO across web sites and access control to those web sites. The former is all we're interested in here; when a user accesses the web server OAM will detect that they haven't authenticated yet and kick them into a process to do that. The latter allows you to decide who gets access to what parts of the protected web sites; it's not something we care about in this case but it can be very useful.

The upside to using OAM in this case is that you only need one or two IIS web servers somewhere in your environment to get Kerberos working. Each of the OAM WebGates plugged into your protected web servers will redirect users to one of those machines to figure out who the user is and then back to the protected web server. This works regardless of which flavor of web server you use - OHS, Apache, IIS, or Sun One. I've seen customers do this sort of thing with as little as one IIS server, but for redundancy you want a pair of IIS boxes somewhere in your environment and probably a second pair in a disaster recovery environment as well.

Plusses: Few Windows/IIS servers needed.
Minuses: Requires additional software (OAM WebGate) to be installed


In this particular customer's case they'd tried the first option already and had run into some issues. Because of those issues and because their requirements were still in flux I suggested that they try the second option (IIS doing Kerberos along with a username Identity Asserter). Your mileage may vary and you should probably ask a knowledgable person for advice before picking one of these options, but that's (part of) what we're here for.

I'm interested in what you think. Let me know in the comments!

Tuesday, August 3, 2010

Maven Integration for Oracle Entitlements Server

This is the final post in what has turned out to be a 3-part series in bringing to life the "hypothetical" OES-Spring integration.. This post is going to focus on the lifecycle aspect. Part of the whole value in how I designed the annotations was to allow the developer to do their work - implementing business logic - while giving enough information to security policy administrators that they could write policy in OES. I used the Java Annotation Process in JDK 1.6 to generate the actions, resources, and attributes that the runtime AuthorizationAspect would be passing to OES. This was a good start, but a long way from having the information stored in OES, let alone working in a "lifecycle".

Introducing the OES Maven Plugin


The way I attempted to address this problem was by creating a Maven plugin for OES. The OES Maven Plugin is part of the oes-jboss project. The information in this post is based on version-1.0

The plugin supports three goals (maven speak for operations)

  • import - Imports policies from the local file system into OES admin server using policyIX
  • export - Exports the policies from OES admin server and into the local file system using policyIX
  • generate-default-policy - Reads the files generated by the OES Annotations Processor and converts them into a policyIX policy file in the file system

The configuration for the plugin basically follows the names of the elements in the policyIX config file.

General Settings



  • server_host_name - Hostname of the OES Admin Server - defaults to localhost
  • server_port - SSL Port for the OES Admin Server - defaults to 7010
  • blm_server_port - The BLM API port for the OES Admin Server - defaults to 7011
  • print_info - Boolean flag that determs if the information about which objects policyIX is loading should be displayed - defaults to true
  • userID - OES Admin user id - defaults to admin
  • password - OES Admin password - defaults to password
  • policyFile - The location of the policy file that policyIX imports into the OES Admin Server or the localtion of where the generated policy file should be saved - defaults to ${project.build.outputDirectory}/com/oracle/security/entitlements/policy/policy.xml

Settings for the generate-default-policy goal



  • policyTemplateFile - the location of the policy template that the plugin should use when generating the default policies - defaults to ${project.build.outputDirectory}/com/oracle/security/entitlements/policy/policy_template.xml
  • resources - the location of the resources file generated by the OES annotations - defaults to ${project.build.outputDirectory}/com/oracle/security/entitlements/policy/object
  • actions - the location of the actions file generated by the OES annotations - defaults to ${project.build.outputDirectory}/com/oracle/security/entitlements/policy/priv
  • attributes - the location of the attributes file generated by the OES annotations -defaults to ${project.build.outputDirectory}/com/oracle/security/entitlements/policy/attr
  • overwrite - boolean indicating that the generated policies should be overwritten, even if th policyFile exists - defaults to true

Settings for the import goal



  • policy_load_procedure - the load procedure the plug in should use when importing the policies into OES - the default is override. The other valid value is delete_existing

Settings for the export goal



  • exportPolicyFile - the location of the file that the OES policies are exported to - defaults to ${project.build.sourceDirectory}/../oes/policy.xml
  • clipping_scope - the clipping scope from which the OES policies are exported - defaults to RootOrg!${oes.organization}!${oes.application}
  • createTemplateOnExport - boolean indicating that the export task should convert the OES policies into a "template", before saving it to disk - default value is true
  • replaceAdminDirInTemplate - boolean indicating that the user and group part of the policies that are defined for the AdminDir should not be templatized - default value is true

Instructions for Installing OES-Maven Plugin


The installation is really in two parts. The first is deploying a special web-application to the OES Admin server. This web-application greatly simplifies the compilation of plugin by materializing the required OES libraries as a moven POM. This is an alternative to the previously suggested ANT based approach or explicitly loading in the OES libraries. Its just too complicated, and when I realized that I needed a slighly different set of libraries to run the policyIX tool, I took the time to build the web app. With the web-app installed, you can easily build the oes-maven plugin.

Building the repository-web-app



  • Build the web-app - this is simple, just type mvn install from oes-maven/repository-web-app
  • Deploy the web-app to the OES Admin Server - This is assuming that the OES Admin Server is running on WLS, but basically, all you're doing is installing a war. You can log into the WLS admin console at https://:7010/console with admin/password, and deploy the web-app.
  • Import the OES policies protecting the web-app - We need to bootstrap the policies for who can access the oes-maven web-application. I included the policyIX policies here.

    <?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!defaultOrg!oes-maven" boundSSM="asiadmin">
    <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/url" isVirtualResoureAllowed="true"/>
    </xb:resources>
    <xb:actions>
    <xb:action_entry value="any"/>
    </xb:actions>
    <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/url"/>
    </xb:policy_resources>
    <xb:policy_subjects>
    <xb:policy_group_entry name="allusers" directory="AdminDir" scope="RootOrg"/>
    </xb:policy_subjects>
    </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>

  • Distribute The Policies - Log into the OES Entitlements Administration Server, and deploy the policies.
  • Add an entry for the OES Admin Server in your Maven's settings.xml - Since the application is protected, you'll need to have the OES admin user's credentials. In Maven, this is configured in your settings.xml

    <servers>
    <server>
    <id>oes-admin</id>
    <username>admin</username>
    <password>password</password>
    </server>
    </servers>

    The id oes-admin is just a reference used by the oes-maven-plugin POM.

Build the Plugin


From the oes-maven-plugin directory type

mvn install -Does-admin-url=http://servername:7000/oes-maven

If this works, you'll see a bunch of files downloaded to your local repository, and the oes-maven-plugin will be built successfully! For those of you who are really hard-code, you can actually access the oes-maven web-app over the SSL port by passing -Does-admin-url=https://servername:7010/oes-maven. If order to get the SSL handshake to work, you just need to import the OES Admin Server's CA into the trusted keystore of the JDK (think of this as extra credit)

Using the OES Maven Plugin - an example


I've created a 1.0.1 version of the oes-spring application that demonstrates the OES maven plugin. All of the magic is inside of the oes_spring_aop_test/pom.xml. First let's run through an example of the "lifecycle", and then we can dig into the details of the POM.

  • Developer Builds Simple Spring+OES Application - In this first step of the lifecycle, the developer is just building the objects. They add the annotations as a way to help surface the security meta-data - mainly the resources, actions, and attributes that will be available for policy authoring. As the developer compiles the application, the OES annotations are evaluated, and the OES maven plugin generates the sample policy file based on the template. You can see this by running

    mvn -Does.server.host=<hostname of admin server> compile

    The result of this is the creation of the actions, attributes, and resources files. Notice that with the sample that there were some compiler warnings generated. This is to be expected. Basically, not every Java type can be mapped to a dynamic attribute type inside of the OES console. This is fine, but you can only access these attributes via OES Attribute Retriever or Eval Function, not through the policy. In the case that you're not passing the object and its a type that is not supported in OES, then the compilation fails.
  • Developer tests application - So now the developer wants to start doing some unit testing. At this point, the OES maven plugin will generate the policyIX import file and import it into the OES admin server. The file is stored as a resource in the classes directory, and as such is expected to be a simple temporary set of policies. You can see the policies deployed to OES by running

    mvn -Does.server.host=<hostname of admin server> test

    The unit test that I have in the sample uses a dummy implemenation of the ISecurityContext, but its possible that if there was a local SM, then the policies would be available. NOTE: For the policies to take affect they need to be distributed from the OES Admin Server. The current version of the OES Maven Task does not deploy the policies
  • Security Administrator changes OES policies - The administrator can now log into the OES Admin console. You can see the resources, the actions, and the attributes that are available for policy authoring.





    The security administrator now can go in and change the policies. Since all of the resourecs, actions, and attributes have been created for them, this greatly simplifies the task. At some point, they are happy with the policies, and the policies are exported back to the project.

    mvn -Does.server.host=<hostname of admin server> oes:export

    By default, this generates a policyIX export and adds it to ${project.build.sourceDirectory}/../oes/policy.xml. This is inside of the source of the project. The expectation is that this export file would be added to source control. One interesting this that the export goal does is to change the file back into a template. This is done so that when the import goal is run, the values of a different environment can be used.
  • Policy and Application is deployed to a different environment - Once the policy hasa been exported from OES and is now part of the project, the application and policies can be moved to a different environment - say integration testing or pre-production. The POM checks to see if the OES file exists in main/oes/policy.xml, and if it does, then it uses that file (as opposed to the generated one) to be imported. You can see this by running

    mvn -Does.server.host=<hostname of admin server> install

    You'll notice that the policies that get added back to OES reflect the changes made after running oes:export - not the default policies.

Understanding a some of the oes_spring_aop POM


The project depends on a few properties

<properties>
<oes.ssm>jboss</oes.ssm>
<oes.application>jboss</oes.application>
<oes.organization>MyOrg</oes.organization>
<oes.directory>jboss_dir</oes.directory>
<oes.server.host>oel55-64.localdomain</oes.server.host>
</properties>

The first four are used for the variable substuitution inside of the policies. The properties that I ship with the project are based on the OES JBOSS SPRING application. The values for these properties should match the values used in the config tool used to create the SM. I used the built in filtering capabilities of Maven to do the variable substitution of these properties into the template.

The last property is a convenient way to specify the hostname of the admin server. Notice that in the example above, I used -Does.server.host to specify the servername. You can override any of these properties with command line arguments or as part of Maven profiles.

Summary


The way that I have the goals of the plugin tied to the phases of the Maven lifecycle is definately a matter of debate. I made a deliberate decision not to tie export to an explicit phase, but if I had to pick one...maybe deploy. My thinking is that before the application is put some place else, it makes sense to get a copy of the policies. Ultimately, I don't think there is a total one size fits all lifecycle, but I think that this OES Maven plugin, and the example project provide a very solid foundation. There are definately more goals that could be added - maybe the ability to automatically create and enroll an SM from the config tool. I'm eager to hear your feedback on the life cycle that I put forth, and what variations you've seen or think the maven plugins should support.

Thursday, July 29, 2010

More on the Identity and Access Management 11g Launch

Hopefully you all enjoyed Amit’s IAM 11g launch webinar. We will be adding a ton of content about the new software in the weeks and months to come but I wanted to get started and post a little bit of follow-up on the launch.

There is an ongoing identity manager launch center here.

The documentation for all the new products/versions in the release can be found in the current version of the Fusion Middleware Documentation Library here. There are links from there to the older product versions if you have a need for the older doc.

The actual software can be downloaded here: http://www.oracle.com/technetwork/middleware/downloads/oid-11g-161194.html

Now to be honest, the package names and all the pre-requisite requirements are a little confusing so while we’ll hold off on doing install related blogs for another day, I want to clarify some things about the various packages and downloads that you see if you follow the link above.

The Oracle Identity and Access Management (11.1.1.3.0) is the new package containing the new 11g versions of OAM and OIM; along with OAAM, OPSS (platform security layer that most Fusion Middleware security is built on), and APM (a tool for managing OPSS authorization policies).

The pre-requisites for this package include the full 11g version of the Oracle Database, the repository creation utility for Fusion Middleware, WebLogic 11g, and (perhaps surprisingly to many people), SOA Suite 11g which is needed for OIM 11g. Most people installing this package will also want or need an LDAP directory which is a good lead in to discussing the other big IDM package called Oracle Identity Management (11.1.1.3.0).

Oracle Identity Management is the original set of Identity Management products included in the Fusion Middleware 11g release that took place a year ago. It includes OID, OVD, OIF, and Enterprise Manager.

This package also requires the database and WebLogic. Additionally, you have to install 11.1.1.2 before upgrading to 11.1.1.3.

Finally, don’t get confused: the product Oracle Identity Manager (OIM) is in the package Oracle Identity and Access Management and not Oracle Identity Management!

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