Saturday, February 28, 2015

Sharing Contributions with ForgeRock via Git Subtree part 2

In my previous post we used Git's subtree feature to pull an existing subdirectory out of a larger maven project and push it to a third party repository for contributing just that subdirectory and below to open source. In today's post we'll see how to tie that subtree to that external repository, make some changes, and selectively push those changes up as well among a few other things.

Replacing with the Now External Source

Currently we have made our subdirectory into a subtree and used a branch to push just its contents and nested directories and resources out. But those contents are still there and not yet tied to the external location that will be the source going forward. Our first step is to remove the existing items.

Back in the root of our main project directory we remove the original directory and correspondingly its subtree to get rid of the original items. Then we commit those changes without pushing. That leaves us one commit ahead of origin/master, the remote on-premise repo. That is an important point to remember.

git rm -r openam-authentication/openam-auth-radius
git commit -m "remove openam-auth-radius to replace with subtree"

Then we define a new remote for referring to the external repository and create a new subtree with that remote as its source. The --squash parameter  means that we only get one commit added to our history indicating the update to the subtree from the repo.

git remote add 
  ext-radius https://github.com/...<fill-in-your-repo>

git subtree add --prefix=openam-authentication/openam-auth-radius 
  --squash ext-radius master

When I did this I ran into the following error on that second command:

prefix 'openam-authentication/openam-auth-radius' already exists.

The directory was still there. Only the Git tracked resources were removed. There was still a target directory left over from the last time I did a build and its contents were still sitting in there. So I used rm -rf to remove the directory completely. Running that second command again resulted in this output from Git:

git fetch ext-radius master
From https://github.com/...<fill-in-your-repo>
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> ext-radius/master
Added dir 'openam-authentication/openam-auth-radius'

Interestingly, if we run git status at this point we are now three commits ahead of origin master. Running git log shows those three commits at the top. The second commit holds the link to the current commit of the external upstream repo. That highlighted commit matches the most recent commit in the repo.

commit ee4b098ad60e55f419789a82a0dc80bd949a3609
Merge: 0ae47a3 ceef534
Author: Mark R. Boyd <boydmr@ldschurch.org>
Date:   Thu Feb 26 10:36:10 2015 -0700

    Merge commit 'ceef534cae7ff8cba41a204867b03766d4422c4b' as 'openam-authentication/openam-auth-radius'

commit ceef534cae7ff8cba41a204867b03766d4422c4b
Author: Mark R. Boyd <boydmr@ldschurch.org>
Date:   Thu Feb 26 10:36:10 2015 -0700

    Squashed 'openam-authentication/openam-auth-radius/' content from commit 2c46086

    git-subtree-dir: openam-authentication/openam-auth-radius
    git-subtree-split: 2c4608649741ce14ce09e21bd766681bf6d219f3

commit 0ae47a3f1f64238ab95883cf9ba22dd01c85911b
Author: Mark R. Boyd <boydmr@ldschurch.org>
Date:   Thu Feb 26 10:28:30 2015 -0700

    removed openam-auth-radius to replace with subtree


If I now look in the openam-auth-radius directory I see my files have been restored. But at this point the files from that directory on down are associated with the upstream external repo. Now lets push to our internal repo shared by the team. In the root of the project I run:

git push

Impact on Other Team Members?

So how do other members of my team see these changes? To simulate another team member I'll clone our on-prem openam repo into another directory, openam2, and then run a maven build:

cd ..
mkdir openam2
git clone https://BoydMR@...<internal repo path> openam2
cd openam2
mvn clean install

Everything builds just as it always has. And why wouldn't it? If you look in the openam-authentication/openam-auth-radius directory the source code is there in contrast with Git submodules whose source isn't in the repo but must be pulled by each user separately. With subtrees the source is in our repo so everyone works just as they always have and knows no difference unless they need to fetch from or push to the subtree's upstream external repo. As long as they are working with the internal remote repo used by the team they see no difference.

Sharing Changes via Internal Repo

To that point, lets try making changes at this point. To be clear, changes may be pushed into the team's internal repo or pushed from the subtree into its external remote by either me or my coworkers. We'll try both. First I'll do the former.

Lets say one of my coworkers needs to tweak a file. Mimicking a coworker I use the openam2 copy of the project and make an edit, commit, and push to the on-premise repo.  I've trimmed some of the path for readability.

git add openam-authentication/openam-auth-radius/src/main/java/.../ConsoleClient.java

git commit -m "removed double print of build date from ConsoleClient startup"

git push

As a member of the team I'd see these changes when next I fetched commits and did a diff with the internal on-premise repo or just did a pull there from. Back in the openam directory and hence a different repo I see the following after doing the fetch to get commits from the internal repo. Recall that this gets commits that I don't have locally but does not merge them into the current branch in contrast to a pull which does both:

git fetch 

git diff master origin/master

