JIT Custom User Provisioning in OAM and SP Continued

This article shows how to build a custom User Provisioning module in OAM/SP. This is based on the OAM Developer’s Guide, chapter 16, which describes how to develop such a module.

In this article, focus on how to:

For this example, use the sample code listed in the OAM Developer’s Guide.

Custom User Provisioning Module

The User Provisioning framework allows the implementation of a custom plugin that implements the interfaces defined by the framework.

A custom User Provisioning plugin is made of the following:

These three elements is bundled in a JAR file which is then uploaded to the OAM server via the OAM Administration Console. Once uploaded and activated, it can be used at runtime by OAM/SP.

Java Class

The class implementing the custom User Provisioning module must adhere to the following:

The following code is an example of the custom plugin called CustomerUserProvisioning.

package userprov;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Map;
import javax.naming.Context;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.InitialDirContext;
import oracle.security.am.plugin.ExecutionStatus;
import oracle.security.am.plugin.MonitoringData;
import oracle.security.am.plugin.PluginConfig;
import oracle.security.fed.plugins.fed.provisioning.OIFUserProvisioningPlugin;
import oracle.security.fed.plugins.fed.provisioning.UserContext;
import oracle.security.fed.plugins.fed.provisioning.UserProvisioningException;


public class CustomUserProvisioning extends OIFUserProvisioningPlugin implements
org.osgi.framework.BundleActivator
{
	private String userBaseDN = null;
	public ExecutionStatus initialize(PluginConfig config)
	{
	ExecutionStatus status = super.initialize(config);
	if (status.getStatus() == ExecutionStatus.SUCCESS.getStatus())
		userBaseDN = (String)config.getParameter("USER_BASE_DN");
		return status;
	}
public ExecutionStatus process(UserContext  context) throws UserProvisioningException
{
	try
	{
		// get user data
	 // after OIF/SP processing of the attributes sent by the IdP, we expect
// givenname, sn, mail as well as fed.nameidvalue which contains
// the userid
		Map assertionAbributes = context.getAttributes();
		Collection collection = (Collection)assertionAbributes.get("givenname");
		String firstname = (String)(collection.size() > 0 ? collection.iterator().next() : null);
		collection =  (Collection)assertionAbributes.get("sn");
		String lastname = (String)(collection.size() > 0 ? collection.iterator().next() : null);
		collection = (Collection)assertionAbributes.get("mail");
		String email = (String)(collection.size() > 0 ? collection.iterator().next() : null);
		collection =  (Collection)assertionAbributes.get("fed.nameidvalue"); String userid = (String)(collection.size() > 0 ?
collection.iterator().next() : null);

// check that the required attributes are present. If not, return an error

if (firstname == null || firstname.length() == 0 || lastname == null || lastname.length() == 0 ||  email == null || email.length() == 0 ||
userid == null || userid.length() == 0)
	{

	// failure
		return ExecutionStatus.FAILURE;
	}
	String ldap = "ldap://adc00pcc.us.oracle.com:11389";
	String username = "cn=orcladmin"; String password = "welcome1";

// connects to the LDAP directory

		Hashtable env = new Hashtable();
		env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
		env.put(Context.PROVIDER_URL, ldap);

		if (ldap.toLowerCase().startsWith("ldaps"))
			env.put(Context.SECURITY_PROTOCOL, "ssl");
			env.put(Context.SECURITY_AUTHENTICATION,"simple");
			env.put(Context.REFERRAL, "follow"); env.put(Context.SECURITY_PRINCIPAL, username);
			env.put(Context.SECURITY_CREDENTIALS, password);

		InitialDirContext ldapContext = new

		InitialDirContext(env);

// create the user entry

		BasicAttributes attributes = new

		BasicAttributes();

// object classes

		BasicAttribute objClassAbr = new

		BasicAttribute("objectClass");

		objClassAbr.add("person");

		objClassAbr.add("organizationalPerson");

		objClassAbr.add("inetOrgPerson");

		objClassAbr.add("top");

		attributes.put(objClassAbr);

// uid abr

		attributes.put(new BasicAttribute("uid", userid));

// first name

		attributes.put(new BasicAttribute("givenname", firstname));

// last name

		attributes.put(new BasicAttribute("sn", lastname));

// email

		attributes.put(new BasicAttribute("mail", email));

// DN: cn will be set to userID

		String dn = "cn=" + userid + (userBaseDN != null && userBaseDN.length() \> 0 ? "," + userBaseDN : "");

// create the user record

		ldapContext.createSubcontext(dn, attributes);

// return success

		return ExecutionStatus.SUCCESS;

	}

catch (Exception ex)

	{
		ex.printStackTrace();
		return ExecutionStatus.FAILURE;

	}
}

	public String getPluginName()
	{
		return "CustomProvisioningPlugin";
	}
	public String getDescription()
	{
		return "Custom Provisioning Plugin";
	}
	public Map<String, MonitoringData> getMonitoringData()
	{
		return null;
	}
	public boolean getMonitoringStatus()
	{
		return false;
	}
	public int getRevision()
	{
		return 10;
	}
	public void setMonitoringStatus(boolean status)
	{

	}
	public void start(BundleContext arg0) throws Exception
	{

	}
	public void stop(BundleContext arg0) throws  Exception

	{

	}

}

