Category: Agents

How to determine NSS/NSPR versions on Linux

Reverse engineering is a quite important skill to have when working with OpenAM, and this is even more the case for the web policy agents. Determining the version of the NSS and NSPR libraries may prove important when trying to build the agents, so here is a trick I’ve used in the past to determine the version of the bundled libraries.

To determine the version for NSPR, create nspr.c with the following content:

#include <dlfcn.h>
#include <stdio.h>

int main() {
        void* lib = dlopen("/opt/web_agents/apache24_agent/lib/libnspr4.so", RTLD_NOW);
        const char* (*func)() = dlsym(lib, "PR_GetVersion");
        printf("%sn", func());

        dlclose(lib);
        return 0;
}

Compile it using the following command (of course, make sure the path to the library is actually correct), then run the command:

$ gcc nspr.c -ldl
$ ./a.out
4.10.6

Here is the equivalent source for NSS, saved under nss.c:

#include <dlfcn.h>
#include <stdio.h>

int main() {
        void* lib = dlopen("/opt/web_agents/apache24_agent/lib/libnss3.so", RTLD_NOW);
        const char* (*func)() = dlsym(lib, "NSS_GetVersion");
        printf("%sn", func());

        dlclose(lib);
        return 0;
}

And an example output would look like:

$ gcc nss.c -ldl
$ ./a.out
3.16.3 Basic ECC

To determine the correct symbol names I’ve been using the following command:

nm -D libns{s,p}*.so | grep -i version

NOTE: While this code works nicely on Linux, for Windows and Solaris you will probably need a few adjustments, or there are potentially other/better ways to get information on the libraries.

How to compile 3.3.3 web agents on Linux

Trying to build the web policy agents may be a little frustrating at times, especially because it is generally not that well documented. As part of the 3.3.3 agent release I had the joy of going through the build process of the Linux web agents, so here you go, here are the steps I’ve gone through to build the agents on a freshly installed CentOS 5.10 (32 & 64 bit). For the very keen, I’ve also aggregated all the commands into shell scripts, you can find them at the bottom of this post.

Packages

On an out of the box CentOS 5.10 installation gcc is already installed, but there are some other components you should make sure you have installed before attempting to compile the agents:

  • subversion: To check out the source code of the agents.
  • ant: To perform the build, the agents are using Ant scripts to define the build steps.
  • zlib-devel: Compilation time dependency.
  • gcc-c++: C++ compiler.
  • rpm-build: RPM packages are being generated as part of the build process.
  • gcc44: Building NSS requires a newer GCC than the default one.
  • java-1.6.0-openjdk-devel: JDK to be able to build the agent installers (and run the Ant scripts).

The agent dependencies

The agents rely on the following external libraries:

  • NSS 3.16.3 & NSPR 4.10.6
    On 32 bit the component should be built with:

    make BUILD_OPT=1 NS_USE_GCC=1 NSS_ENABLE_ECC=1 NSDISTMODE="copy" CC="/usr/bin/gcc44 -Wl,-R,'$$ORIGIN/../lib' -Wl,-R,'$$ORIGIN'" nss_build_all

    On 64 bit the command is:

    make USE_64=1 BUILD_OPT=1 NS_USE_GCC=1 NSS_ENABLE_ECC=1 NSDISTMODE="copy" CC="/usr/bin/gcc44 -Wl,-R,'$$ORIGIN/../lib' -Wl,-R,'$$ORIGIN'" nss_build_all
  • PCRE 8.31
    On 32 bit:

    ./configure --with-pic --enable-newline-is-anycrlf --disable-cpp

    On 64 bit:

    CC="gcc -m64" CXX="g++ -m64" ./configure --with-pic --enable-newline-is-anycrlf --disable-cpp
  • libxml2 2.9.1
    On either platform:

    ./configure --prefix=/opt/libxml2 --with-threads --with-pic --without-iconv --without-python --without-readline
  • The header files of various web containers

Once all the libraries are in place, you can run the build on 32 bit:

ant nightly

on 64 bit:

ant nightly -Dbuild.type=64

And here are the shell scripts:
64-bit
32 bit

Java EE agent internals

Not so long ago I’ve been working on JBoss v7 agent, so let me try to sum up some of my findings with Java EE agents in general.
A Java EE agent basically stands from 4 main components:

  • Installer
  • Container specific JAAS integration
  • Java EE Filter implementation
  • Agent application

Let’s go through each one of these and see how they really work.

Agent installer

As its name suggest, the agent installer helps to install the Policy Agent (PA) on the chosen Java EE container. The main behavior of the installer is defined within config/configure.xml file. This file is basically a big XML descriptor of the followings:

  • interactions – what should be asked from the user when performing install/custom-install/migrate/uninstall
  • tasks – what tasks needs to be performed as part of the agent installation, things like backup, creating directory layout, etc

So basically this XML describes how the installer should work in general. Now let’s go even more deeper…

Interactions

During an agent installation all user input is being stored in a thing called IStateAccess (well sometimes there is a persistent=”false” interaction which isn’t persistent, but that part I don’t fully grasp yet πŸ™‚ ).
As part of an interaction it is possible to set up different validators (even custom ones), so for example this makes it possible that a given agent is actually installed on a supported container version. For example with JBoss we are running “JBOSS_HOME/bin/instancename.(bat|sh) –version” command to get back the version number of the JBoss instance, parse it and if it matches, we let the installer further.

Tasks

Tasks are usually just a well defined “change” that needs to be performed by the installer. Implementing a task is not just performing a given change, rollback is just as important part of it. In order to make an agent work, it is very likely that some container specific configuration file needs to be modified (for example to configure/enable the JAAS integration), the necessary file paths are all calculated based on the user input during the interactions (IStateAccess).
Usually an agent installer performs the following tasks:

  • creating backups for the container’s configuration files
  • perform modifications to the container configuration
  • create agent directory layout (i.e. creating the Agent_00x folder structure)
  • encrypt the agent profile’s password and save it in the agent bootstrap config
  • generate the configuration files based on the values provided to the installer
  • in certain scenarios: deploy agentapp.war in the container
  • in case of custom-install: create agent profile if needed

As you can probably see there is nothing super magical about the agent installer, its sole purpose is basically to make the deployer’s life easier by automating this whole process.
I feel we heard enough about the installer for now, so let’s go a bit further and see what the JAAS integration is really all about.

Container specific JAAS integration

JAAS in general isn’t that new really, it’s been part of JRE 1.4 already, so let’s look at it very shortly (here is a longer version):

  • You can implement a custom authentication module
  • You can define authentication “chains” using built-in/custom modules in a configuration file

Well hopefully this concept doesn’t sound too new for you, since the whole OpenAM authentication system is based on JAAS. πŸ˜‰
As an extra, application servers tend to have the concept of “JAAS realm”, which is basically a collection of users (to be sparse as much as possible). Unfortunately there is not much standard around implementing JAAS support for application servers, so this part of the agents is different per container (and sometimes even across container versions).

Advantages of JAAS

Well the main advantage of JAAS is that it can help making the OpenAM integration as less intrusive as possible, but there are others as well:

  • Retrieving the logged in user’s name is quite simple, you can call request#getRemoteUser() or request#getUserPrincipal().
  • By setting up Java EE Security it is possible to define roles in the application’s descriptor files and later on in your application you can just simply check against these using request#isUserInRole(String) (authorization).
  • In case you later on decide to use an LDAP based JAAS module instead, the idea is that you can simply switch out the JAAS login module (of course you’ll need to configure it to work similarly to OpenAM), without actually modifying any part of your application code.
  • While this is already good enough, I think JAAS really pays off when EJBs are used in applications. In that case you can use the @DeclareRoles and @RolesAllowed annotations and magically your EJB method will be protected, only those in the configured role can actually invoke the method (anything else results in failure), which sounds quite neat. πŸ™‚

So what about agents?

The Java EE agents support JAAS, they integrate well with the container and within the agent configuration it is possible to set up role mapping based on pretty much any arbitrary data (session property, profile attribute). To enable JAAS support though you must ensure that you configure the agent in J2EE_POLICY or ALL mode. While it is possible to define security-constraints in web.xml to protect access to pages, usually that’s a bit cumbersome, instead it’s probably simpler to just define OpenAM policies (i.e. use the agent in ALL mode), and only use JAAS for the previously described goodies.

Java EE Filter implementation

The agent itself is implemented as a Java EE filter, which is (obviously) standard, so this part is common for all the agents and as such it is part of the agent SDK. When the filter intercepts a given request, it will basically go through a list of “TaskHandlers” and execute them in a predefined order. If a given TaskHandler returns with an AmFilterResult, then the processing stops and the result will be handled. Here is a small example subset of the available TaskHandlers:

  • CDSSOTaskHandler – detects if the user needs to authenticate using CDSSO and redirects to CDCServlet if necessary
  • CDSSOResultTaskHandler – processes the incoming LARES response and creates the cookie on the application’s domain
  • URLPolicyTaskHandler – checks the currently visited URL against configured URL policies in OpenAM, and blocks access if necessary
  • InitialPDPTaskHandler – saves POST data if the user hasn’t authenticated yet, so later on the POST can be resubmitted once authentication took place.
  • XSSDetectionTaskHandler – checks incoming request parameters for malicious characters

Since the agent is implemented as a filter, you can see how it can alter the outcome of a given incoming request. If the user doesn’t have session yet, it will prevent further processing of the page, and redirect straight to OpenAM instead. This however means that in order to protect the application fully, you must set the agent’s filter as the first one, otherwise it may be possible that a filter earlier in the chain alters the response, or returns earlier, which could basically prevent the agent to protect the application properly.

Agent application

And here is the last component which is pretty simple, the agent application. The purpose of this application is to provide a unique contextroot for the agent, so the agent can receive notifications from OpenAM, and also LARES responses in case of CDSSO. To be fair the agentapp only has the agent’s filter defined, and that basically handles everything. If there is an incoming notification, then the filter just checks if the requested URL is actually the notification URL, and processes it if so.
As a sidenote I would mention that deploying agentapp.war is not necessary when using global web.xml with Tomcat 6. That is simply because the global web filter already includes the agent filter, hence any incoming request to the /agentapp context will be catched by the filter already.

Conclusion

Agents are fun, but that doesn’t mean they are not complex. πŸ™‚