8 Developing a Custom User Provisioning Plug-in
This chapter provides the following sections:
See Also,
Using the Default Identity Provisioning Plug-in in Fusion Middleware Administering Oracle Access Management.
8.1 Introduction to User Provisioning Plug-ins
When Identity Federation is acting in Service Provider (SP) mode, the user assertion is mapped to a local store to complete the federated single sign-on. However, in some cases when a Service Provider is performing user assertion, a user may not be found. The default user provisioning plug-in (LDAPProvisioningPlugin
) will provision the user in the LDAP store configured as the Access Manager identity store.
All the information collected at runtime is passed to any user provisioning plug-in, standard or custom. The custom user provisioning plug-in must decide, based on this information, what user information it needs to retrieve and use. Additionally, each custom plug-in can include its own configuration designed to perform extra processing of the user to be provisioned.
When Identity Federation is acting in SP mode and fails to map assertion to a user, it will look for a configuration property to check if the missing user should be provisioned. If the user provisioning flag is set to true, Identity Federation will look up the plug-in name that needs invoking. The stand plug-in (LDAPProvisioningPlugin
) is invoked by default if a custom plug-in is not being used. The GenricPluginFactory
is used to locate the plug-in defined and executes the provisioning logic.
Identity Federation retrieves the property associated with the partner nameideattrname
to populate the nameid
value in the attribute list sent to the plug-in. If Identity Federation is configured to use the standard plug-in, the options for data store selection is as follows:
-
If Identity Federation is using the partner specific data store (multi-store), then Identity Federation will pass the identify store name to the plug-in.
-
If Identity Federation uses the default user identity store, the standard plug-in will use the User Provisioning APIs to provision user data in the data store.
-
If no partner specific store is configured, the default identity store is used.
The User Provisioning API used to provision a user is the same regardless whether a default identity store or a partner specific store is used.
8.2 Introduction to Plug-in Interfaces
Reviewers: Do we want to provide a short summary of each OIF interface here? If so, please provide. See Introduction to Plug-in Interfaces in the OAM plug-in chapter that provides a similar discussion.
The main class a custom user provisioning plug-in extends is OIFUserProvisioningPlugin
. The following interfaces are exposed to custom plug-ins:
-
oracle.security.fed.plugins.fed.provisioning.OIFUserProvisioningPlugin.java
(extendsoracle.security.am.plugin.AbstractAMPlugin
) -
oracle.security.fed.plugins.fed.provisioning.UserContext.java
-
oracle.security.fed.plugins.fed.provisioning.UserProvisioningException.java
-
oracle.security.fed.plugins.fed.provisioning.UserProvisioningConstants.java
For more information about these interfaces, see Oracle Fusion Middleware User Provisioning Plug-in Java API Reference for Oracle Access Management Identity Federation.
8.3 Sample Code: Custom User Provisioning Plug-in
The custom user provisioning plug-in jar file structure must conform to an Access Manager custom authentication plug-in structure. Namely, it requires the following files: plugin.class, plugin.xml, and MANIFEST.MF. For more information about this structure, see Sample Code: Custom Database User Authentication Plug-in.
This section provides the following user provisioning plug-in code samples:
Sample UserProvisioning.java
The following sample code explains user provisioning plug-in:
package oif.test; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.BasicAttribute; import javax.naming.directory.BasicAttributes; import javax.naming.directory.DirContext; 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.UserProvisioningConstants; import oracle.security.fed.plugins.fed.provisioning.UserProvisioningException; /* * Sample OIF User provisioning plugin */ public class ProvisioningPlugin extends OIFUserProvisioningPlugin { private boolean monitoringStatus = false; private Map paramMap ; private String userRecordAttrList = null; private String useridAssertionAttr = null; /* (non-Javadoc) */ @Override public ExecutionStatus process(UserContext context) throws UserProvisioningException { /* * Execute method for plugin */ boolean provisioningStatus = false; try{ Map<String, Object> attrs = context.getAttributes(); Map<String, Object> attrsMapping = context.getAttributesUsedInMapping(); if (useridAssertionAttr == null) { System.out.println("User id attribute to create user is not found in the attributes list"); return ExecutionStatus.ABORT; } String userid = null; if (attrs.containsKey(useridAssertionAttr)) { Object valueObj = attrs.get(useridAssertionAttr); if (valueObj instanceof String) userid = (String) valueObj; else { userid = (String)((Set) valueObj).iterator().next(); } } DirContext ctx = getContext(); // creating the user record Attributes record = new BasicAttributes(); // Create the objectclass to add Attribute objClasses = new BasicAttribute("objectClass"); objClasses.add("top"); objClasses.add("person"); String objectClass = "inetOrgPerson"; objClasses.add(objectClass); objClasses.add("organizationalPerson"); record.put(objClasses); String userIDAttr = "uid"; // Set the attributes record.put(new BasicAttribute(userIDAttr, userid)); StringTokenizer st = new StringTokenizer(userRecordAttrList, ","); while (st.hasMoreTokens()) { String key = (String) st.nextToken(); record.put(new BasicAttribute(key, attrs.get(key))); } Set keys = attrsMapping.keySet(); Iterator itr = keys.iterator(); while (itr.hasNext()) { String key = (String) itr.next(); if (!attrs.containsKey(key)) { record.put(new BasicAttribute(key, attrsMapping.get(key))); } String ldapUserBaseDN = "dc=iplanet,dc=com"; // Create the record ctx.createSubcontext("cn=" + userid + "," + ldapUserBaseDN, record); provisioningStatus = true; } } catch(Exception e){ /* * If exception abort the authentication. */ e.printStackTrace(); return ExecutionStatus.ABORT; } if( provisioningStatus){ /* * Success */ return ExecutionStatus.SUCCESS; }else{ /* * Failure. */ return ExecutionStatus.FAILURE; } } /* (non-Javadoc) * @see oracle.security.am.plugin.GenericPluginService#initialize(java.util.Map) */ @Override public ExecutionStatus initialize(PluginConfig config) { //success for the execution status userRecordAttrList = (String)config.getParameter(UserProvisioningConstants.KEY_USER_RECORD_ATTRIBUTE_LIST); useridAssertionAttr = (String)config.getParameter(UserProvisioningConstants.KEY_USERID_ATTRIBUTE_NAME); return ExecutionStatus.SUCCESS; } /* (non-Javadoc) * @see oracle.security.am.plugin.GenericPluginService#getDescription() */ @Override public String getDescription() { return "Ldap Provisioning Plugin"; } /* (non-Javadoc) * @see oracle.security.am.plugin.GenericPluginService#getMonitoringData() */ @Override public Map < String, MonitoringData > getMonitoringData() { // TODO Auto-generated method stub return null; } /* (non-Javadoc) * @see oracle.security.am.plugin.GenericPluginService#getMonitoringStatus() */ @Override public boolean getMonitoringStatus() { return monitoringStatus; } /* (non-Javadoc) * @see oracle.security.am.plugin.GenericPluginService#getName() */ @Override public String getPluginName() { return "LDAP_Provisioning_plugin"; } /* (non-Javadoc) * @see oracle.security.am.plugin.GenericPluginService#getVersion() */ @Override public int getRevision() { return 10; } /* (non-Javadoc) * @see oracle.security.am.plugin.GenericPluginService#setMonitoringStatus(boolean) */ @Override public void setMonitoringStatus(boolean status) { monitoringStatus = status; } private DirContext getContext() { try { DirContext context = null; String ldapURL = "ldap://myldap.example.com:389"; String ldapUserBaseDN = "dc=iplanet,dc=com"; Hashtable<String, String> env = new Hashtable <String, String> (); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, ldapURL); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.REFERRAL, "follow"); String credential = "password"; String secPrincipal = "cn=Directory Manager"; env.put(Context.SECURITY_PRINCIPAL, secPrincipal); env.put(Context.SECURITY_CREDENTIALS, credential); context = new InitialDirContext (env); return context; } catch (NamingException ne) { throw new UserProvisioningException(ne); } catch (Throwable e) { throw new UserProvisioningException(e); } } }
Sample UserPlugin.xml
The following sample code provides UserPlugin.xml
<Plugin type="User Provisioning"> <author>uid=User1</author> <email>User1@example</email> <creationDate>09:32:20,2012-06-15</creationDate> <description>User provisioning</description> <configuration> <AttributeValuePair> <Attribute type="string" length="100">KEY_USERID_ATTRIBUTE_NAME</Attribute> <mandatory>false</mandatory> <instanceOverride>false</instanceOverride> <globalUIOverride>true</globalUIOverride> <value>uid</value> </AttributeValuePair> <AttributeValuePair> <Attribute type="string" length="200">KEY_USER_RECORD_ATTRIBUTE_LIST</Attribute> <mandatory>true</mandatory> <instanceOverride>false</instanceOverride> <globalUIOverride>true</globalUIOverride> <value>mail,uid</value> </AttributeValuePair> </configuration> </Plugin>
Sample MANIFEST.MF
The following sample code provides MANIFEST.MF
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: ProvisioningPlugin Bundle-SymbolicName: ProvisioningPlugin Bundle-Version: 10 Bundle-Activator: oif.test.ProvisioningPlugin Import-Package: org.osgi.framework;version="1.3.0",oracle.security.fed.plugins.fed.provisioning Bundle-RequiredExecutionEnvironment: JavaSE-1.6
8.4 Developing a User Provisioning Plug-in
This section provides steps to write a custom Identity Federation user provisioning plug-in. The following describes the actions a developer must take after the system architect identifies the business requirements for the custom plug-in and considers the user provisioning flow when a user is not mapped to a local user store.
This section contains the following topics:
8.4.1 Developing a Custom Plug-in: Process Overview
As Identity Federation leverages the Access Manager plug-in framework, the process is similar for both. For more information, see About Planning, the Authentication Model, and Plug-ins.
For information about deploying and managing custom authentication plug-ins, see Deploying and Managing Individual Plug-ins for Authentication.