And in the output I'll see any changes that were made. And a git status at this point tells me that my current branch master is behind origin/master by one commit since we did a fetch and not a pull. But note that I did not specify a remote. By default it uses the origin remote. If we did a fetch from the remote associated with our subtree we won't get anything brought in from their either because nothing has changed. So lets try that route next.


Seeing Changes in Subtree's External Upstream

Suppose that my coworker made changes to what is now tracked in our subtree directory of openam-authentication/openam-auth-radius and pushed them into the subtree's external upstream remote repo. To simulate that I move to the openam2 directory, edit a file, and commit but will leave those details out to save space. To push to the upstream we need first to add the remote. We have that already in the repository of the openam directory but didn't add it to this repo yet. Once added we then subtree push to the upstream:

git remote add upstream-radius https://github.com/...<fill-in-your-repo>

git subtree push   --prefix=openam-authentication/openam-auth-radius   upstream-radius master


Again we get some interesting output from that last command:

git push using:  upstream-radius master
-n 1/     109 (0)
-n 2/     109 (1)
-n 3/     109 (2)
...
-n 108/     109 (106)
-n 109/     109 (107)
Counting objects: 27, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (15/15), 6.14 KiB | 0 bytes/s, done.
Total 15 (delta 3), reused 0 (delta 0)
To https://github.com/...<fill-in-your-repo>
   2c46086..dd773db  dd773dbe09d065a440f67021f0d309ff4acb7939 -> master

Now that my coworker placed changes in the external library I have older code in my openam repo subtree. But how can I tell that? The steps are the same as with a regular remote. I first do a fetch from that remote to gather those changes. Remember that in the openam repo the remote is ext-radius

git fetch ext-radius master 

The output from this command is:

remote: Counting objects: 15, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 15 (delta 3), reused 15 (delta 3), pack-reused 0
Unpacking objects: 100% (15/15), done.
From https://github.com/ForgeRock/radius-server
 * branch            master     -> FETCH_HEAD
   2c46086..dd773db  master     -> ext-radius/master

And again, now that we have fetched those changes into our repo we can see what effect they will have without pulling them into our current branch:

git diff master origin/master

And sure enough I'll see the changes and how they'll impact my local source. In my next post I'd like to take this one step further and consider how I would collaborate on that upstream library, itself a single maven submodule, a subdirectory, if I didn't have write privileges on it as I have had here. 

See you then.   


Wednesday, February 25, 2015

Sharing Contributions with Forge Rock via Git Subtree

The Radius Server functionality has raised interest in the community and is desired as a feature of Open AM. At the same time there is more to do on the feature set such as adding attribute mapping. Currently, the final success response is a simple Access-Accept response with no fields included as can be seen in that former post. So as work progresses I'd like to be able to do that in my local and on-premis remote repos and when ready with a new feature be able to push those changes as a unit to be included in baseline via an external remote repo.

But that goal is further complicated by how we are currently including Open AM and injecting extensions that we need.

Project Directory Structure

Our approach is to use maven's war overlay plugin as one maven subproject in a larger parent project and have siblings along side it representing separately build-able pieces that replace chunks of Open AM such as the openam-auth-radius maven submodule that we've extended to add the Radius Server functionality. Our project directory structure looks like this:


The root maven project is the top level openam folder. I'll cover the relevant parts beneath that directory. The openam-authentication directory is a maven subproject mirroring Open AM's corresponding submodule. Within this module are two authentication submodules one being openam-auth-radius that contains the original Open AM code with our enhancements. The openam-auth-smsotp is a One Time Passcode authentication module that delivers via an in-house REST SMS service and includes support for both HTTP and Radius clients allowing us to do multi-factor authentication for VPN access as well as web sites.

The openam-extensions includes extension point implementations such as a post authentication processor enabling us to front our older Oracle Access Manager system with Open AM, some custom tag libs for help in skinning the sign-in page, and other supporting runtime code.

The openam-warOverlay directory is a maven submodule that has the magic for pulling in the version of Open AM that we build against (12.0.0 currently) and including the other modules mentioned openam-extensions, openam-auth-smsotp, and openam-auth-radius replacing the corresponding jar where applicable in the Radius case.

Sharing That One Directory

The goal is to share the openam-auth-radius directory with a separate and off-premise Git repo while maintaining a local copy of the code to be worked on as needed and then selectively push enhancements to the external repo only when we have a fully functional feature to contribute. But I need to do this with an existing directory structure. I researched both Git submodules and Git subtrees and felt the latter were the better approach since all members of our internal team would just get the codebase when they clone without having to take steps to pull in the Git submodules themselves.

The steps found here looked exactly like what I needed. The steps that I took follow. In case that other page goes away I'm adding comments here for my reference when I have to do this again.

Extract the Directory as a Git Subtree

