Apache
Home » Documentation

Apache Felix JAAS Support

Apache Felix JAAS support aims to simplify usage of JAAS in OSGi.

It supports following features

  1. It can work both in Standalone and AppServer deployments i.e. in those environment where global JAAS configuration might be used by other applications and our usage of JAAS should not affect them
  2. It enables usage of OSGi Configuration support to dynamically configure the login modules.
  3. It allows LoginModule instances to be created via factories registered in OSGi Service Registry
  4. It does not require the client to depend on any OSGi API
  5. It works well with the dynamic nature of the OSGi env
  6. Implementation depends only on Core OSGi API and ConfigAdmin (RFC 104)

The Problem

The basic problem when using JAAS in OSGi is that it creates the LoginModule instance using reflection. This poses problem in OSGi env as the client bundle does not have the visibility of all the required LoginModule classes.

A typical use of JAAS login looks like below

// let the LoginContext instantiate a new Subject
LoginContext lc = new LoginContext("myApp");
lc.login();

In this mode the LoginContext would access the global JAAS Configuration internally via Configuration.getConfiguration(). It would then instantiate the LoginModule instance based on the configuration value. It uses the Thread Context ClassLoader (TCCL) to create the instance. This approach fails to work when used in OSGi

  1. The Thread Context ClassLoader is not defined in general in an OSGi context. It can and has to be set by the caller and OSGi cannot generally enforce that.
  2. Instantiating a LoginModule generally requires access to internal implementation classes, by exporting these classes an implementing bundle would break its encapsulation.
  3. Even if an implementation class was exported, importing this class in a consumer bundle would bind it to the specific implementation package provided, which violates the principle of loose coupling.

Usage

The JAAS support involves following parts

  1. LoginModule Registration - Mechanism by which LoginModule is registered with a given realm.
  2. LoginContext Creation - Refers to the client code which constructs the LoginContext and then perform login operation

In section below we would first provide details on various ways by which a LoginModule would be configured so that it can participate in JAAS flow and then about various ways in which the client code can invoke the JAAS logic

LoginModule registration

The login modules can be registered via two mechanism

A - OSGi Configuration

LoginModules can also be configured via configuration which is somewhat similar to the file based configuration. It consist of two parts

Manifest Header Entry

Any bundle which provides a LoginModule class needs to provide this information via Jaas-ModuleClass manifest header.

<Jaas-ModuleClass>org.apache.felix.example.jaas.config.internal.SampleConfigLoginModule</Jaas-ModuleClass>
Configuration

JAAS module depends on OSGi Configuration for managing the LoginModule configuration. The configuration factory PID is org.apache.felix.jaas.Configuration.factory.It provides the required metatype descriptor thus enabling configuration via "Configuration" tab of Felix WebConsole

Configuration properties

For an example refer to Sample Configuration. It configures a SampleConfigLoginModule for sample realm

B - LoginModuleFactory

Any bundle which want to provide a LoginModule implementation would need to provide a factory service which implements the LoginModuleFactory interface. The factory needs to be registeredwith following optional properties

Interface

/**
 * A factory for creating {@link LoginModule} instances.
 */
public interface LoginModuleFactory
{
    /**
     * Property name specifying whether or not a <code>LoginModule</code> is
     * REQUIRED, REQUISITE, SUFFICIENT or OPTIONAL. Refer to {@link javax.security.auth.login.Configuration}
     * for more details around the meaning of these flags
     *
     * By default the value is set to REQUIRED
     */
    String JAAS_CONTROL_FLAG = "jaas.controlFlag";

    /**
     * Property name specifying the Realm name (or application name) against which the
     * LoginModule would be registered.
     *
     * <p>If no realm name is provided then LoginModule would registered with a default realm
     * as configured
     */
    String JAAS_REALM_NAME = "jaas.realmName";

    /**
     * Creates the LoginModule instance
     * @return loginModule instance
     */
    LoginModule createLoginModule();
}

Refer to JdbcLoginModuleFactory for one example of its usage. It constructs a JdbcLoginModule based on the configuration and passes on the datasource.

LoginContext creation patterns

