Monday, January 17, 2011

My first custom OVD adapter

For a PoC I have been working on I wrote a (demo quality) OVD adapter that I thought might be interesting for others.

In my PoC I had OIF, OAM, OVD and DSEE and OES. In the main use case a user can come along to the SP with an x.509 certificate issued by an issuer known to the SP. The SP is expected to do the normal certificate authentication "stuff" (crypto operations, CRL & OCSP checking) and then make authorization decisions for URLs based upon the user identity including information about the user that the SP doesn't get in advance. To get that information the SP will need to make SAML attribute requests to an IdP.

Out of the box OAM and OIF support this use case via the Oracle Access Manager AuthZ Plug-in. That plug-in makes calls to OIF which in turn goes and gets the necessary attributes from the right IdP. This is great and answers most of the requirement.

The missing bit is that this customer wanted to go further... much, much further. They want to make very fine-grained authorization decisions deep down in their applications (by calling OES). And they want OES to make its decisions based on the attributes coming from the IdP.

My first plan was to write an equivalent to the OAM x.509 Attribute Sharing plug-in for OES. It should have taken me all of a couple of hours start to finish including deploying it in the PoC environment. Naturally I thought to myself "That's not all that interesting. Why don't you do something more clever?". I blame too much caffeine and inadequate sleep for that thought.

Everything in the environment (OAM, OES, WebLogic and a few other things) already make LDAP calls to get user info and make authorization decisions. Why not hide all of the SAML stuff down in OVD. Then there's only one place that needs to talk to OIF.

Click through to see what I did.

First some background. The X.509 Attribute Sharing Profile is a little known profile that allows something inside a Service Provider to ask the Service Provider to ask the Identity Provider to get some attributes about the user.

So it's a "two hop" operation. Something like OAM would make a call to the local SAML Service Provider which includes the DN of the x.509 certificate. The local Service Provider takes that DN and looks though its configuration to figure out which IdP is responsible for the user. The SP then makes a conventional SAML attribute retrieval from the IdP and returns it.

As I mentioned in the intro Oracle ships a plug-in for OAM to make that call. I could have just written the same thing for OES. Had I done that I'd have been done in an hour or maybe a couple of hours if it took longer than expected. Then I could have had a nice dinner and shared a bottle of wine with the sales guy and followed that up with a good night's sleep.

But where's the fun in that?

What I decided to do instead was hide the XASP call inside OVD. OAM would do a search for a user with the certdn set to the DN of the certificate. My plug-in would see that search, make the XASP call, build up a fake record in memory, squirrel it away in a cache and return it back to OVD. The caller would see a regular LDAP record and can retrieve attributes of that record.

Any other apps calling OVD via LDAP can execute a search against the directory and my plug-in should return the right record.

Here's what that looks like in practice...

The environment looks like this:

Here'a a search looking for mail= someone that it has never seen before. In this case my plug-in doesn't find the user in its cache and since it doesn't have a certificate DN it can't make an XASP call. Consequently the search result won't return any users:
$ ldapsearch -x -w welcome1 -b ou=ismyidentity,ou=People,dc=us,dc=oracle,dc=com 'mail=sara.i@ismyidentity.com'
# extended LDIF
#
# LDAPv3
# base  with scope subtree
# filter: mail=sara.i@ismyidentity.com
# requesting: ALL
#

# search result
search: 2
result: 0 Success

# numResponses: 1
Here's an example search with a Certificate DN. When I make this LDAP call the plug-in makes an XASP call and remaps all of the attributes from SAML into their LDAP names:
$ ldapsearch -x -w welcome1 -b ou=ismyidentity,ou=People,dc=us,dc=oracle,dc=com 'certificatedn=CN=Sara.I,OU=ismyidentity,O=Oracle,C=US'
# extended LDIF
#
# LDAPv3
# base  with scope subtree
# filter: certificatedn=CN=Sara.I,OU=ismyidentity,O=Oracle,C=US
# requesting: ALL
#

# sara.i@ismyidentity.com, ismyidentity, People, us.oracle.com
dn: mail=sara.i@ismyidentity.com,ou=ismyidentity,ou=People,dc=us,dc=oracle,dc=
 com