First I pull that directory's code out of the project by making an empty Git repo and pushing the current code to it. I created the radius-contrib directory as a sibling to the openam directory but it really could be anywhere outside of an existing Git project.

mkdir ~/git/radius-contrib
cd radius-contrib
git init --bare

Back in the openam project root directory I create a Git subtree by splitting out the openam-auth-radius subdirectory and creating a branch called contribs holding just that directory's code:

git subtree split --prefix=openam-authentication/openam-auth-radius -b contribs

Be forwarned, that step freaked me out a bit as it started dumping the following lines before indicating that the subtree was created. I don't know what they mean but it appears to be part of the process.

-n 1/     104 (0)
-n 2/     104 (1)
-n 3/     104 (2)
...
-n 102/     104 (101)
-n 103/     104 (102)
-n 104/     104 (103)
Created branch 'contribs'
2c4608649741ce14ce09e21bd766681bf6d219f3

Now I push that into my recently created empty repository. To do this I must be sitting in the newly create subtree otherwise you get messages like:

error: src refspec constribs does not match any.
error: failed to push some refs to '/Users/boydmr/git/radius-contrib/'

So change directory as needed and then do the push:

cd ~/git/openam/openam-authentication/openam-auth-radius
git push ~/git/radius-contrib/ contribs:master

Now moving into the directory of the newly created Git repo I can now see the newly created master branch that resulted from that step:

git branch -a
* master

Now we can push just that directory into the external remote repo:

git remote add origin https://github.com/...<fill-in-your-repo>
git push -u origin master

Once pushed that remote repo contains everything that resides within the openam-auth-radius directory and its subdirectories but not the openam-auth-radius directory itself. That is all for today. In my next post I'll take the next steps to now pull that repo into my subtree and even make some changes and push them back.

See you then.

Tuesday, February 17, 2015

Open AM Version Number Source (in 12.0.0)

This post is mostly for me to remember how I found where Open AM's version comes from since I used a number of mechanisms to find it and I don't want to forget them and the trip was amazingly long and convoluted. But I did successfully arrive at an end. And if it helps others when troubleshooting Open AM then that is a bonus.

As shown below, Open AM has a Version button in the top left corner of its admin console when signed in as an administrator. 



When clicking that button you typically get a popup browser window showing Open AM's current version like so:



Upon recently updating one of our servers to version 12.0.0 the update failed to offer us the typical prompt asking if we wanted to upgrade the configuration store. And upon starting the server up we seemed to be in some kind of limbo state where most of the console worked but there were some inaccessible areas including the version. It came up empty as in no version was discernible. Support said that the version was what triggered the prompt to upgrade configuration. And that prompted the following steps to find out the source from which the version value originated.

First: Chrome Developer Tools

That page holds the value. So where is it getting it from. I opened Chrome's Developer Tools, selected the Network pane, and checked Preserve Log so it wouldn't clear after a redirect or loading of a new page. Then I clicked the Version button again. It turns out that the page is loaded from the URL where /sso is Open AM's root in my installation:

/sso/ccversion/Version?
&productNameSrc=../console/images/PrimaryProductName.png
&windowTitle=Version+Information+-+

But this is a frameset with the gray section containing the version number value being loaded from a URL of:

/sso/base/Version

which returns text/html content. Looking through the server's web.xml doesn't show anything mapping to that path directly. Having done some debugging before in Open AM's JATO conundrum led me to wonder if this was being handled by a JATO JSP. Knowing from previous experience with the Login page and its affiliates that JATO typically maps the last path item to a similarly named JSP file I grabbed my next two tools.

Next Up: *nix's Find & Open AM's source

I opened a shell window, changed directory to the root of Open AM version 12's source. If you don't have Open AM's source you can download it from http://openam.forgerock.org/. Then I used "find" to see if there was a file by the name of Version.jsp somewhere in Open AM's source:

find . -name "Version.jsp" 

I'll use find in a number of places below and in each instance I will always be located in the root of Open AM's source. Running this command found a likely candidate at:

/openam/openam-console/src/main/webapp/console/base/Version.jsp

Opening that file and comparing its divs and their classes with the content of the frame convinced me that was indeed the provider of that content. This JSP was a typical JATO JSP. It contained a view bean declaration where the view bean in JATO can be seen as the controller and source of the model backing the JSP:

<jato:useViewBean 
className="com.sun.identity.console.base.VersionViewBean" 
fireChildDisplayEvents="true">

And based upon the divs and their classnames in that page the JSP was injecting the version content using the following tag. In JATO, that name attribute typically ends up being the name of a value set on the view bean:

<cc:text name="txtVersion" />

So back to our good friend Find. I then ran the following command in the root:

find . -name "VersionViewBean.java"

That found the java file at:

/openam/openam-console
/src/main/java/com/sun/identity/console/base/VersionViewBean.java

Fortunately, this view bean class file was only 78 lines long and it did indeed have a line setting a txtVersion value:

setDisplayFieldValue("txtVersion", AMSystemConfig.version);

Looking at imports  and using find the AMSystemConfig class is found in the same subproject at:

/openam/openam-console
/src/main/java/com/sun/identity/console/base/model/AMSystemConfig.java

Now you'd think that would be completely obvious based upon a similar package structure. But be forewarned that that is not always the case. Often I've found similarly packages classes in other Open AM submodules. So when you can't find a file drop back to find and let it do the looking for you. 

AMSystemConfig shows an interesting characteristic of Open AM. Its admin console can be run locally or remotely and delegate to the real servers. If the console is not remote then it gets the value for its version variable from:

SystemProperties.get(Constants.AM_VERSION)

I'll come back to SystemProperties in a minute. If the console is running remotely then a call is made to:

/sso/SMSServlet?method=version

Again looking in my web.xml I see that path is handled by:

<servlet>
        <servlet-name>SMSServlet</servlet-name>
        <servlet-class>com.sun.identity.sm.SMServlet</servlet-class>
</servlet>
...
<servlet-mapping>
    <servlet-name>SMSServlet</servlet-name>
    <url-pattern>/SMSServlet</url-pattern>
</servlet-mapping>

The SMServlet is found in:

/openam/openam-core/src/main/java/com/sun/identity/sm/SMServlet.java

That class too is a small one, only 88 lines long, and shows that it too is getting the value from the same place that AMSystemConfig is when running locally:

SystemProperties.get(Constants.AM_VERSION)

So that confirms where the version number is ultimately coming from. Hence, back to SystemProperties. Again, looking at the package path of the class and using find, I found that SystemProperties is located in:

/openam/openam-core
/src/main/java/com/iplanet/am/util/SystemProperties.java

And now the code got a lot more involved. SystemProperties is over 700 lines long. Its get method looks in a couple different places for values. So that is when I brought in my next tool.

Remote Debugging

One of the things about java that I fell in love with when it came out was the Java Debug Wire Protocol allowing any JVM to be started with debugging turned on even supporting a "suspend" mode preventing any code from running until a debugger connected to the JVM after start up thus allowing us to step through fleeting startup situations as well.

I have Open AM running in Tomcat8. The catalina.sh script supports specifying a parameter of jpda followed by start to trigger launching the JVM in debug mode. The comments at the top of catalina.sh are extremely helpful. By default, it does not start the JVM in debug mode. By adding a setenv.sh script as a peer to catalina.sh you can add values as defined in the comments to override the defaults. 

So I created setenv.sh  with the following value:

export JPDA_SUSPEND="y"

Then I launch tomcat with the following command:

$TOMCAT_HOME/bin/catalina.sh jpda start

And sure enough, using tail on logs/catalina.out shows that the JVM started in debug mode and since no further activity is being logged it appears to be suspended waiting for a debugger to connect to that port.

Listening for transport dt_socket at address: 8000

I use Intellij currently. But used eclipse for a number of years. Both readily support remote debugging. With Intellij open on the POM of the Open AM source:

/openam/pom.xml

I then created a Debug Configuration of type Remote and set the host to be 127.0.0.1 and port 8000. Before starting it up I opened SystemProperties and set a breakpoint at the top of the get method. Then I started up that debug configuration. It connected and some time thereafter I was stepping through that code.

However, I first wanted to know where the version value was coming from. Recalling that the most direct way to trigger retrieval of the version from SystemProperties was through the URL called by AMSystemConfig when the console is running remotely, I entered that URL into the browser and immediately had the debugger stop execution in the method. The key being passed to the method was:

com.iplanet.am.version

The value ultimately was being returned from the props properties object in SystemProperties. To find where that we being loaded I added breakpoints in every location where props was being set or added to. Our desired value was being returned in the Properties object returned from this line in the initializeProperties method. 

ServerConfiguration.getDefaults(appToken)

Again using find I located the ServerConfiguration file in:

/openam/openam-core/src/main/java
/com/sun/identity/common/configuration/ServerConfiguration.java

Stepping through these lines is getting into the core of Open AM's configuration code. It turns out that it load a ServiceConfigManager instance for the iPlanetAMPlatformService, obtains its global configuration, then loads a ServiceConfig instance for its sub configuration of com-sun-identity-servers and from that instance loads another ServiceConfig instance for sub configuration server-defaults.  From that instance of  it then gets the serverconfig attribute which holds a Set of 155 key/value strings with the = character as a delimiter between keys and values. And one of those values is the one we are looking for.

So where does this last paragraph mean? I've had some experience with ServiceConfigManager and  ServiceConfig. If you look in Open DJ at the root of your configuration you'll see the following items. I'm using Apache Directory Studio here. Note that my configuration is at the default location. Your root DN may differ depending on how you configured your system.


