Creating a Custom Authentication Plugin in OAM 11gR1
The oracle documentation is not very clear on how to create
a sample OAM plugin and it takes a while to create and get one working.
Recently I had to work on creating a custom cookie for a legacy web application
to achieve single sign on between EPP applications protected by OAM and legacy
web portal. Below are the brief steps on how to create one. The code was created
using eclipse. Below are the steps on how to create a sample OAM plugin.
1)
Create a Sample Java Project. Say SampleOAMPlugin. Important: Please note
that the name of java project, java class and the Meta data xml should be same.
2)
Add the following jar files to the build path of
the eclipse project. Felix.jar, felix-service.jar, extensibility_lifecycle.jar,
oam-plugin.jar,identitystore.jar,identity provider.jar and utilities. .jar.
These jar files will be found in a tmp folder under Domain home . $DOMAIN_HOME/servers/$ADMIN_SERVER_NAME/tmp/_WL_user/oam_admin_11.1.1.3.0/XXXXXX/APP-INF/lib/oam-plugin.jar
3)
Under the src folder in eclipse create a folder
called META_INF and inside it create a file called MANIFEST.MF
4)
Under the src folder create a xml file called SampleOAMPlugin.xml.
5)
If you have any third party library dependent
jar files create a folder say lib under the project at the same level as the
src folder. The jar file which will be created will have only these jar files
and not the ones in the step 2.
6)
Create a java package say sample and create a
java class SampleOAMPlugin , it has
to be same name as of the project.
7)
The java class should extend AbstractAuthenticationPlugIn
found in the package oracle.security.am.plugin.authn.So the java project
structure should be like this:-
8)
Out of the several inherited methods in the
SampleOAMPlugin class we need to implement the the process method .public
ExecutionStatus process(AuthenticationContext context)throws
AuthenticationException method.
9)
To extract the username and password entered on
the custom login page use the below methods. The below methods will only work
when the username and password fields defined on the login form are username
and password.
CredentialParam credentialParam =
context.getCredential().getParam(PluginConstants.KEY_USERNAME);
String userName =
(String)credentialParam.getValue();
credentialParam =
context.getCredential().getParam(PluginConstants.PASSWORD); String password =
(String)credentialParam.getValue();
10)
If you need any values which have to be read at
runtime(like a properties a file in java), like let’s say domain name for the
cookie, or the identity store against which we may want to authenticate the
users you can define that in the meta
data xml created in step 4 . To read those values use below statements.. for
e.g if KEY_IDENTITY_STORE_REF is a field
defined in meta data xml file.
String stepName = context
getStringAttribute(PluginConstants.KEY_STEP_NAME);
String identityStoreRef =
PlugInUtil.getFlowParam(stepName,"KEY_IDENTITY_STORE_REF", context);
11)
For authenticating the users use the below
statements. Though you may not need these if you are authenticating against an
OID. Oracle has two out of box plugins for identifying and authenticating the
users. UserIdentificationPlugin and UserAuthenticationPlugin.
UserIdentityProvider
provider = UserIdentityProviderFactory.getProvider(identityStoreRef);
boolean isAuthenticated =
provider.authenticateUser(userName, password);
12)
For looking up some attribute from user identity
store like OID, for example email you can use the below methods. String[]
userAttributeName = {"mail" };
AuthnUser userauth = new AuthnUser();
userauth.setUserName(userName);
List<String> attributeNames =
Arrays.asList(userAttributeName);
Map<String, String> resultMap =
provider.getUserAttributes(userauth, attributeNames);
String resultAttributeValue =
resultMap.get(userAttributeName[0]);
String emailId = resultAttributeValue;
13)
If you are using this plugin as a for authentication
then, you have to return some mandatory responses in the plugin response and
also set the subject if the user is authenticated, else if you are using Oracle’s
plugin for authentication/identification , the following steps are not required.
Create a subject as follows for the authenticated users.
Subject subject = new Subject();
if (isAuthenticated) {
subject.getPrincipals().add(new
OAMUserPrincipal(userIdentity));
subject.getPrincipals().add(new
OAMUserDNPrincipal(userDN));
if (guid !=
null)subject.getPrincipals().add(new OAMGUIDPrincipal(guid));
else subject.getPrincipals().add(new
OAMGUIDPrincipal(userIdentity));
}context.setSubject(subject);
Set mandatory responses in Plugin Response. The three responses which need to be set are KEY_RETURN_ATTRIBUTE,
KEY_IDENTITY_STORE_REF, KEY_AUTHENTICATED_USER_NAME. PluginResponse rsp = new
PluginResponse();
rsp.setName(PluginConstants.KEY_RETURN_ATTRIBUTE);
rsp.setType(PluginAttributeContextType.LITERAL);
rsp.setValue(provider.getReturnAttributes());//provider
is the user identity provider
context.addResponse(rsp);
// 2 nd response
IDPAdmin idpAdmin =
UserIdentityProviderFactory.getIDPAdmin();
String runtimeIDStore =
idpAdmin.getDefaultProviderName();
rsp = new PluginResponse();
rsp.setName(PluginConstants.KEY_IDENTITY_STORE_REF);
rsp.setType(PluginAttributeContextType.LITERAL);
rsp.setValue(runtimeIDStore);
context.addResponse(rsp);
//3 rd response
UserInfo user =
provider.locateUser(userName);
String userIdentity =
user.getUserObject().getPrincipal().getName();
rsp = new PluginResponse();
rsp.setName(PluginConstants.KEY_AUTHENTICATED_USER_NAME);
rsp.setType(PluginAttributeContextType.LITERAL);
rsp.setValue(userIdentity);
context.addResponse(rsp);
14)
If we need set the custom cookie we need to
create class in the package which should extend oracle.security.am.plugin.GenericTransportToken
and implements the getter and setter methods.
import
oracle.security.am.plugin.GenericTransportToken;
public class TokenClass implements
GenericTransportToken {
/*
* This is a sample Tokenclass that creates
a GenericTransportToken,
* which can be set on the transportContext
as a cookie.
* It has all the cookie
details:Name,Value,MaxAge, Version, Domain and secure flag.
*/
/** The token name. */
private final String m_tokenName;
/** The token version. */
private String m_tokenVersion;
...
...
//Instantiates a new TransportToken.
public TokenClass(String tokenName, String
tokenValue) {
m_tokenName = tokenName;
m_tokenValue = tokenValue;
}
//Retrieve the token name
public String getTokenName() {
return m_tokenName;
}
..
..
@Override
public void setMaxAgeInSeconds(int age) {
this.m_maxAgeInSeconds = age;
}
...
....
@Override
public void setTokenVersion(String version)
{
this.m_tokenVersion = version;
}
}
In the plugin class, call this
class constructor and access the values using the getter and setter methods.
Set the cookie using oracle.security.am.plugin.GenericTransportContext.
GenericTransportContext trContext =
context.getTransportContext();
TokenClass tok = new
TokenClass(cookieName, "cookieValue");
tok.setMaxAgeInSeconds(12000);
tok.setTokenDomain(“.abc.org”);
trContext.setToken(tok, false);
15)
For logging use
private final static Logger LOGGER =
java.util.Logger.getLogger(SampeCookieCreationPlugin.class.getCanonicalName());
LOGGER.info(CLASS_NAME + " Entering
SampleCookieCreationPlugin.process");
To view this logs in oam server diagnostic logs
run the following commands using wlst. connect('weblogic','weblogic1','t3://localhost:7001')
domainRuntime()
setLogLevel(logger="oracle.oam.plugin",level="TRACE:32",
persist="0", target="oam_server1")
After the above commands are run you should
see the following line in logs.
[sample.SampleOAMPlugin] [tid:
[ACTIVE].ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)']
[userId: <anonymous>] [ecid: 0d58708dceef42e5:7313f42d:13ea0e820c9:-8000-0000000000002f7a,0]
[APP: oam_server]sample.SampleOAMPlugin Entering SampleCookieCreationPlugin.process
16)
Jar file Manifest file .In the bundle class path
include the current class. And dependent jar files. Make sure the Symbolic Name
and bundle name are same as the java project name.
Manifest-Version:
1.0
Bundle-ManifestVersion: 2
Bundle-SymbolicName: SampleOAMPlugin
Bundle-Name: SampleOAMPlugin
Bundle-Version: 10
Bundle-Activator: sample.SampleOAMPlugin
Import-Package: javax.security.auth,
javax.crypto.spec,
javax.crypto,
oracle.security.am.common.utilities.principal,
oracle.security.am.engines.common.identity.provider,
oracle.security.am.plugin,
oracle.security.am.plugin.api,
oracle.security.am.plugin.authn,
oracle.security.idm,
org.osgi.framework;version="1.3.0"
Bundle-ClassPath: .,
lib/core.jar,
lib/j2ee.jar,
lib/redpoint-core.jar
17)
Meta data xml file. Although the oracle
documents says that the interface and implementation elements are optional but it
seems they are required. You will not be able to activate the oam plugin
without these parameters. The Attribute Value pair provides us with an ability
to define parameters whose value can be changed from OAM console. Refer Step 10
on how to read from this xml file in plugin class.
<Plugin name="SampleOAMPlugin"
type="Authentication">
<author>uid=cn=orcladmin</author>
<email>abc@abc.dev</email>
<creationDate>09:32:20,
2010-12-02</creationDate>
<version>10</version>
<description>Custom
Sample Auth Plugin</description>
<interface>oracle.security.am.plugin.authn.AbstractAuthenticationPlugIn</interface>
<implementation>sample.SampleOAMPlugin</implementation>
<configuration>
<AttributeValuePair>
<Attribute
type="string"
length="20">KEY_IDENTITY_STORE_REF</Attribute>
<instanceOverride>false</instanceOverride>
<globalUIOverride>false</globalUIOverride>
<value>DEVOID</value>
</AttributeValuePair>
<AttributeValuePair>
<Attribute
type="string" length="20">CookieDomain</Attribute>
<mandatory>true</mandatory>
<instanceOverride>false</instanceOverride>
<globalUIOverride>false</globalUIOverride>
<value>abc.dev</value>
</AttributeValuePair>
</configuration>
</Plugin>
19)
That’s it . After
this we need to upload this jar file using the OAM console. Reference http://docs.oracle.com/cd/E21764_01/doc.1111/e12491/authnapi.htm#autoId17