Wednesday, October 27, 2010

Keystores and signing your SAML assertions

I've been working on a project recently that includes SOAP clients submitting messages via JMS and HTTP to Oracle Service Bus (OSB). OSB is supposed to validate the assertion, perhaps do some transformations on the SOAP, and then send the message off to some backend service. I'll probably talk about the last two thirds of the solution at some point in the future, but it's the first third that has raised a bunch of questions that other people probably have too.

Before I go into the details let me just remind you that the details here are specific to this customer's situation. I'm not advocating for, endorsing or otherwise suggesting that the info here is useful to YOUR situation. With that said...

The customer's architecture includes submitting the messages over a 2-way SSL channel and they want to use SAML 1.1 assertions with the Bearer confirmation method. Most people are probably more familiar with the Sender Vouches method in which the entity sending the SAML assertion (i.e. the SOAP client) is trusted by the receiving party - which means that every client needs a private key and the receiver needs to have the associated Certificate (or the issuer's Certificate).

In Bearer the sender of the message isn't necessarily the party that actually created the SAML Assertion; if they were then you could just use Sender Vouches and be done. In Bearer you're saying that the communication channel authenticates the caller; this also means that the party sending the message could get a SAML assertion from somewhere else and then just includes it in the SOAP message. There are a bunch of dangers in this sort of architecture, but you can mitigate most of them through appropriate architectural choices. What those dangers are and how you mitigate them is a subject for a separate post. There's a third confirmation method called Holder of Key which is, again, a great subject for another post.

In any case when you use the Bearer Confirmation Method you might want the assertion to be signed, especially if it comes from somewhere other than the client. So who has the private key? And what certificates do you need to put in the keystore?

When you install WebLogic the installer automatically creates a couple of keystores for you. Gerard Davison discusses this a bit in a blog post in the context of setting up SSL. We can use the same keystores for testing SOAP.

First here's the table (shamelessly copied) from Gerard's post:

Property Value
Trust store location wlserver_10.3/ server/lib/DemoTrust.jks
Trust store passwordDemoTrustKeyStorePassPhrase
Key store location wlserver_10.3/ server/lib/DemoIdentity.jks
Key store passwordDemoIdentityKeyStorePassPhrase
Private key passwordDemoIdentityPassPhrase

As you can see there are two JKS files - DemoTrust.jks and DemoIdentity.jks. Take a look at the contents of them by using keytool:

keytool -list -keystore DemoIdentity.jks -storepass DemoIdentityKeyStorePassPhrase
keytool -list -keystore DemoTrust.jks -storepass DemoTrustKeyStorePassPhrase

You'll find that DemoIdentity.jks contains a Private Key and DemoTrust.jks contains the associated Certificate (and a few others).


I'm a huge fan of automated unit test tools. I'll often invest literally tens of hours writing test drivers that will be thrown away when the project is done just so I can be sure that I haven't missed anything. More importantly I want to be 100% sure that we've got test coverage for all of the positive and negative cases we've thought of in the design phase.


So for my little SOAP tester in my test environment I can use the DemoIdentity.jks file to sign the SAML Assertion and as long as OSB is configured to use DemoTrust.jks it should accept my SAML Assertion.

In the real world you definitely won't be using the DemoTrust keystore. Instead you'll create another Key Store to be used on the OSB server and you'll probably put the Certificate of the SAML assertion generator in there (if it's a self-signed cert) or the Cert chain needed to verify the signature.

Hope this helps!

Monday, October 25, 2010

Quick tip: OVD – Providing namespace translation for DN attributes

Breaking off the ADF/OPSS series…

OVD (Oracle Virtual Directory) guru Mark Wilcox gave me this really helpful tip that it’s worth sharing. It can save you folks quite a bit of headache.

Scenario: you have configured an OVD authentication provider in WLS, but you cannot login with any user from OVD in WLS Console, even the user being a member of an Administrators group in the backend LDAP directory. When you try it, you end up with an “Authentication Denied” error. And if you login into WLS Console in the “normal” way (i.e., using weblogic user from Default Authenticator provider) you don’t see the OVD users memberships. These two problems are definitely related.

Solution: you need to change the LDAP adapter definition in OVD a bit. Connect to ODSM (Oracle Directory Services Manager), retrieve your adapter, click on the General tab and add uniquemeber as one of DN Attributes, as shown:

image

OVD translates all attributes listed as DN Attributes. Translation here means converting the backend repository (in this case OID) namespace into the adapter’s namespace. In this example, OID namespace is dc=us,dc=oracle,dc=com, while adapter’s is ou=oid,dc=us,dc=oracle,dc=com. Without the translation, uniquemembers of a group would end up being cn=<user>,dc=us,dc=oracle,dc=com. With the translation, they align nicely with the adapter’s namespace: cn=<user>,ou=oid,dc=us,dc=oracle,dc=com.

No need to restart anything. You should now be able to see users memberships as well as login in WLS Console with administrators users defined in the OVD authentication provider.

Note: this has been done in Oracle Identity Management 11g PS2.

Wednesday, October 20, 2010

Several ADF apps to one single OPSS policy stripe

In OPSS Artifacts Life Cycle in ADF Applications, I’ve explained how to change the default behavior for migration of authorization policies when deploying applications. Revisiting it, I’ve said that one can specify the MERGE value for jps.policystore.migration param-name in weblogic-application.xml and that is particularly useful in some deployments where more than one application have to share the same policy context (or policy stripe).

A real use case is when a customer wants to hide the concept of how a system is partitioned across ADF applications for security administrators. Most of the times, a security administrator is interested in the policies of the system as whole. This article explains how it can be done.
Before going further, some definitions:
  • Policy Store: repository of policies comprising one or more application policy stripes and code-based grants. There’s only one policy store per WLS domain.
  • Policy Stripe: set of application policies to which one or more applications bind to. One application binds to only one policy stripe.
Clarifying a little bit more, take the following system-jazn-data.xml snippet, the OOTB policy store in WLS domains. In such case, system-jazn-data.xml itself represents the policy store, while OrderEntry#V2.0 and OrderCapture#V2.0 are the policy stripes, defining an application-level scope for authorization policies. In default mode, OrderEntry application does not have access to application policies in OrderCapture#V2.0 policy stripe, and vice-versa.

<?xml version='1.0' encoding='utf-8'?>
<jazn-data>
<policy-store>
<applications>
<application>
<name>OrderEntry#V2.0</name>
<app-roles>
...
</app-roles>
<jazn-policy>
...
</jazn-policy>
</application>
<application>
<name>OrderCapture#V2.0</name>
<app-roles>
...
</app-roles>
<jazn-policy>
...
</jazn-policy>
</application>
</applications>
</policy-store>
</jazn-data>

When we develop an ADF application in JDeveloper and enables ADF security, the authorization policies you create go into a workspace-level jazn-data.xml under a stripe name that has the same name as the application itself, as show below. Let’s say our application is called OrderEntry. In jazn-data, we would have:

<?xml version='1.0' encoding='utf-8'?>
<jazn-data>
<policy-store>
<applications>
<application>
<name>OrderEntry</name>
<app-roles>
...
</app-roles>
<jazn-policy>
...
</jazn-policy>
</application>
</applications>
</policy-store>
</jazn-data>

Then if you do nothing and just deploy the application, the policies get migrated to the runtime policy store under an application policy stripe named OrderEntry#V2.0. For our mental sanity, the V2.0 comes from the Weblogic-Application-Version property in the MANIFEST.MF, but this is not the topic of this article.

Now what happens if we want to have OrderEntry and OrderCapture binding to the same policy stripe, say OrderMgmt? We need to add some properties to some deployment descriptors:

1) in weblogic-application.xml:

<application-param>
<param-name>jps.policystore.applicationid</param-name>
<param-value>OrderMgmt</param-value>
</application-param>

Such information is used only at deployment time. It basically tell the OPSS listeners to migrate application policies in jazn-data.xml to OrderMgmt policy stripe in the runtime policy store. In this scenario, the version number is not appended to the stripe name.

2) in web application’s web.xml:

<filter>
<filter-name>JpsFilter</filter-name>
<filter-class>oracle.security.jps.ee.http.JpsFilter</filter-class>
<init-param>
<param-name>enable.anonymous</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>remove.anonymous.role</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>application.name</param-name>
<param-value>OrderMgmt</param-value>
</init-param>
</filter>