Notice the services element. Expanding it and looking for an element with an ou of iPlanetAMPlatformService. This relates to the ServiceConfigManager instance that we acquired. From there each of the other steps relate nicely to the structure beneath that element as shown below. There is a GlobalConfig with a sub configuration of  com-sun-identity-servers  and a sub configuration of server-defaults



By selecting that last item we can see that it has 157 values for the sunKeyValue multivalued attribute. 


Expanding it and looking through the list we find the value that we are searching for. 


And interestingly, if we use Directory Studio to modify the value and refresh the browser we immediately see that change appear.


One Final Note

It should be noted that the relationship between LDAP values and the code should not be relied upon. Things could change from release to release. But the tools and steps to locate this information when problems arise will hopefully be of use to someone. Most likely of course is that person will be me when I come back to my own work six months from now. At which time I'll be grateful for this breadcrumb.

Enjoy.

Wednesday, December 17, 2014

Adding Config Pages Into OpenAM's Console (Legacy not XUI)

My goal in this post is to shed light on how to add configuration values and containing pages into OpenAM's admin console. In a following post I'll outline how to programmatically gain access to the values configured therein. So lets start.

The RADIUS server support added into OpenAM requires a number of configuration parameters. For example, the RADIUS RFC requires that incoming requests only be accepted if from a source IP address of a defined client. All other packets should silently be dropped. Further, the shared secret for a client must be determined by that IP address. Meaning, when looking in the set of defined clients for the shared secret with which to validate the packet only the source IP address should be used to identify the client not some field in the packet. So we need to define clients, their IP address from which their packets will arrive, and the secret shared between the server and the remote client. And there are more values as will be seen.

New configuration pages can be added to OpenAM's admin console via an XML declaration and OpenAM will provide the page rendering, submit processing, data storage, and retrieval later via code including supporting registration of change listeners to be notified when some value has been changed through the console. I refer to these registered "chunks" of configuration as an admin console configuration service and the XML files used to define them as their service descriptor file.

Before I get into the structure of the service descriptor file I need to discus some of the other parameters that are needed and where I want the configuration pages to show up in OpenAM. The RADIUS server feature will listen on UDP port 1812 for incoming requests following the spec. However, I'll support placing it on some other port if desired. The service must supports enabling and disabling the server and when disabled should close the port. Further, the implementation is designed using a thread pool and a limited wait queue ensuring that the server can't be flooded to the point of failure. It also supports any number of remote clients each with their own configuration as noted above.

The Service Descriptor File

With that in mind the service descriptor file: amRadiusServer.xml and its resource bundle file radiusServer.properties are included at the bottom of this post.  Since the documentation isn't very plentiful at present for adding configuration pages into OpenAM's admin console, I arrived at my service descriptor file by looking in the existing UI for another item located in a similar location to where I desired the Radius configuration to show up. And I looked for an item that had similar configuration constructs. The Dashboard service found in the Configuration tab and Global sub-tab was a good match. Everything I need to configure for Radius fits nicely at that global level. And just like the Dashboard I needed a group of sub items to configure, clients. So I found and started with its file as a basis, changed the resource bundle and keys and pushed it into OpenAM as outlined below, over and over until everything looked just right.

The DTD that service descriptor files conform to can be found in an installed instance of OpenAM at web-root/WEB-INF/sms.dtd. There really could be a number of blog posts just on that document alone and the various ways things can show up in the UI depending on what you declare. I'll cover just a few points here.

First is the Service element's name attribute. It has the well-known name of the service; RadiusServerService in my case. NOTE: This name is what we'll need in our code at runtime to acquire what has been configured in the admin console.

Second, in a number of places there is an i18nKey attribute. The value of this attribute is the key in the resource bundle having base name of radiusServer as declared in the Schema's  i18nFileName attribute.  What isn't clear is that the sort order of the keys for a given level, more on that in a minute, defines the order of the fields as they are rendered in the UI. Also unclear is that for each key in the resource bundle you can also have <key>.help and <key>.help.txt properties that will be used by the UI to respectively render descriptive text next to the input control and place an information icon next to the control that can be clicked to see further detail about that input value displayed in a modal box.

Structure wise, note that there is a Global element with a bunch of nested AttributeSchema items and one SubSchema element with its own nested AttributeSchema items. The AttributeSchema items each define one input item be it a list or single field as determined by its type. And there is even some rudimentary validation for different types as defined by the syntax attributes. See the DTD for more detail albeit I had to try a few times before I got everything working the way that I wanted it.

The SubSchema element renders in the admin console as a table amidst the other fields as shown below and gives us the ability to create groupings of additional related fields and edit them in a separate page as a group. Also note the empty Organization element that is a sibling to the Global element for the reason noted in the xml comment. That is important to remember. Without having that element you won't be able to save your configuration values.

Registering the Service Descriptor File

