Wednesday, April 8, 2015

Open AM Realms and Authentication Chains

Wow. Two posts in one day. I've had this one ready to publish for a while and wanted to get it out there before I forget everything.

As I refine the RADIUS support being added to Open AM I've run across a few items that I want to preserve so that I don't loose them. I hope they are of benefit to others.

Realms

Open AM provides the concept of Realms. In a newly installed instance of Open AM there is one realm named '/' known as the root realm. Any number of realms can be defined and are conceptually presented in the admin console as being children of the root realm as shown below.


Authentication Chains

In OpenAM Users can only authenticate through another OpenAM construct called an authentication chain. An authentication chain is defined in a realm on the Authentication tab for that realm. A chain has a name and from one to many Authentication Module instances placed within it. These module instances must be created before they can be embedded in any chain. A single module instance can be embedded within multiple chains if desired since these instances are actually instances of configuration. When actually used for authentication, the underlying Pluggable Authentication Module class for the authentication module is instantiated, given a copy of this instance configuration, and is allowed to contribute its authentication behavior to the authentication experience provided to the user by the chain.

Modules in the chain have order meaning users must pass the requirements for an earlier module in the chain before incurring the requirements for modules later in the chain. This order is presented vertically in the admin console as shown below. Authentication by a user proceeds through the modules in the chain from top to bottom.



If any authentication chains exist in the top level realm when a new realm is created, those chains and correspondingly their module configuration instances will be copied into the new realm. If they are deleted from that new realm or any configuration changes are made to the configuration instances in that other realm it has no impact on those in the root realm.

LDAP Constructs

Interestingly, from an ldap perspective, the OpenAM DN at which OpenAM is installed (such as dc=openam,dc=forgerock,dc=org), has an ou=services child node that holds a number of child nodes mostly for the root realm. For example, in OpenAM version 11.0.0 the authentication chains defined for that realm show up in ou=services, ou=iPlanetAMAuthConfiguration, ou=1.0, ou=OrganizationConfig, ou=default, ou=Configurations with nodes therein each representing a given chain by name:


Any new realms show up as child nodes of the base ou=services node as well. And within each of those there is an ou=services node that has a subset of the top level ou=services nodes children copied within. Note the entries for the "again", "another", and "yet-another" in the image below corresponding to the realms listed in the first image above. And if you look in the corresponding path noted above for authentication chains you'll find the chains for that realm. Hence why changing config for a chain in a newly created realm does not affect the configuration that was copied from the root realm.



Programmatically Listing Realms and Their Chains

The set of defined realms that are currently defined in OpenAM can be acquired by the following code:

   SSOToken admTk = (SSOToken) AccessController.doPrivileged(
     AdminTokenAction.getInstance());

   // see what realms we have available to us
   OrganizationConfigManager ocm = null;
   try {
    ocm = new OrganizationConfigManager(admTk, "/");
   } catch (SMSException e) {
    cLog.log(Level.SEVERE, "----- Unable to get realms", e);
   }
   Set<String> realms = null;
   if (ocm != null) {
    realms = CollectionUtils.asOrderedSet("/");
    try {
     realms.addAll(ocm.getSubOrganizationNames("*", true));
     cLog.log(Level.INFO, "---->>> realms: " + realms);
    } catch (SMSException e) {
     cLog.log(Level.SEVERE, "----- Unable to get sub-realms", e);
    }
   }

Once I have the set of realm names I can loop through each and acquire the set of defined chains by name with the following code:

if (realms != null) {
 ConfiguredAuthServices cas = new ConfiguredAuthServices();

 for(String realm : realms) {
  Map parms = new HashMap();
  parms.put(Constants.ORGANIZATION_NAME, realm);
  parms.put(Constants.SSO_TOKEN, admTk);
  Map vals = cas.getChoiceValues(parms);
  cLog.log(Level.INFO, "--->>> '" + realm + "' chains: " + vals);
 }
}

The output of these lines is as shown below with highlighting added for clarity and the timestamp and class name and other cruft trimmed from the front of the lines. I can see the realms as shown in the first image above. I can see the chains of the root realm reflected in some of the other realms. Where they are not found is where I went into that realm and removed that chain. And you can see where I've added new chains to a given realm. Those Empty chains are a concern.

realms: [/, another, again, yet-another, more]
chains for realm /: {smsotp=smsotp, [Empty]=[Empty], ldapService=ldapService, local-radius-1815-server=local-radius-1815-server}
chains for realm another: {smsotp=smsotp, [Empty]=[Empty], ldapService=ldapService, local-radius-1815-server=local-radius-1815-server}
chains for realm again: {smsotp=smsotp, [Empty]=[Empty], againChain2=againChain2, ldapService=ldapService, againChain1=againChain1, againChain3=againChain3, local-radius-1815-server=local-radius-1815-server}
chains for realm yet-another: {smsotp=smsotp, [Empty]=[Empty], ldapService=ldapService, yetAnotherChain=yetAnotherChain, local-radius-1815-server=local-radius-1815-server}
chains for realm more: {smsotp=smsotp, testOne=testOne, [Empty]=[Empty], ldapService=ldapService, local-radius-1815-server=local-radius-1815-server}

At some point I hope to modify the current RADIUS Server config page to provide a dropdown of al l realm/chain combinations from which to select a value rather than require users to enter the realm and chain names as outlined in a previous blog.  These will be very useful notes to have whenever I get time to polish off that RADIUS support.

Enjoy.





No comments:

Post a Comment