Where has your LDAP connection pool gone?

Introduction You have deployed Oracle BPM and decided to run some load tests against it. You’re concerned, among other things, about the behavior of your backend LDAP server under peak times, whether it’s going to be able to handle the load or not. You check the security providers settings in Weblogic Server and see you […]

5 minutes or less: User/Role API and SSL

This short post follows up Couple of things you need to know about the User/Role API. Now imagine that your LDAP identity provider is SSL enabled in 1-way mode (the server authenticates to the client, but the client does not authenticate to the server).

Now you need to tell Weblogic server how to validate the LDAP server certificate. And this is accomplished by adding the LDAP server CA certificate to the configured Weblogic trust store. If we’re talking about a self-signed certificate, simply add the certificate itself to the trust store. And there are a couple of options for the trust key store: Command Line, Custom Trust, Java Standard Trust or the OOTB Demo Trust. So far, so good. By adding the certificate to one of these options, Weblogic is all good to talk to the identity provider in SSL mode.

However, the User/Role API is not directly tied to Weblogic, so don’t expect it to take whatever is configured for the server. By default, as a standard Java-based client, the User/Role API looks for the standard Java $JDK_HOME/jre/lib/security/cacerts file, unless you tell it to look elsewhere, by informing the java system properties

javax.net.ssl.trustStore=<path_to_trust_store_file>
javax.net.ssl.trustStorePassword=<trust_store_password>

Relying on the original cacerts file may be dangerous in case you upgrade your JDK. If you need to leverage the existing certificates there, make a copy of the file and use the copy. Then simply tell the User/Role API where to read it from using the properties mentioned above.

Couple of things you need to know about the User/Role API

The idea of the User/Role API is to abstract developers from the identity store where users and groups are kept. A developer can basically interact with any identity provider supported by Weblogic server using the same methods. The javadoc can be found here: http://download.oracle.com/docs/cd/E15523_01/apirefs.1111/e14658/toc.htm

In this post I want to alert you about two caveats:

1) User/Role API is able to query data from only one provider. If you want to query multiple identity stores, you need to go through an OVD Authenticator (or libOvd). And depending on how you get a handle to the identity store, the order in which providers are defined in Weblogic server Console as well as their CONTROL FLAGs do matter.

Shamelessly borrowing content from FMW Application Security Guide:

“OPSS initializes the identity store service with the LDAP authenticator chosen from the list of configured LDAP authenticators according to the following algorithm:

  1. Consider the subset of LDAP authenticators configured. Note that, since the context is assumed to contain at least one LDAP authenticator, this subset is not empty.
  2. Within that subset, consider those that have set the maximum flag. The flag ordering used to compute this subset is the following:
    REQUIRED > REQUISITE > SUFFICIENT > OPTIONAL

    Again, this subset (of LDAPs realizing the maximum flag) is not empty.

  3. Within that subset, consider the first configured in the context.


    The LDAP authenticator singled out in step 3 is the one chosen to initialize the identity store service.”

Lack of such understanding is a big source of headache.

Weblogic server ships with DefaultAuthenticator as the out-of-box authentication provider with the CONTROL FLAG set as REQUIRED.  Customers typically want to retrieve users from an enterprise-wide LDAP server, like OID or Active Directory. They go ahead and define a new authenticator and put it as the first in the providers list. But they leave DefaultAuthenticator untouched, because they still want to leverage the weblogic user as the administrator. And when some application relying on the User/Role API is executed (Oracle’s BPM and BIP are examples), a problem is just about to happen, because none of the users and groups defined in the enterprise-wide identity store are found. And the solution to this is pretty simple: switch DefaultAuthenticator’s CONTROL FLAG from REQUIRED to SUFFICIENT. What happens now during authentication time is that if the user is not found in the first authenticator, the lookup falls back to DefaultAuthenticator, so leveraging weblogic user is not a problem. And that will also make the User Role API querying the identity provider that you want (the first in the list).

2) Depending on how you get a handle to the identity store, provider-specific metadata (user, password, address, root search base) won’t be reused and you’ll be forced to define it in code again (of course you can externalize them to some properties file, but it is still a double maintenance duty).

That said, let’s examine possible ways of getting a handle to the identity store.

IdentityStoreFactoryBuilder builder = new IdentityStoreFactoryBuilder();
IdentityStoreFactory oidFactory = null;
Hashtable factEnv = new Hashtable();
// Creating the factory instance
factEnv.put(OIDIdentityStoreFactory.ST_SECURITY_PRINCIPAL, “cn=orcladmin”);
factEnv.put(OIDIdentityStoreFactory.ST_SECURITY_CREDENTIALS,“welcome1”);
factEnv.put(OIDIdentityStoreFactory.ST_LDAP_URL,“ldap://ldap.us.oracle.com:3060/”);
oidFactory = builder.getIdentityStoreFactory(“oracle.security.idm.providers.oid.
OIDIdentityStoreFactory”, factEnv);
Hashtable storeEnv = new Hashtable();
storeEnv.put(OIDIdentityStoreFactory.RT_SUBSCRIBER_NAME,”cn=users,dc=us,dc=oracle,dc=com”);
IdentityStore oidStore = oidFactory.getIdentityStoreInstance(storeEnv);
// Use oidStore to perform various operations against the provider

Look at how specific this snippet is to OID and how we’re passing metadata that is already available in the provider definition itself. By doing this, you do not incur in the problem described in my bullet #1, because you’re going directly against a specific identity store. You’re not leveraging the definitions in Weblogic server at all.

But if you do this…

JpsContextFactory ctxFactory = JpsContextFactory.getContextFactory();
JpsContext ctx = ctxFactory.getContext();
LdapIdentityStore idstoreService = (LdapIdentityStore)ctx.getServiceInstance(IdentityStoreService.class)
IdentityStore idStore = idstoreService.getIdmStore();

// Use idStore to perform various operations against the provider

you’re delegating the provider lookup process to OPSS (Oracle Platform Security Services), and it will abide by those rules outlined in my bullet #1. Here, you don’t have to redefine your connection metadata. You are simply reusing whatever is defined in Weblogic server and are not incurring in the problem mentioned in bullet #2. For consistency and manageability, this is a much better approach.

For the curious, the following is the necessary configuration in jps-config.xml to make this happen (see text in bold red). It is out-of-box available in any FMW install, so don’t worry about it.

<serviceInstances>

<serviceInstance name=”idstore.ldap” provider=”idstore.ldap.provider”>
     <property name=”idstore.config.provider” value=”oracle.security.jps.wls.internal.idstore.WlsLdapIdStoreConfigProvider”/>
     <property name=”CONNECTION_POOL_CLASS” value=”oracle.security.idm.providers.stdldap.JNDIPool”/>
</serviceInstance>

</serviceInstances>

<jpsContexts default=”default”>
        <jpsContext name=”default”>
            <serviceInstanceRef ref=”credstore”/>
            <serviceInstanceRef ref=”keystore”/> 
            <serviceInstanceRef ref=”policystore.xml”/>
            <serviceInstanceRef ref=”audit”/>
            <serviceInstanceRef ref=”idstore.ldap”/>
            <serviceInstanceRef ref=”trust”/>            
   <serviceInstanceRef ref=”pdp.service”/>
        </jpsContext>

        …
</jpsContexts>