To tell OpenAM about this configuration service we use the ssoadm tool or the ssoadm.jsp page included with OpenAM which is what I've always used. However, by default that JSP is blocked from access. To enable it, log in as an admin, go to the Configuration tab, Servers and Sites sub-tab, select the server for the server on which you want to enable ssoadm.jsp, then select the Advanced sub-tab. In the Advanced Properties pane press the Add button and add a property of ssoadm.disabled with a value of false and press the save button.

Now you can go to http(s)://servername(:port)/your-root/ssoadm.jsp. In the list of links on that page search for create-svc and select it. This presents the screen below in version 11 of OpenAM. Into the text area I pasted the service descriptor file contents as shown and pressed the Submit button resulting in a message that the service was created.


Accessing Your New Pages

The service is available in the UI immediately but will be stuck presenting only keys for labels if the resource bundle is not found. That can be in WEB-INF/classes or included in the root of a jar which is where mine is located; a new openam-auth-radius.jar. You can use my files to give this a try on your own to learn more about this feature. It won't hurt anything. And if you use the delete-svc tool in ssoadm.jsp specifying RadiusServerService when you are done and that will remove the constructs from the console and remove all persisted values.

Once registered the results are seen by signing-in as an admin, selecting the Configuration tab followed by the Global sub-tab. As shown in the image below there is now a RADIUS Server included in the Global Properties table.




Upon selecting the RADIUS Server link OpenAM generates the global attributes declared and generates the Secondary Configuration Instances table for the sub-schema element.  You see that we can enable or disable the RADIUS service which essentially opens or closes the UDP port. And we can customize our thread pool parameters that we declared. To see the fields defined within the sub-schema we press the Add button in the table.



Creating Radius Clients

Upon pressing the Add button in the table I am presented with the fields declared in the sub-schema as shown below.


I'll post specifics about configuring these clients as I explain the Radius support that is now working in my local OpenAM instance. Until then...Enjoy.

Admin Console Configuration Service Descriptor File for Radius Server


<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE ServicesConfiguration
PUBLIC "=//iPlanet//Service Management Services (SMS) 1.0 DTD//EN"
"jar://com/sun/identity/sm/sms.dtd">

<ServicesConfiguration>
 <Service name="RadiusServerService" version="1.0">
  <Schema
    serviceHierarchy="/DSAMEConfig/RadiusServerService"
    i18nFileName="radiusServer"
    revisionNumber="1"
    i18nKey="radius-server-service-description">

   <Global validate="yes" >
    <AttributeSchema name="radiusListenerEnabled"
         type="single_choice"
         syntax="string"
         i18nKey="a-radius-listener-enabled-label">
     <ChoiceValues>
      <ChoiceValue i18nKey="choiceYES">YES</ChoiceValue>
      <ChoiceValue i18nKey="choiceNO">NO</ChoiceValue>
     </ChoiceValues>
     <DefaultValues>
      <Value>NO</Value>
     </DefaultValues>
    </AttributeSchema>

    <AttributeSchema name="radiusServerPort"
         cosQualifier="default"
         i18nKey="b-radius-port"
         isSearchable="no"
         syntax="number_range"
         rangeStart="1025"
         rangeEnd="65535"
         type="single" >
     <DefaultValues>
      <Value>1812</Value>
     </DefaultValues>
    </AttributeSchema>

    <AttributeSchema name="radiusThreadPoolCoreSize"
         cosQualifier="default"
         i18nKey="c-radius-thread-pool-core-size"
         isSearchable="no"
         syntax="number_range"
         rangeStart="1"
         rangeEnd="100"
         type="single" >
     <DefaultValues>
      <Value>1</Value>
     </DefaultValues>
    </AttributeSchema>

    <AttributeSchema name="radiusThreadPoolMaxSize"
         cosQualifier="default"
         i18nKey="d-radius-thread-pool-max-size"
         isSearchable="no"
         syntax="number_range"
         rangeStart="1"
         rangeEnd="100"
         type="single" >
     <DefaultValues>
      <Value>10</Value>
     </DefaultValues>
    </AttributeSchema>

    <AttributeSchema name="radiusThreadPoolKeepaliveSeconds"
         cosQualifier="default"
         i18nKey="e-radius-thread-pool-keepalive-seconds"
         isSearchable="no"
         syntax="number_range"
         rangeStart="1"
         rangeEnd="3600"
         type="single" >
     <DefaultValues>
      <Value>10</Value>
     </DefaultValues>
    </AttributeSchema>

    <AttributeSchema name="radiusThreadPoolQueueSize"
         cosQualifier="default"
         i18nKey="f-radius-thread-pool-queue-size"
         isSearchable="no"
         syntax="number_range"
         rangeStart="1"
         rangeEnd="1000"
         type="single" >
     <DefaultValues>
      <Value>10</Value>
     </DefaultValues>
    </AttributeSchema>

    <SubSchema name="radiusClient"
         inheritance="multiple"
         maintainPriority="no"
         supportsApplicableOrganization="no"
         i18nFileName="radiusServer"
         i18nKey="client-config-instance">
     <AttributeSchema name="clientIpAddress"
          i18nKey="a-client-ip-address-label"
          isSearchable="no"
          syntax="string"
          type="single" >
     </AttributeSchema>
     <AttributeSchema name="clientSecret"
          i18nKey="b-client-secret-label"
          isSearchable="no"
          syntax="string"
          type="single" >
      <DefaultValues>
       <DefaultValuesClassName className="com.sun.identity.authentication.modules.radius.server.config.DefaultClientSecretGenerator"></DefaultValuesClassName>
      </DefaultValues>
     </AttributeSchema>
     <AttributeSchema name="clientPacketsLogged"
          type="single_choice"
          syntax="string"
          i18nKey="c-client-log-packets">
      <ChoiceValues>
       <ChoiceValue i18nKey="choiceYES">YES</ChoiceValue>
       <ChoiceValue i18nKey="choiceNO">NO</ChoiceValue>
      </ChoiceValues>
      <DefaultValues>
       <Value>NO</Value>
      </DefaultValues>
     </AttributeSchema>

     <AttributeSchema name="handlerClass"
          i18nKey="d-handler-class"
          isSearchable="no"
          syntax="string"
          type="single" >
      <DefaultValues>
       <Value>com.sun.identity.authentication.modules.radius.server.spi.handlers.OpenAMAuthHandler</Value>
      </DefaultValues>

     </AttributeSchema>
     <AttributeSchema name="handlerConfig"
          i18nKey="e-handler-config-params"
          isSearchable="no"
          syntax="string"
          type="list" >
     </AttributeSchema>
    </SubSchema>
   </Global>
   <!--
   Having an Organization declaration is required before
   openAM will allows us to save an instance of the global
   SubSchema. Otherwise, it gives an error upon saving saying,
   "The service RadiusClientService does not have organization
   schema." By adding an empty Organization no configuration
   is added to the Services tab for this service in realms but
   we can persist our configuration.
   -->
   <Organization>
   </Organization>

  </Schema>
 </Service>