Plugin Registration File

The custom User Provisioning plugin must be defined in a plugin XML file such as:

<Plugin type="User Provisioning">
<author>uid=admin</author>
<email>admin@example</email>
<creationDate>08:00:00,2014-01-15</creationDate>
<description>Custom Provisioning Plugin</description>
 <configuration>
   <AbributeValuePair>
     <Attribute type="string" length="100">USER_BASE_DN</Abribute> <mandatory>false</mandatory>
     <instanceOverride>false</instanceOverride>
     <globalUIOverride>false</globalUIOverride>
     <value> </value>
  </AbributeValuePair>
</configuration>
</Plugin>

Important Note: The XML file must have the same name as the class implementing the plugin, in this case CustomUserProvisioning.xml

See the OAM Developer’s Guide for more information.

Manifest File

Before packaging the custom User Provisioning plugin in a JAR file, a MANIFEST.MF must be defined such as:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: CustomUserProvisioning
Bundle-SymbolicName: CustomUserProvisioning
Bundle-Version: 10
Bundle-Activator: userprov.CustomUserProvisioning Import-Package: org.osgi.framework;version="1.3.0",oracle.security.fed
.plugins.fed.provisioning,javax.naming,javax.naming.directory,oracle. security.am.plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.6

See the OAM Developer’s Guide for more information.

Note: The manifest file must include the ImportPackage property which lists all the packages that are used in the plugin.

Building the Plugin

Compiling

The following JAR files from the OAM deployment need to be used for compilation:

These files are found in the following locations:

To compile, execute the following command:

$JDK_HOME/bin/javac -cp $IAM_HOME/oam/server/lib/plugin/felix.jar:$IAM_HOME/oam/server/lib/plugin/oam-plugin.jar:/tmp/oam-server/APPINF/lib/fed.jar src/userprov/*.java

Packaging the Custom Plugin

We created the MANIFEST.MF in the current directory based on the content listed in the previous section, and the CustomUserProvisioning.xmlin the src directory, which contains the plugin definition listed in the previous section.

find
.
./MANIFEST.MF
./src
./src/userprov
./src/userprov/CustomUserProvisioning.class
./src/userprov/CustomUserProvisioning.java ./src/CustomUserProvisioning.xml

To create the CustomUserProvisioning.jar JAR file that contains the plugin and the required files, execute the following command:

jar cfvm CustomUserProvisioning.jar MANIFEST.MF -C src/ .
added manifest adding: userprov/(in = 0) (out= 0)(stored 0%) adding: userprov/CustomUserProvisioning.class(in =3991) (out= 1954)(de_ated 51%)
adding: userprov/CustomUserProvisioning.java(in =4717) (out= 1401)(de_ated 70%)
adding: CustomUserProvisioning.xml(in = 486) (out= 266)(de_ated 45%)

This creates the CustomUserProvisioning.jar. To view the contents of the file:

unzip -l CustomUserProvisioning.jar Archive: CustomUserProvisioning.jar

Length Date Time Name
0 03-01-2014 14:32 META-INF/
404 03-01-2014 14:32 META-INF/MANIFEST.MF
0 03-01-2014 12:10 userprov/
3991 03-01-2014 12:10 userprov/CustomUserProvisioning.class
4717 03-01-2014 11:42 userprov/CustomUserProvisioning.java
486 03-01-2014 14:04 CustomUserProvisioning.xml
9598     6 files

Important Note: The JAR file must have the same name as the class implementing the plugin, in this case CustomUserProvisioning.jar

Deploying the Custom Provisioning Module

Perform the following steps to deploy the custom User Provisioning plugin in OAM:

  1. Go to the OAM Administration Console: http(s)://oam-admin-host:oam-adminport/oamconsole.

  2. Navigate to Access Manager , Plugins.

  3. Click Import Plug-In.

  4. Select the plugin JAR file (CustomUserProvisioning.jar in this example).

Description of the illustration Import_Plugin.jpg

The plugin will be in an uploaded state:

Description of the illustration Plugin_Screen.jpg

You need to distribute the plugin to the runtime OAM servers and activate it:

  1. Select the plugin.

  2. Click Distribute Selected.

  3. The Activation Status tab of the plugin shows the state of the plugin.

Description of the illustration Plugin_Status.jpg

You needs to activate the plugin:

  1. Select the plugin.

  2. Click Activate Selected.

  3. The Activation Status tab of the plugin shows the state of the plugin.

Description of the illustration Activation_Status.jpg

Finally, the plugin must be configured for user base DN. Perform the following steps:

  1. Select the plugin.

  2. Click on the Configuration Parameters tab of the plugin.

  3. Enter the User Base DN (for example for the directory we are using: ou=users,dc=us,dc=oracle,dc=com).

  4. Click Save.

Description of the illustration Configure_Plugin.jpg

Using the Custom User Provisioning Module

Enabling the User Provisioning in OAM

To enable/disable User Provisioning in OAM/SP, perform the following steps:

  1. Enter the WLST environment by executing: $IAM_ORACLE_HOME/common/bin/wlst.sh.

  2. Connect to the WLS Admin server: connect().

  3. Navigate to the Domain Runtime branch: domainRuntime().

  4. Update the userprovisioningenabled property to:

  5. Enable User Provisioning in OAM/SP: putBooleanProperty("/fedserverconfig /userprovisioningenabled", "true")

  6. Disable User Provisioning in OAM/SP: putBooleanProperty("/fedserverconfig /userprovisioningenabled", "false")

  7. Exit the WLST environment: exit().

Configuring OAM to use the Custom Plugin

To configure OAM/SP to use the custom plugin, perform the following steps:

  1. Enter the WLST environment by executing: $IAM_ORACLE_HOME/common/bin/wlst.sh.

  2. Connect to the WLS Admin server: connect().

  3. Navigate to the Domain Runtime branch: domainRuntime().

  4. Update the userprovisioningplugin property to: Configure OAM to use the custom plugin, set the property to the plugin name (in our example CustomUserProvisioning): putStringProperty("/fedserverconfig/userprovisioningplugin","CustomUserProvisioning")

  5. Configure OAM to use the built-in User Provisioning module: putStringProperty("/fedserverconfig /userprovisioningplugin","FedUserProvisioningPlugin")

  6. Exit the WLST environment: exit().

Testing Setup

Use the same SAML 2.0 Federation setup that was configured earlier, where:

During a SAML 2.0 Federation SSO with the remote IdP partner, the XML SAML Response with the Assertion sent back by the IdP is:

<samlp:Response ..>
 <saml:Issuer ...>http://acme.com/idp</saml:Issuer>
 <samlp:Status>
   <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion ...>
<saml:Issuer ...>http://acme.com/idp</saml:Issuer>
<dsig:Signature ...>
 ...
</dsig:Signature>
<saml:Subject>
<saml:NameID ...>alice</saml:NameID>
...
</saml:Subject>
<saml:Conditions ...>
 ...
</saml:Conditions>
<saml:AuthnStatement ...>
...
</saml:AuthnStatement>
<saml:AbributeStatement ...>
<saml:Attribute Name="email" ...>
 <saml:AbributeValue ...>alice@oracle.com</saml:AbributeValue>
</saml:Abribute>
<saml:Attribute Name="title" ...>
<saml:AbributeValue ...>manager</saml:AbributeValue>
</saml:Abribute>
<saml:Attribute Name="surname" ...>
<saml:AbributeValue ...>Appleton</saml:AbributeValue>
</saml:Abribute>
<saml:Attribute Name="fname" ...>
<saml:AbributeValue ...>Alice</saml:AbributeValue>
</saml:Abribute>
</saml:AbributeStatement>
</saml:Assertion>
</samlp:Response>

The result of the processing of the SAML 2.0 Assertion by OAM/SP shows the transformed attributes as well as the NameID

Description of the illustration Operation_Result.jpg

Test

After Federation SSO, the user record for alice was created:

More Learning Resources

Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.

For product documentation, visit Oracle Help Center.