Month: June 2010

OpenDS 2.3.0 as embedded configstore in trunk

In the last few days the OpenAM trunk has been upgraded to use OpenDS 2.3 for embedded datastore, which is quite a big step from OpenDS 1.0. This change also affects the building process, so here are the changes, that you need to do to be able to build your OpenAM again:

  • Download OpenDS 2.3.0-build003
  • extract the zip to opensso/products/opends folder.
  • Copy the je.jar and OpenDS.jar from OpenDS-2.3.0-build003/lib folder into opensso/products/extlib directory (overriding the old ones).
  • Run the following command:
./create_opends_zip.sh OpenDS-2.3.0-build003
  • copy the resulted opends.zip also in the extlib folder.

And off you go, you can build your OpenAM now any way you want. πŸ™‚

Proper way of changing password in OpenAM

There is always a point, when an OpenAM user ends up asking the question: ‘but how can my users change their passwords?’. The answer is quite tricky: there are several ways to do this, but you’re going to have problems with almost each one of them. But first things first, let’s see what do we want exactly:

  • Show an own form for the user, where he/she can give the old password, new password / confirmation of the new password combo and press the button, which changes the password with help of OpenAM.
  • Change the users password in LDAP without enabling the force-reset password LDAP control. (Note this is only important if you use LDAP datastore, JDBC datastore is in early access stage, this article will not cover that).

This second point is not mandatory, but this feature is used often (by the LDAP module for example).
Note: your Directory Server configuration should contain a force-change-on-reset option with true value. The force-change-on-reset mode means, that if the password was resetted by an LDAP administrator, then the user HAS TO change his/her password to be able to do anything.
Note 2: if your DS uses this option, and you’re using the Datastore module (so something that’s not based on the LDAP module), then your module will genuinely fail, if you’re not handling this special case.

So what’s the proper way?

The proper way is when you have the old password, you validate it (by doing a BIND request) to make sure, that the user is who he tell he is. If the BIND was successful, then we execute a MODIFY command in the name of the just logged in user to modify the userPassword field. This is the proper way, because with this logic you are not resetting your password with the help of an administrator, so the force-reset stays false.

The REST API way

The REST API does not have a specific changepassword function, but it does have an update function as I mentioned in my earlier post. This also means, that because you don’t supply the old password, you just can’t reset the password as yourself, it has to run in the LDAP admins name, so this is a force-reset always! So the magic here is that you call the following REST function:

https://<FQDNSSO>/openam/identity/update?identity_name=aldaris&
identity_realm=/&identity_attribute_names=userPassword&
identity_attribute_values_userPassword=newPass

Doing this as the logged in user

If you do have the users sessionid, then you could call this resource as the user, IF your DS does not forbid modifying the userPassword for example with an ACI. OpenDS by default has the following global-aci:

(targetattr="audio||authPassword||description||displayName||givenName||
homePhone||homePostalAddress||initials||jpegPhoto||labeledURI||mobile||
pager||postalAddress||postalCode||preferredLanguage||telephoneNumber||
userPassword")(version 3.0; acl "Self entry modification"; allow (write)
userdn="ldap:///self";)

This will enable you to modify your own password.

Doing this as admin

Since you’re doing this as admin, the password will be certainly overwritten.

The WebService way

The WebService way and the REST API way does not differ from each other, since they are both using the exact same code.

The ClientSDK way

The ClientSDK has several way accessing an Identity, for example using AMIdentityRepository:

SSOToken token = //getting an SSOToken object
AMIdentityRepository idRepo = new AMIdentityRepository(token, "/realm");
IdSearchResults results = idRepo.searchIdentities(IdType.USER, "aldaris",
    new IdSearchControl());
Set identities = results.getSearchResults();
AMIdentity identity = (AMIdentity) identities.iterator().next();

Using AMIdentity#store

The idea here is to use the setAttributes method to update the desirable attributes and then call the store, something like this:

AMIdentity identity = ...
Map attrs = new HashMap();
Set values = new HashSet(1);
values.add(newPass);
attrs.put("userPassword", values);
identity.setAttributes(attrs);
identity.store();

The problem with AMIdentity#store is the same as with the update function: you don’t supply the old password for the function, so there is no way, that this could end up without a force-reset. Also this solution worked for me with an IdRepo created with user token.

Using AMIdentity#changePassword

The AMIdentity class also has a changePassword method, which does exactly what we want, so let’s see some code:

AMIdentity identity = ...
identity.changePassword(oldPass, newPass);

but I had one problem with this: when I accessed the AMIdentity from an IdRepo with a usertoken, then I had the following error message:

Permission to perform the read operation denied to
id=aldaris,ou=user,dc=opensso,dc=java,dc=net

For me this does not make any sense, since I’m giving the old password and the new one, the username is supplied by the AMIdentity itself, then why do I need read permission and for what?? Anyway, when I did this with admintoken, then everything was working great without force-reset.

The OpenAM console way

There is also a way to change your password with help of OpenAM console. Just point your browser to

https://<FQDNSSO>/openam/user/UMChangeUserPassword

I tried it many times, but the Old password field was always disabled for me, so this password change method also sets the force-reset bit…

Summary

As you can see there are many ways to change a users password, but the best way I think is to use ClientSDK with AMIdentity#changePassword or LDAP API directly. For testing the pwdReset flag I’ve used the following command:

ldapsearch -D "cn=Directory Manager" -b "ou=forgerock,o=org" -h localhost
-p 1389 -w password "uid=aldaris" "pwdReset"

If you don’t need the force-change-on-reset functionality, then probably you can disable it in your Directory Server. If you want to hack, then maybe you can try out to delete the pwdReset attribute with the REST API, maybe it will work, I haven’t tried it.

Resolving SAML Federation redirect bug

Sadly OpenAM Snapshot 9 is shipped with a small Federation bug, which shows up in the following form:

When a user came from an SP, the login form is showed up, but when he tries to submit the form, the page is simply reloaded and the GET parameters are gone, so when he tries to login again, then the login works, but the browser is redirected to the default success URL and not the original SP-protected page. Also if you check your webcontainer log files, then you should see something like this:

[WARNING] Could not load ViewBean class "com.sun.identity.authentication.UI.
RedirectViewBean" via Class.forName(); attempting to use current thread's
context class loader

The problem is that the browser was redirected to /opensso/UI/Redirect instead of /opensso/UI/SSORedirect. This issue is known (OPENAM-3), and it is already resolved in OpenAM trunk, so if you need a patch for this, then here it is, apply it, and federation will work as good as in the old days. πŸ˜‰

How to develop custom auth module

NOTE: if you’re looking for a quick way to learn how to develop auth modules, then you may want to read this or this instead.

In the OpenAM world an authentication module is responsible for authenticating a user, but sometimes the method of authentication is not that simple, as we think. For example the OpenAM gives out-of-the-box support for LDAP, Cert, SPNEGO token, etc. based authentication, but what happens if you need to authenticate (for some reason) from a WebService, this is when you’re probably going to end up developing a custom authentication module.

OpenAM is using JAAS, so if you don’t know what JAAS is, probably you need to read this, this is going to help you understand the basic concepts of the Auth API.

To create an authentication module, you’re going to need the followings:

  • Configuration-UI descriptor XML with localization
  • Callback-descriptor XML for login page UI
  • Some java code for authentication logic
  • maybe some JSP
  • and lot’s of lot’s of OpenAM container restarts πŸ™‚

So based on these needs I’m going to write a few more posts in this area, probably in the following structure:

  • Configuration basics
    • Config UI elements
    • Validation of configuration
  • Login UI basics
    • Callbacks
    • Dynamic Callback-handling
  • How to write the Java code
  • Gotcha’s, best practices
  • How to install auth module

I hope you will find these articles useful, some of them are new stuff for me too, so it may going to need some time to write them, but they’re going to (Forge)ROCK! πŸ˜€