Here I have added the init-param application.name to the JpsFilter definition. The param-value must match the value defined in weblogic-application.xml. This information is used only at runtime. It tells the JpsFilter where to bind to when looking for authorization policies. As the JpsFilter intercepts all requests for the Faces Servlet (javax.faces.webapp.FacesServlet), it establishes the policy store context for every request to an ADF artifact.

By repeating this very same configuration across your applications, you can bind any number of applications to the same policy stripe, i.e., the same authorization context and expose a single and consolidated view of your authorization policies to security administrators.

Monday, September 27, 2010

OPSS Artifacts Life Cycle in ADF applications

After writing about users and groups migration, it looked to me we should also talk about the life cycle of other important entities in secured ADF applications. When you enable security in an ADF application, you see a couple of new artifacts in your JDeveloper workspace, namely jps-config.xml, jazn-data.xml and cwallet.sso.

Have you ever wondered what their purpose is, their life cycle and how they relate to WLS domain security configuration? This article is just about it.

As you might know, secured ADF applications leverage OPSS (Oracle Platform Security Services). OPSS is a fundamental component within Oracle Fusion Middleware security. It works as an abstraction layer on top of security services providers, shielding applications from all the complexities in dealing with them. For instance, applications can transparently switch between file-based and LDAP-based policy stores. Likewise for credential store services.

Let's take a closer look at each of those artifacts and their life cycles.

jps-config.xml


This file can be seen as the lookup services registry for OPSS. Among these services are login modules, authentication providers, authorization policy providers, credential stores and auditing services.
Whenever an OPSS-enabled application requires security services, it looks up a JPSContext object where all the necessary services are supposedly configured.

In ADF applications, a workspace-level jps-config.xml is created once ADF security is enabled. It drives services lookup for ADF's BC (Business Components) Tester available in JDeveloper, which is a JavaSE application. If you want to have security unit tests, you can also easily leverage it.

It is never used once the ADF application gets deployed in a WLS container, even though it is packaged in the ear file. Within a WLS container, a jps-config.xml in <domain-home>/config/fmwconfig is used by all applications in all servers deployed in that WLS domain. There's no such concept of an application-level or server-level jps-config.xml.

jazn-data.xml


This file keeps users, groups and authorization policies for OPSS-enabled applications and is automatically created once ADF security is enabled. I've already covered users and groups life cycles in a previous article. It is important to mention that users and groups are also leveraged by ADF's BC Tester and can be integrated into security unit tests as well.

Authorization policies are, if not the most, one of the most sensitive parts of a secured ADF application, since it governs who has access to what. As you might guess, they are also leveraged by ADF's BC Tester. When the ADF application is deployed into WLS, at startup time, policies are OOTB (Out-Of-The-Box) migrated into the configured policy store, who, by default, is a file called system-jazn-data.xml, located under <domain-home>/config/fmwconfig. You can configure how (and if) policies are migrated through some properties in weblogic-application.xml. Here they are:

<listener>
<listener-class>oracle.security.jps.wls.listeners.JpsApplicationLifecycleListener<listener-class>
<listener>


This listener is the one actually responsible for pushing the changes to the runtime policy store. Make sure it is present in weblogic-application.xml. Otherwise, you’ll experience a lot of frustration in trying to deploy authorization policies along with your application.

<application-param>
<param-name>jps.policystore.migration</param-name>
<param-value>[MERGE|OVERWRITE|OFF]</param-value>
</application-param>


MERGE, OVERWRITE and OFF are exclusive and applicable for deployments and redeployments. And they mean exactly what you might be thinking.
  • MERGE will merge what’s already available in the runtime policy store. This might be particularly useful in some advanced deployments where more than one application share the same application policy stripe.
  • OVERWRITE wipes away the existing application policy stripe and load all policies from scratch.
  • OFF skips policy migration.
Do notice that once the application is undeployed, its policies are also removed from the policy store, unless you set the following property in weblogic-application.xml:

<application-param>
<param-name>jps.policystore.removal</param-name>
<param-value>OFF</param-value>
</application-param>

Authorization policies migration will always happen according to weblogic-application.xml configuration, no matter what the deployment method is.

cwallet.sso


This file keeps credentials used by the application. A subtle and fundamental distinction is important to be made here: credentials and identities are not the same thing. Simply put, in OPSS, identities are what authentication requests are done against, while credentials are securely kept objects that are somehow presented to authentication providers to be matched against identities.

cwallet.sso is encrypted and you cannot browse it or explicitly edit it via JDeveloper. At design-time, different components make use of cwallet.sso and are responsible for creating the necessary credentials in it. Examples are OWSM policy attachments that override the csf-key and ADF connections requiring credentials in the call out.

If you need credentials that can’t be created within JDeveloper, you can either use wlst createCred online command or write some code using OPSS APIs. Both options makes the whole life cycle story a little catchy, because a running WLS container is necessary. You can also disable credentials migration and create them directly in the WLS domain where applications are deployed.

Like authorization policies, credentials are also OOTB migrated into the configured WLS domain credential store on application startup. By default, the credential store is the cwallet.sso file in <domain-home>/config/fmwconfig folder.

The following weblogic-application.xml properties govern how (and if) they're deployed.

<listener>
<listener-class>oracle.security.jps.wls.listeners.JpsApplicationLifecycleListener</listener-class>
</listener>

As for policies, the same listener migrates credentials. Avoid frustration and make sure the listener is present if you want to migrate or control how your credentials are migrated.

<application-param>
<param-name>jps.credstore.migration</param-name>
<param-value>[MERGE|OVERWRITE|OFF]</param-value>
</application-param>
  • MERGE: migrate non-existing credentials only;
  • OVERWRITE: overwrites existing credentials;
  • OFF: skips credentials migration;

Monday, September 20, 2010

Users and Groups migration: a handy JDeveloper feature

When you run an ADF web application directly from JDeveloper, it starts its embedded WLS and deploys the application. In such context, JDeveloper has a very convenient feature when dealing with users and groups defined in the application's jazn-data.xml file. They get deployed along with the application into WLS embedded LDAP server, provided the Users and Groups check box is selected in the Application Properties Deployment window, as shown right below:


applicationMenu

UsersAndGroupsMigration 

Then by simply asking JDeveloper to run your application you get everything you need.

As said, that's a JDeveloper convenience that only works when deploying the application through JDeveloper. Do notice this apply whether you click & run a page or taskflow or explicitly ask JDeveloper to deploy your application into WLS, as shown:

DeployingViaJDev

But if you’re not using JDeveloper, you’re on your own. You should not expect it to happen when generating an ear file and deploying via any other means, although jazn-data.xml is packed within the ear file. `I've gotten this question from a few of customers. And some believe that's a bug. It's not.

You need to manually populate WLS embedded LDAP. There are two ways to accomplish it:

1) Using wlst.sh:

> connect ('weblogic','<weblogic-password>','t3://<server>:<port>')
> cd('<folder-where-your-ldif-file-is-kept>')> 
> cmo.importData('DefaultAtn', '<your-ldif-file>', None) 


2) Using WLS Console:

Notice the path at the top to understand how to get to this screen.

Enter the ldif file absolute path name in “Import File” on Server field. Notice the file has to be accessible on the server file system.

DefaultAuthenticatoSetupWLS

Here's a small sample of the ldif file you can use and extend:

dn: dc=@domain@
dc: @domain@
objectclass: top
objectclass: domain
      
dn: ou=@realm@,dc=@domain@
ou: @realm@
objectclass: top
objectclass: organizationalUnit
      
dn: ou=groups,ou=@realm@,dc=@domain@
ou: groups
objectclass: organizationalUnit
objectclass: top
      
dn: cn=group1, ou=groups, ou=@realm@, dc=@domain@
memberURL: ldap:///ou=people,ou=@realm@,dc=@domain@??sub?(&(objectClass=person)(wlsMemberOf=cn=group1,ou=groups,ou=@realm@,dc=@domain@))
objectclass: top
objectclass: groupOfUniqueNames
objectclass: groupOfURLs
cn: group1
uniquemember: cn=user1,ou=people,ou=@realm@,dc=@domain@ 
 
dn: ou=people,ou=@realm@,dc=@domain@
ou: people
objectclass: organizationalUnit
objectclass: top
      
dn: uid=user1,ou=people,ou=@realm@,dc=@domain@
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
objectclass: wlsUser
cn: user1
sn: user1
uid: user1
userpassword: welcome1
wlsMemberOf: cn=group1,ou=groups,ou=@realm@,dc=@domain@