certificateDN: CN=Sara.I,OU=ismyidentity,O=Oracle,C=US
clearanceLevel: S
cleared: T
sn: O
mail: sara.i@ismyidentity.com
displayName: sara
postalCode: USA
givenName: Sara
uid: sara.i
obuseraccountcontrol: ACTIVATED
obver: 10.1.4.0
cn: Sara.I
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
objectclass: oblixOrgPerson
objectclass: authorizationPerson

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
If you repeat the first query again my plug-in returns the same record:
$ ldapsearch -x -w welcome1 -b ou=ismyidentity,ou=People,dc=us,dc=oracle,dc=com 'mail=sara.i@ismyidentity.com'
# extended LDIF
#
# LDAPv3
# base  with scope subtree
# filter: mail=sara.i@ismyidentity.com
# requesting: ALL
#

# sara.i@ismyidentity.com, ismyidentity, People, us.oracle.com
dn: mail=sara.i@ismyidentity.com,ou=ismyidentity,ou=People,dc=us,dc=oracle,dc=
 com
certificateDN: CN=Sara.I,OU=ismyidentity,O=Oracle,C=US
clearanceLevel: S
cleared: T
sn: O
mail: sara.i@ismyidentity.com
displayName: sara
postalCode: USA
givenName: Sara
uid: sara.i
obuseraccountcontrol: ACTIVATED
obver: 10.1.4.0
cn: Sara.I
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
objectclass: oblixOrgPerson
objectclass: authorizationPerson

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
Before you go further a warning: If you're going to try this at home make sure you test if for scalability. It's not entirely clear that this will scale up to thousands of concurrent users. OAM and OVD will easily support that, as will OIF (as both the SP and IdP). But the entire architecture relies on SOAP calls over the Internet and those are notoriously latency heavy. As a result the initial access by a user will be relatively slow and that could cause any number of issues. If a large percentage of your users visit for only a short time those problems will be worse.

Want to follow in my footsteps? First start with the samples available from the samples page at Oracle.com. You'll need the WSDL for the x.509 Attribute Sharing Profile service from the OIF docs. Then find yourself a caching mechanism - perhaps something like Coherence?You'll also want to read my previous post on caching OVD's Entry object.

Other than that it's all pretty straightforward.

If you're interested in my source code let me know in the comments. If there's enough interest I'll put it on samplecode.

6 comments:

  1. Hi Chris,
    Can you share the source code? I am looking into developing a custom adapter and the sample would be helpful.
    Thanks,
    SM

    ReplyDelete
  2. @D can you reach me directly at christopher.johnson at oracle.com? I'll email the code directly to you.

    ReplyDelete
  3. Hi Chris,

    I have question regarding X509 authentication, I have a user authenticating using X509 auth -> OAM -> OVD further talking to OID & Active Directory, are the client certs needs to be loaded into the "userCertificate" attribute of LDAP(OID,AD) for X509 to work or is it optional ?

    Regards,
    KS

    ReplyDelete
  4. @KS That's really a question about OAM rather than OVD.
    Take a look at the settings for the x.509 Authentication Module at http://download.oracle.com/docs/cd/E21764_01/doc.1111/e15478/oam_set.htm#CIHGHFEA

    If you check the "Cert Validation Enabled" box then the certificate needs to be present in the LDAP directory. If you leave it unchecked then the certificate doesn't need to be embedded in the LDAP record.

    ReplyDelete
  5. Perfect. Thank You Chris. One more question related to this, when the OAM connects to OID can it it just use the certificate passed from browser or does it need to make a search first using subjce.CN and then compare the certificate on the LDAP server with the certificate received from the user's browser.

    Is there anyway we can implement this using OVD ? because the certificates are spread into different LDAP directory stores in our case.

    Thanks again for these wonderful blogs.

    Regards,
    KS

    ReplyDelete
  6. No, OAM will not send the certificate the user sent from the browser to the LDAP directory (either in the bind credentials or as a search). Instead it retrieves the certificate and compares it.

    ReplyDelete

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