</ServicesConfiguration>

radiusServer.properties resource bundle file


radius-server-service-description=RADIUS Server

a-radius-listener-enabled-label=Enabled
a-radius-listener-enabled-label.help=The RADIUS Server will only open a port and listen for requests when enabled.
choiceYES=YES
choiceNO=NO

b-radius-port=Listener Port
b-radius-port.help=The UDP port on which each OpenAM server will listen for RADIUS Access-Request packets
b-radius-port.help.txt=According to the RADIUS Authentication Specification, RFC 2865, the officially assigned port number for RADIUS is 1812. We allow values from 1025 up to 65535. Requests for all Clients are handled through the same port.

c-radius-thread-pool-core-size=Thread Pool Core Size
c-radius-thread-pool-core-size.help=Click the Info icon for details from ThreadPoolExecutor javadoc.
c-radius-thread-pool-core-size.help.txt=When a RADIUS request is received and fewer \
than corePoolSize threads are running, a new thread is created to handle the request, even if other worker threads \
are idle. If there are more than Pool Core Size but less than Pool Max Size threads running, a new thread will be \
created only if the queue is full. By setting Pool Core Size and Pool Max Size the same, you create a fixed-size \
thread pool. Limited from 1 to 100.<br/><br/>

d-radius-thread-pool-max-size=Thread Pool Max Size
d-radius-thread-pool-max-size.help=See notes and range restrictions for Thread Pool Core Size.

e-radius-thread-pool-keepalive-seconds=Thread Pool Keep-Alive Seconds
e-radius-thread-pool-keepalive-seconds.help=Click the Info icon for details from ThreadPoolExecutor javadoc.
e-radius-thread-pool-keepalive-seconds.help.txt=If the pool currently has more than Thread Pool Core Size threads, \
excess threads will be terminated if they have been idle for more than the Kee-Alive Seconds. Limited from 1 to 3600.

f-radius-thread-pool-queue-size=Thread Pool Queue Size
f-radius-thread-pool-queue-size.help=Number of request that can be queued for the pool. Click the Info icon for details.
f-radius-thread-pool-queue-size.help.txt=The number of requests that can be queued for the pool before further requests \
will be silently dropped. See notes for Thread Pool Core Size on the interplay with Pool Max Size. Limited from 1 to 1000.

client-config-instance=Radius Client