There are various ways through which a JAAS Client can invoke the JAAS login.

LoginContextFactory Mode

In this mode the client logic obtains a reference to the org.apache.felix.jaas.LoginContextFactory service and then creates a LoginContext instance

:java
LoginContextFactory loginContextFactory = ...
CallbackHandler handler = ...;
Subject subject = new Subject();
try
{
    LoginContext lc = loginContextFactory.createLoginContext("sample",subject,handler);
    lc.login();
    ...
}
catch (LoginException e)
{
    handleAuthenticationFailure(e);
}

Refer to FactoryDemoServlet for an example. Following points to be noted for this usage pattern

Configuration SPI with Default Policy Mode

In this mode the client logic explicitly fetch the JAAS Configuration and then pass it on to the LoginContext. In this mode the JAAS Configuration Policy is set to Default.

CallbackHandler handler = ...;

Subject subject = new Subject();
final ClassLoader cl = Thread.currentThread().getContextClassLoader();
try
{
    Configuration config = Configuration.getInstance(
                              'JavaLoginConfig',      //Algorithm name
                              null,                   //Extra params to be passed. For this impl its null
                              'FelixJaasProvider'     //Name of the config provider
                      );
    Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
    LoginContext lc = new LoginContext("sample", subject, handler, config);
    lc.login();

    ...
}
finally
{
    Thread.currentThread().setContextClassLoader(cl);
}

In above flow the Configuration instance is explicitly fetched and passed on to the

Refer to TCCLDemoServlet for an example. Following points to be noted for this usage pattern

Replace Global Configuration Mode

In this mode the JAAS bundle would replace the Global configuration through Configuration.setConfiguration call. In this mode the client code would use the normal LoginContext creation and the JAAS Configuration Policy is set to Replace Global Configuration.

final ClassLoader cl = Thread.currentThread().getContextClassLoader();
try
{
    Thread.currentThread().setContextClassLoader(getClass().getClassLoader());

    // let the LoginContext instantiate a new Subject
    LoginContext lc = new LoginContext("appName");
    lc.login();
}
finally
{
    Thread.currentThread().setContextClassLoader(cl);
}

Following points need to be considered this mode

Refer to GlobalConfigDemoServlet for an example

Modified Boot Classpath Mode

In previous modes (except the LoginContextFactory mode) the client code needs to switch the Thread Context Classloader (TCCL). This is due the way JAAS logic instantiates the LoginModule. The Felix JAAS Support provides a ProxyLoginModule which takes care of routing the LoginModule calls properly. However for this class to be visible to JAAS logic one of the two approaches can be used

Manage TCCL Explicitly

The client bundle would need to

  1. Have an explicit import for org.apache.felix.jaas.boot package and
  2. Manage TCCL explicitly which making JAAS related calls.
    final Thread current = Thread.currentThread();
    final ClassLoader orig = current.getContextClassLoader();
    try {
      current.setContextClassLoader(getClass().getClassLoader());
     loginContext = new LoginContext(appName, subject,callbackHandler, config);
    

    } finally{ current.setContextClassLoader(orig); }

Note that in above flow the TCCL is managed explicitly

Modify Boot Classpath

Another way would involve modifying the boot classpath.

  1. Place the org.apache.felix.jaas-xxx-boot.jar in the boot classpath via -Xbootclasspath:bootclasspath option
  2. Make the org.apache.felix.jaas.boot part of boot delegation list
    LoginContext lc = new LoginContext("sample", subject, handler);
    lc.login();
    

Note that in above code we do not have to manage TCCL and neither add an import to org.apache.felix.jaas.boot package

Refer to BootClasspathDemoServlet for code sample

JAAS Configuration SPI Settings

There are various ways in which LoginContext can be created depending on the usage mode. The JAAS support exposes following properties

WebConsole Plugin

The runtime JAAS realm is exposed via a WebConsole Plugin.

Resources

  1. Java JAAS Reference Guide
  2. JAAS Login Configuration File
Rev. 1599411 by chetanm on Tue, 3 Jun 2014 05:34:14 +0000
Apache Felix, Felix, Apache, the Apache feather logo, and the Apache Felix project logo are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners.