custom identity asserter Archive

Simple Sample Custom Identity Asserter for Weblogic Server 12c

To implement a custom identity asserter for Weblogic Server we need to write a provide that implements AuthenticationProviderV2 and IdentityAsserterV2. We need to write and Mbean definition file and a callback handler.

SimpleSampleIdentityAsserterProviderImpl

 

package examples.security.providers.identityassertion.simple;

import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.AppConfigurationEntry;
import weblogic.management.security.ProviderMBean;
import weblogic.security.service.ContextHandler;
import weblogic.security.spi.AuthenticationProviderV2;
import weblogic.security.spi.IdentityAsserterV2;
import weblogic.security.spi.IdentityAssertionException;
import weblogic.security.spi.PrincipalValidator;
import weblogic.security.spi.SecurityServices;
import javax.servlet.http.HttpServletRequest;

public final class SimpleSampleIdentityAsserterProviderImpl implements AuthenticationProviderV2, IdentityAsserterV2
{
  final static private String TOKEN_TYPE   = "SamplePerimeterAtnToken"; 
  final static private String TOKEN_PREFIX = "username="; 

  private String description; 

  public void initialize(ProviderMBean mbean, SecurityServices services)
  {
    System.out.println("SimpleSampleIdentityAsserterProviderImpl.initialize");
    SimpleSampleIdentityAsserterMBean myMBean = (SimpleSampleIdentityAsserterMBean)mbean;
    description                         = myMBean.getDescription() + "\n" + myMBean.getVersion();
  }

  public String getDescription()
  {
    return description;
  }

  public void shutdown()
  {
    System.out.println("SimpleSampleIdentityAsserterProviderImpl.shutdown");
  }

  public IdentityAsserterV2 getIdentityAsserter()
  {
    return this;
  }

  public CallbackHandler assertIdentity(String type, Object token, ContextHandler context) throws IdentityAssertionException
  {
    System.out.println("SimpleSampleIdentityAsserterProviderImpl.assertIdentity");
    System.out.println("\tType\t\t= "  + type);
    System.out.println("\tToken\t\t= " + token);

	Object requestValue = context.getValue("com.bea.contextelement.servlet.HttpServletRequest");
    if ((requestValue == null) || (!(requestValue instanceof HttpServletRequest)))
	  {
	   System.out.println("do nothing");
	   }
   else{
       HttpServletRequest request = (HttpServletRequest) requestValue;
	   java.util.Enumeration names = request.getHeaderNames();
        while(names.hasMoreElements()){
            String name = (String) names.nextElement();
            System.out.println(name + ":" + request.getHeader(name));
        }
   }

    // check the token type
    if (!(TOKEN_TYPE.equals(type))) {
      String error =
        "SimpleSampleIdentityAsserter received unknown token type \"" + type + "\"." +
        " Expected " + TOKEN_TYPE;
      System.out.println("\tError: " + error);
      throw new IdentityAssertionException(error);
    }

    // make sure the token is an array of bytes
    if (!(token instanceof byte[])) {
      String error = 
        "SimpleSampleIdentityAsserter received unknown token class \"" + token.getClass() + "\"." +
        " Expected a byte[].";
      System.out.println("\tError: " + error);
      throw new IdentityAssertionException(error);
    }

    // convert the array of bytes to a string
    byte[] tokenBytes = (byte[])token;
    if (tokenBytes == null || tokenBytes.length < 1) {
      String error =
        "SimpleSampleIdentityAsserter received empty token byte array";
      System.out.println("\tError: " + error);
      throw new IdentityAssertionException(error);
    }

    String tokenStr = new String(tokenBytes);

    // make sure the string contains "username=someusername
    if (!(tokenStr.startsWith(TOKEN_PREFIX))) {
      String error =
        "SimpleSampleIdentityAsserter received unknown token string \"" + type + "\"." +
        " Expected " + TOKEN_PREFIX + "username";
      System.out.println("\tError: " + error);
      throw new IdentityAssertionException(error);
    }

    // extract the username from the token
    String userName = tokenStr.substring(TOKEN_PREFIX.length());
    System.out.println("\tuserName\t= " + userName);

    // store it in a callback handler that authenticators can use
    // to retrieve the username.
    return new SimpleSampleCallbackHandlerImpl(userName);
  }

  public AppConfigurationEntry getLoginModuleConfiguration()
  {
    return null;
  }

  public AppConfigurationEntry getAssertionModuleConfiguration()
  {
    return null;
  }

  public PrincipalValidator getPrincipalValidator() 
  {
    return null;
  }
}

SimpleSampleCallbackHandlerImpl

 

package examples.security.providers.identityassertion.simple;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

/*package*/ class SimpleSampleCallbackHandlerImpl implements CallbackHandler
{
  private String userName; // the name of the user from the identity assertion token

  /*package*/ SimpleSampleCallbackHandlerImpl(String user)
  {
    userName = user;
  }

  public void handle(Callback[] callbacks) throws UnsupportedCallbackException
  {
    // loop over the callbacks
    for (int i = 0; i < callbacks.length; i++) {

      Callback callback = callbacks[i];

      // we only handle NameCallbacks
      if (!(callback instanceof NameCallback)) {
        throw new UnsupportedCallbackException(callback, "Unrecognized Callback");
      }

      // send the user name to the name callback:
      NameCallback nameCallback = (NameCallback)callback;
      nameCallback.setName(userName);
    }
  }
}

SimpleSampleIdentityAsserter.xml

<?xml version="1.0" ?>
<!DOCTYPE MBeanType SYSTEM "commo.dtd">

<MBeanType
 Name          = "SimpleSampleIdentityAsserter"
 DisplayName   = "SimpleSampleIdentityAsserter"
 Package       = "examples.security.providers.identityassertion.simple"
 Extends       = "weblogic.management.security.authentication.IdentityAsserter"
 PersistPolicy = "OnUpdate"
>

 <MBeanAttribute
  Name          = "ProviderClassName"
  Type          = "java.lang.String"
  Writeable     = "false"
  Preprocessor = "weblogic.management.configuration.LegalHelper.checkClassName(value)"
  Default       = "&quot;examples.security.providers.identityassertion.simple.SimpleSampleIdentityAsserterProviderImpl&quot;"
 />

 <MBeanAttribute
  Name          = "Description"
  Type          = "java.lang.String"
  Writeable     = "false"
  Default       = "&quot;WebLogic Simple Sample Identity Asserter Provider&quot;"
 />

 <MBeanAttribute
  Name          = "Version"
  Type          = "java.lang.String"
  Writeable     = "false"
  Default       = "&quot;1.0&quot;"
 />

 <MBeanAttribute  
  Name 		= "SupportedTypes"
  Type 		= "java.lang.String[]"
  Writeable 	= "false"
  Default 	= "new String[] { &quot;SamplePerimeterAtnToken&quot; }"
 />

 <MBeanAttribute  
  Name 		= "ActiveTypes"
  Type 		= "java.lang.String[]"
  Default 	= "new String[] { &quot;SamplePerimeterAtnToken&quot; }"
 />

   <MBeanAttribute  
  Name 		= "Base64DecodingRequired"
  Type 		= "boolean"
  Writeable 	= "true"
  Default 	= "false"
 />

</MBeanType>

Create a build.xml as follows.

<project name="Build" default="all" basedir=".">

<property name="fileDir" value="test" />

<target name="all" depends="build"/>

 <target name="build" depends="clean,build.mdf,build.mjf"/>

  <target name="clean">
    <delete dir="${fileDir}" failonerror="false"/>
	<delete file="SampleIdentityAsserter.jar" failonerror="false"/>
	<echo message="Clean finish" />
  </target>

  <!-- helper to build an MDF (mbean definition file) -->
	<target name="build.mdf">
		<java dir="${basedir}" fork="false" classname="weblogic.management.commo.WebLogicMBeanMaker">
			<arg line="-files ${fileDir}" />
			<arg value="-createStubs" />
			<arg line="-MDF SimpleSampleIdentityAsserter.xml" />
		</java>
		<echo message="Created Supporting Classes" />
	</target>

	<target name="build.mjf">

	    <copy todir="${fileDir}" flatten="true">
			<fileset dir=".">
			  <include name="*.java" />
			</fileset>
		</copy>

		<java dir="${basedir}" fork="false" classname="weblogic.management.commo.WebLogicMBeanMaker">
		    <arg line="-MJF SampleIdentityAsserter.jar" />
			<arg line="-files ${fileDir}" />
		</java>
		<echo message="Created Mbean Jar" />
	</target>

</project>

Keep all these files in the same directory. Copy setWLSEnv.cmd from WL_HOME\server\bin and commo.dtd from WL_HOME\server\lib to this diretory. The directory will then have the following files.

 

files

 

 

Run Ant

C:\Replication\identityasserter12c>ant build

Buildfile: build.xml

clean:
[delete] Deleting directory C:\Replication\identityasserter12c\test
[delete] Deleting: C:\Replication\identityasserter12c\SampleIdentityAsserter.
jar
[echo] Clean finish

build.mdf:
[java] Working directory ignored when same JVM is used.
[java] Parsing the MBean definition file: SimpleSampleIdentityAsserter.xml
[echo] Created Supporting Classes

build.mjf:
[copy] Copying 2 files to C:\Replication\identityasserter12c\test
[java] Working directory ignored when same JVM is used.
[java] Creating an MJF from the contents of directory test…
[java] Compiling the files…
[java] Creating the list.
[java] Doing the compile.
[java] WLMaker-SubProcess: : EXTRACT FROM C:/bea12c/WLSERV~1.1/server\lib\m
beantypes\wlManagementMBean.jar
[java] WLMaker-SubProcess: : INTO wlMakerTempDir
[java] WLMaker-SubProcess: :
[java] WLMaker-SubProcess: :
[java] WLMaker-SubProcess: :
[java] WLMaker-SubProcess: : Generating the implementations for security MB
eans
[java] WLMaker-SubProcess: : Generating for examples.security.providers.ide
ntityassertion.simple.SimpleSampleIdentityAsserterMBean to C:\Replication\identi
tyasserter12c\test\examples\security\providers\identityassertion\simple\SimpleSa
mpleIdentityAsserterMBeanImpl.java
[java] WLMaker-SubProcess: : no annotation found for key [i]
[java] WLMaker-SubProcess: : no annotation found for key [velocityCount]
[java] WLMaker-SubProcess: : no annotation found for key [line]
[java] WLMaker-SubProcess: : no annotation found for key [f]
[java] WLMaker-SubProcess: : no annotation found for key [m]
[java] WLMaker-SubProcess: : no annotation found for key [p]
[java] WLMaker-SubProcess: : no annotation found for key [n]
[java] WLMaker-SubProcess: : done
[java] WLMaker-SubProcess: :
[java] WLMaker-SubProcess: :
[java] WLMaker-SubProcess: :
[java] WLMaker-SubProcess: : Generating the parsing binders for security MB
eans
[java] WLMaker-SubProcess: : Generating for examples.security.providers.ide
ntityassertion.simple.SimpleSampleIdentityAsserterMBean to C:\Replication\identi
tyasserter12c\test\examples\security\providers\identityassertion\simple\SimpleSa
mpleIdentityAsserterMBeanBinder.java
[java] WLMaker-SubProcess: : done
[java] WLMaker-SubProcess: :
[java] WLMaker-SubProcess: :
[java] WLMaker-SubProcess: :
[java] WLMaker-SubProcess: : Generating the bean infos for security MBeans

[java] WLMaker-SubProcess: : Generating for examples.security.providers.ide
ntityassertion.simple.SimpleSampleIdentityAsserterMBean to C:\Replication\identi
tyasserter12c\test\examples\security\providers\identityassertion\simple\SimpleSa
mpleIdentityAsserterMBeanImplBeanInfo.java
[java] WLMaker-SubProcess: : no annotation found for key [import]
[java] WLMaker-SubProcess: : no annotation found for key [property]
[java] WLMaker-SubProcess: : no annotation found for key [beanConfigurable]

[java] WLMaker-SubProcess: : no annotation found for key [beanIntfExclude]
[java] WLMaker-SubProcess: : no annotation found for key [propertyMethod]
[java] WLMaker-SubProcess: : no annotation found for key [method]
[java] WLMaker-SubProcess: : Generating Bean Factory Class to test\weblogic
\management\security\SAMPLEIDENTITYASSERTERBeanInfoFactory.java
[java] WLMaker-SubProcess: : done
[java] WLMaker-SubProcess: : Stopped draining WLMaker-SubProcess:
[java] WLMaker-SubProcess: : Stopped draining WLMaker-SubProcess:
[java] WLMaker-SchemaGen-SubProcess: Generating schema for security provide
r mbeans …
[java] WLMaker-SchemaGen-SubProcess: MBEAN TYPES DIR : null
[java] WLMaker-SchemaGen-SubProcess: SET BASE LIB C:\bea12c\WLSERV~1.1\serv
er\lib\schema\weblogic-domain-binding.jar
[java] WLMaker-SchemaGen-SubProcess: Stopped draining WLMaker-SchemaGen-Sub
Process
[java] WLMaker-SchemaGen-SubProcess: Stopped draining WLMaker-SchemaGen-Sub
Process
[java] Creating the list.
[java] Doing the compile.
[java] Note: C:\Replication\identityasserter12c\test\examples\security\prov
iders\identityassertion\simple\SimpleSampleIdentityAsserterMBeanImpl.java uses o
r overrides a deprecated API.
[java] Note: Recompile with -Xlint:deprecation for details.
[java] Note: Some input files use unchecked or unsafe operations.
[java] Note: Recompile with -Xlint:unchecked for details.
[java] Creating the MJF…
[java] MJF is created.

 

An  Mbean JAR file will b created in that directory with the name SampleIdentityAsserter.jar

Place this jar file in WL_HOME\server\lib\mbeantypes

 

mbeantype

 

After placing the jar file, restart the Weblogic server.

Go to Security Realm Providers, create a new Authentication Provider
Home > Summary of Security Realms > myrealm > Providers > Authentication > new Simple Sample Identity Asserter

 

Simple Sample Identity Asserter

 

Once the identity asserter is created reorder the providers to make it first in the list. One more restart is required. On restart the custom identity asserter will be initialized. When any secure resource is accessed on the server and the token is present in the header the Custom Identity Asserter is invoked. Note, this identity asserter does not expect Base64 encoded token.

You will see the following loggging when the identity asserter is invoked.

SimpleSampleIdentityAsserterProviderImpl.assertIdentity
Type = SamplePerimeterAtnToken
Token = [B@c4221d
SamplePerimeterAtnToken:username=SamplePerimeterAtnUsers
User-Agent:Java/1.6.0_37
Host:localhost:7001
Accept:text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection:keep-alive
userName = SamplePerimeterAtnUsers
Header Name SamplePerimeterAtnToken Content username=SamplePerimeterAtnUsers
Header Name User-Agent Content Java/1.6.0_37
Header Name Host Content localhost:7001
Header Name Accept Content text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Header Name Connection Content keep-alive