a-client-ip-address-label=Client IP Address
a-client-ip-address-label.help=The IP Address of the client.
a-client-ip-address-label.help.txt=Section 5.4 of the RADIUS Authentication Specification, RFC 2865, indicates that \
  the source IP address of the Access-Request packet MUST be used to identify a configured client and thence determine \
  the shared secret to use for decrypting the User-Password field. The Client IP Address field should hold the source IP address of the \
  client. This should match the value obtained from Java's InetSocketAddress.getAddress().toString(). If there is any \
  question, send an Access-Request packet to OpenAM's RADIUS port and watch for a message stating, "No Defined RADIUS Client \
  matches IP address '/127.0.0.1'. Dropping request." Then copy the value in single quotes into this field.


b-client-secret-label=Client Secret
b-client-secret-label.help=This secret shared between server and client for encryption of the user password.
b-client-secret-label.help.txt=This secret must be conveyed to the RADIUS client and entered into its configuration \
before the User-Password field of incoming Access-Request packets can be decrypted to validate the password for the \
represented by that packet. A default value is generated for you but you can enter a custom value if desired.

c-client-log-packets=Log Packet Contents for this Client
c-client-log-packets.help=Indicates if full packet contents should be dumped to the log.
c-client-log-packets.help.txt=When troubleshooting issues with RADIUS it is helpful to know what was received in \
  a given packet. Enabling this feature will cause packet contents to be logged in a human consumable format. The \
  only caveat is that the USER_PASSWORD field will be obfiscated by replacing with asterisks. This should only be \
  enabled for troubleshooting as it adds significant content to logs and slows processing.


d-handler-class=Handler Class
d-handler-class.help=The fully qualified name of a class to handle incoming RADIUS Access-Requests for this client.
d-handler-class.help.txt=This class must implement the <code>com.sun.identity.authentication.modules.radius.server.spi.AccessRequestHandler</code> \
  interface to handle incoming Access-Request packets and provide a suitable response. An instance of this class is \
  created when configuration is first loaded to validate the class and then once for each new request. The configuration \
  properties will only be passed for the request handling instances and not when validating the class.<br/><br/><br/>

e-handler-config-params=Handler Class Configuration Properties
e-handler-config-params.help=Properties needed by the handler class for its configuration.
e-handler-config-params.help.txt=These properties are provided to the handler via its \
  <code>init</code> method prior to the call to handle the request packet. If these values are changed the next \
  handler instance created for an incoming request will receive the updated values. Each entry assumes that the first '=' \
  character incurred separates a key from its value. All entries are placed in a properties file handed to each handler \
  instance<br/><br/><br/>




Tuesday, December 9, 2014

OpenAM Answers Its 1st RADIUS Request

For those who are waiting to hear back on the progress adding RADIUS Server support to OpenAM, your wait is over. Pasted below is the output of the first ever successful authentication response from OpenAM to a RADIUS client. It just so happens that this client is also included in the codebase enhancements. It is a very simple command line client that I've included for testing purposes. It uses a radius.properties config file in the current directory containing the following items telling it where to connect, the secret shared with the RADIUS server for encryption and integrity checks, and if packets should be dumped in a readable fashion to the command line.

$ cat radius.properties
secret=MY-SECRET
host=127.0.0.1
port=1812
show-traffic=true

Upon startup it prompts for username and password (please don't tell anyone my demo user's password ;-) and then sends a RADIUS AccessRequest to the targeted server. Upon receiving an AccessAccept response it dumped that response to the console as shown below and then exited. Those NAS fields are hard coded and have no meaning in this test but are required by the RFC to make the incoming request be valid on the server side.

$ java -cp openam-auth-radius-11.0.2-2014.12.09_04.15.jar com.sun.identity.authentication.modules.radius.ConsoleClient
? Username: demo
? Password: password

Packet To 127.0.0.1:1812
  ACCESS_REQUEST [1]
    - USER_NAME : demo
    - USER_PASSWORD : *******
    - NAS_IP_ADDRESS : localhost/127.0.0.1
    - NAS_PORT : 1200

Packet From 127.0.0.1:1812
  ACCESS_ACCEPT [1]

---> SUCCESS! You've Authenticated!


How about entering the wrong password? We are denied access as expected.

$ java -cp target/openam-auth-radius-11.0.2-2014.12.09_04.15.jar com.sun.identity.authentication.modules.radius.ConsoleClient
? Username: demo
? Password: bad-password

Packet To 127.0.0.1:1812
  ACCESS_REQUEST [1]
    - USER_NAME : demo
    - USER_PASSWORD : *******
    - NAS_IP_ADDRESS : localhost/127.0.0.1
    - NAS_PORT : 1200

Packet From 127.0.0.1:1812
  ACCESS_REJECT [1]

---> Sorry. Not Authenticated.

I'll be posting more entries on the RADIUS solution and how it is configured and hopefully some of what I've learned about OpenAM's internal workings. But for now, to be clear, I've only defined this one client in the OpenAM console instructing OpenAM to authenticate requests for that particular client against the root realm, "/", and authentication chain, "ldapService", which only contains the DataStore authentication module within it. So what happens when there are more modules in the chain?

Stay tuned.