- OTIS Documentation
- Authentication Tasks
- Authenticate User
- Creating a Custom Authentication Method
- Introduction
- Implementing the IAuthMethod Interface
- The AuthMaterial Object
- Configuration Settings For Your IAuthMethod Implementation
- Authentication Material Gatherer Object
- Deploying Your Custom Authentication Method in the OTIS Server
- OTIS Client SDK Use of Custom Authentication Methods
- Using a Custom Authentication Method in an Application
- REST Protocol Example
- Log Out Authenticated User
- Read Authenticated Entity
- Reauthenticate User
Creating a Custom Authentication Method
Introduction
The OTIS authentication architecture is designed to support custom pluggable authentication methods that are multi-step, as well as using multiple authentication methods (sometimes referred to as multi-factor authentication). OTIS ships with the following authentication methods, all of which are written as pluggable authentication methods:
- Username/Password
- Anonymous
- Information Card
- SAML Assertion NOTE: This includes SAML 1.x and 2.0 assertions.
Each of these authentication methods is implemented using the mechanisms described on this page. In fact, not only can a developer create new authentication methods, but these pre-built authentication methods can be completely replaced if desired.
To build a new authentication method (or override an existing authentication method):
- Create a unique authentication method identifier. For example, the pre-built authentication methods listed above have the following identifiers:
- Username/Password: urn:bandit-project:otis:authmethod:1.0:usernamePassword
- Anonymous: urn:bandit-project:otis:authmethod:1.0:anonymous
- Information Card: urn:bandit-project:otis:authmethod:1.0:infocard
- SAML Assertion: urn:bandit-project:otis:authmethod:1.0:samlpolicy
- Create a Java class that implements the IAuthMethod interface of the Bandit OTIS Client. How to do this is described in more detail below.
- Make the Java class available in the class path of the OTIS server so that the OTIS server can instantiate the class as needed. Any classes or interfaces that the class depends on must also be made available to OTIS. This is typically done by placing the necessary jar files (both the jar file containing the IAuthMethod implementation and the dependent jar files) in the WEB-INF/lib directory of the OTIS Web application.
- Add appropriate configuration settings to the OTIS configuration file. This is described in more detail below.
- For Java developers, the class must also be made available on the client side in much the same way it is made available to an OTIS server.
Implementing the IAuthMethod Interface
The IAuthMethod interface has a number of methods that must be properly implemented. Both the OTIS client SDK and the OTIS server application make use of these interfaces. These methods and the intended uses are described below.
OTIS Client/Server Relationship
The OTIS client SDK can be configured to work locally only, or remotely with a connection to an OTIS server. On the client side, there is always an IAuthSession object. If the OTIS client is configured to work locally only, the local session object discovers and uses IAuthMethod objects to perform authentication. When the client-side session object is configured to communicate with a remote OTIS server, the authenticate request is marshalled and sent to the OTIS server, and it is the OTIS server that will discover and use IAuthMethod objects to perform authentication.
IAuthMethod Methods
- public void configure( Map<String, ?> settings) throws AuthSessionException; This method is inherited from the IConfigurable interface. OTIS will call this method immediately after instantiating the object in order to pass in any configuration settings for the object. These settings will normally come from configuration files (see below).
- public AuthMaterial getNextAuthMaterialRequest() throws AuthSessionException;. This method is called by OTIS when it needs to know what authentication materials need to be requested next. An authentication method may require multiple steps. For example, there might be a custom authentication method which would request a username and password in step 1, and then do a challenge/response in step 2, etc. It is up to the object to keep track of what step it last performed, and when the getNextAuthMaterialRequest method is called to return what authentication materials are needed next. It must return an AuthMaterial object. This is described in more detail below. If there are no more authentication steps to perform, the method should return throw an exception. A return of null is a valid response (the anonymous method uses no authentication material), and hence, should NOT be used to indicate that there are no further authentication steps. It is incorrect for OTIS to call this method when there are no further authentication steps to perform. OTIS will know whether there are further steps to perform because of the return from the processAuthMaterialResponse method.
- public boolean processAuthMaterialResponse( AuthMaterial response) throws AuthSessionException; This method is called by OTIS when it wants the object to process authentication material it has received. The response parameter contains the authentication material that was provided. The object should authenticate the provided authentication material. If the authentication material cannot be authenticated, or is invalid in some way, it should throw an exception. The AuthenticationException exception should be thrown to indicate that authentication failed. If authentication succeeded, the method should return true if there are additional authentication steps to take. If no more authentication steps are needed, it should return false. If the method returns true, OTIS will call the getNextAuthMaterialRequest() method to determine what authentication materials need to be requested for the next authentication step.
- public void reauthenticate() throws AuthSessionException; This method is called by OTIS when it wants to determine if previously provided authentication materials are still valid. It is invalid to call reauthenticate if authentication never successfully completed. This method should throw an exception if it is called when authentication has not been completed. As an example of how this method might be used, take the case of the username/password authentication method. It may be that some time after the object was successfully authenticated, the password has been changed, or for some reason is no longer valid. A call to this method would determine if the password was still valid. In another example, the SAML assertion authentication method may want to see if the original assertion it was passed as authentication material is still valid or has expired. This implies that an authentication method object, whether multi-step or single-step, should retain authentication materials used in its authentication steps so that if reauthenticate is ever called, it will know what materials need to be revalidated and how to revalidate them. It is up to the object to determine which materials need to be revalidated and which do not. It is conceivable that some authentication method objects will simply implement a no-op for this method, as no revalidation of authentication material is possible. If the authentication method determines that one or more authentication materials are no longer valid, it should throw an AuthenticationException exception. Furthermore, the internal state should be modified so that the isAuthenticated method will now return false if called.
- public boolean isAuthenticated(); This should return true if the method has successfully completed all authentication steps, false otherwise.
- public String getAuthEntityId() throws AuthSessionException; This method returns the authenticated entity ID for the authentication method if the authentication method has been successfully authenticated. If the authentication method has not been authenticated, it should return null.
- public String getAuthenticateErrorMessage(); This method should return detailed error information if authentication failed. If no detailed information is available, it may return null.
- public IContext getContext() throws AuthSessionException; This method returns the IdAS IContext object that was used to authenticate, if IdAS was used to do the authentication. Since it is not required that a particular authentication method use IdAS to authenticate, it is possible that this method will return null. The getContext() method is called by the session object which used the authentication method to authenticate if the session wants to read or update entity or attribute data. If the authentication method cannot return an IContext object, the session will not be able to read or update entity or attribute data. NOTE: This method should always return null if the authentication method has not been successfully authenticated.
- public void clear(); This method should clear the object's authenticated state, if the object was previously authenticated. After this call, the isAuthenticated() method should return false, and the getAuthEntityId methods and the getContext methods should return null.
The AuthMaterial Object
The AuthMaterial object has two uses during authentication:
- Specification of authentication material to be requested.
- Instance of authentication material to be authenticated.
In the first kind of AuthMaterial object there is no value to be authenticated. It is merely used to specify what kind of authentication material needs to be requested. This kind of AuthMaterial object is generated by the getNextAuthMaterialRequest method of the IAuthMethod interface.
The second kind of AuthMaterial has all of the same information as the first kind, but it also carries the actual value that is to be authenticated. The material's value may be a complex hierarchical value comprised of various sub-values. This kind of AuthMaterial object is passed into the processAuthMaterialResponse method of the IAuthMethd interface to be authenticated.
An AuthMaterial object is an encapsulation of a hierarchical tree whose nodes represent the composition of an authentication material. The simplest kind of authentication material is one that consists of a single node. Complex authentication materials may consist of a hierarchy of nodes. Each node in the tree may have the following components:
- MaterialID. This is a unique URI that is used to identify the material represented by that part of the sub-tree. The URI at the root of the tree is the identifying URI for a particular authentication material. As such, it embodies the semantics of the material. If an authentication method uses that kind of authentication material, it must obviously understand the semantics that are implied by the material ID. In addition, gatherer objects that collect that kind of authentication material from an end user will need to understand the semantics implied by the material ID (see below for more discussion on authentication material gatherer objects).
- GatherAllChildren. This is a boolean flag which indicates whether all of the child authentication material nodes (if any) are required for authentication. This is only valid for a non-leaf node.
- Properties. This is a set of properties that is used during collection of authentication material values. The properties may be as simple or complex as desired. For example, they may be display hints, captchas, etc.
- Value. This is only allowed on leaf nodes - the "simple" authentication materials. It is NOT needed when the purpose of the AuthMaterial object is only a specification of materials to be requested. It is only required when the AuthMaterial object is an instance of authentication material that is to be authenticated, i.e., when it is to be passed to the processAuthMaterialResponse method of the IAuthMethd interface. A value on a leaf node may only be one of the following Java types:
- String
- Boolean
- Integer
- Long
- Short
- Byte
- Float
- Double
- byte []
- java.net.URI
- java.util.Date
- org.w3c.dom.Element
By way of example, consider the following fictitious authentication material tree. This illustrates a complex authentication material called "MaterialA" which consists of two simpler materials, "MaterialB" and "MaterialC". Both MaterialB and MaterialC are required for authentication. The MaterialA node has some properties, whereas the MaterialB and MaterialC nodes do not.

Note that in this example, the leaf nodes do not have a value. This particular AuthMaterial object could only be used to request MaterialA. It could not be authenticated by an authentication method, as it has no values to authenticate, but it could be passed to an authentication gatherer object as the specification for what authentication materials need to be gathered. An authentication method implementing the getNextAuthMaterialRequest method of the IAuthMethod interface might do something like the following to create an AuthMaterial request for MaterialA:
import org.bandit.otis.impl.AuthMaterial;
import org.bandit.otis.api.AuthSessionException;
import java.util.Map;
import java.util.HashMap;
public AuthMaterial getNextAuthMaterialRequest() throws AuthSessionException
{
Map properties = new HashMap();
// Code here would create whatever properties were needed for MaterialA
// ...
// Create MaterialA
AuthMaterial authMaterialA = new AuthMaterial( "MaterialA", properties, true);
// Create MaterialB and MaterialC
AuthMaterial authMaterialB = new AuthMaterial( "MaterialB", null, false);
AuthMaterial authMaterialC = new AuthMaterial( "MaterialC", null, false);
// Add MaterialB and MaterialC as child nodes of MaterialA.
authMaterialA.addChildMaterial( MaterialB);
authMaterialA.addChildMaterial( MaterialC);
return( authMaterialA);
}
Below is an example of this same AuthMaterial object that is now populated with values. It could be passed to an authentication method to be authenticated. The AuthMaterial object would be passed to the processAuthMaterialResponse method of the IAuthMethd interface.

Below is the code that shows how someone collecting a MaterialA AuthMaterial object would create it and populate it with appropriate values. The created AuthMaterial object would be passed to the processAuthMaterialResponse method of the IAuthMethod interface.
import org.bandit.otis.impl.AuthMaterial;
import java.util.Map;
import java.util.HashMap;
public AuthMaterial getMaterialAWithValues(
String strValueForMaterialB,
String strValueForMaterialC)
{
// Create MaterialA - note that there is no need to set properties here
// because this AuthMaterial object is being returned in response to
// request to get MaterialA authentication materials.
AuthMaterial authMaterialA = new AuthMaterial( "MaterialA", null, true);
// Create MaterialB and MaterialC
AuthMaterial authMaterialB = new AuthMaterial( "MaterialB", null, false);
AuthMaterial authMaterialC = new AuthMaterial( "MaterialC", null, false);
// Set values for MaterialB and MaterialC - Strings are used here, but other simple types are also allowed
authMaterialB.setValue( strValueForMaterialB);
authMaterialC.setValue( strValueForMaterialC);
// Add MaterialB and MaterialC as child nodes of MaterialA. Note that the order matters.
authMaterialA.addChildMaterial( MaterialB);
authMaterialA.addChildMaterial( MaterialC);
return( authMaterialA);
}
Below is an example of an AuthMaterial object that specifies complex material MaterialX. MaterialX has two alternatives for authentication - either complex MaterialY or complex MaterialZ. MaterialY if chosen would need to return MaterialA and MaterialB. MaterialZ if chosen would need to return MaterialC and MaterialD.

Here is how an authentication method implementing the getNextAuthMaterialRequest method of the IAuthMethod interface might create an AuthMaterial request for MaterialX:
import org.bandit.otis.impl.AuthMaterial;
public AuthMaterial getNextAuthMaterialRequest() throws AuthSessionException
{
// Create MaterialX, Y, Z, A, B, C, and D
AuthMaterial authMaterialX = new AuthMaterial( "MaterialX", null, false);
AuthMaterial authMaterialY = new AuthMaterial( "MaterialY", null, true);
AuthMaterial authMaterialZ = new AuthMaterial( "MaterialZ", null, true);
AuthMaterial authMaterialA = new AuthMaterial( "MaterialA", null, false);
AuthMaterial authMaterialB = new AuthMaterial( "MaterialB", null, false);
AuthMaterial authMaterialC = new AuthMaterial( "MaterialC", null, false);
AuthMaterial authMaterialD = new AuthMaterial( "MaterialD", null, false);
// Make A & B children of Y, C & D children of Z, and Y & Z children of X
authMaterialY.addChildMaterial( authMaterialA);
authMaterialY.addChildMaterial( authMaterialB);
authMaterialZ.addChildMaterial( authMaterialC);
authMaterialZ.addChildMaterial( authMaterialD);
authMaterialX.addChildMaterial( authMaterialY);
authMaterialX.addChildMaterial( authMaterialZ);
return( authMaterialX);
}
The following illustrates an AuthMaterial for MaterialX that is populated with values. Observe that only leaf nodes MaterialA and MaterialB have values, as it is only necessary for either the MaterialY or the MaterialZ branch of the tree to be populated.

Below is the code that shows how someone collecting a MaterialX AuthMaterial object would create it and populate it as illustrated above. Note that only child materials A and B are actually populated with values. Also note that the example below does NOT create the MaterialZ branch, as it is not necessary. The created AuthMaterial object would be passed to the processAuthMaterialResponse method of the IAuthMethod interface.
import org.bandit.otis.impl.AuthMaterial;
public AuthMaterial getMaterialXWithValues()
{
// Create MaterialX, Y, A, & B
AuthMaterial authMaterialX = new AuthMaterial( "MaterialX", null, false);
AuthMaterial authMaterialY = new AuthMaterial( "MaterialY", null, true);
AuthMaterial authMaterialA = new AuthMaterial( "MaterialA", null, false);
AuthMaterial authMaterialB = new AuthMaterial( "MaterialB", null, false);
// Put values into A and B
authMaterialA.setValue( "....some value....");
authMaterialB.setValue( "....some value....");
// Make A & B children of Y, and Y a child of X
authMaterialY.addChildMaterial( authMaterialA);
authMaterialY.addChildMaterial( authMaterialB);
authMaterialX.addChildMaterial( authMaterialY);
return( authMaterialX);
}
Configuration Settings For Your IAuthMethod Implementation
A place for authentication method settings is reserved in the overall configuration settings for the OTIS client, which is documented here. Within OTIS client settings, there is a setting whose name (or key) is authMethods. This setting is a List (java.util.List) which contains a sub-Map for each authentication method. Within that sub-map, there is a setting called authMethodID which contains the URI for the method. There is also a setting called authMethodClass which contains the name of the Java class that implements the authentication method. Other method-specific settings for the authentication method may be included in the map. These will be passed to the Java class via a call to its configure method (see above). In documenting settings, we use the XML settings syntax described here. Built-in authentication method settings are illustrated using this XML syntax here. Settings for a new custom token type called urn:my-custom-auth:1.0:fingerprintAuthMethod with an implementing Java class of org.mycorp.customMethods.FingerPrintAuthMethod might have custom configuration that looks as follows:
<Setting Name="authMethods" Type="htf:list">
<Setting Type="htf:map">
<Setting Name="authMethodID" Type="xsd:string">urn:my-custom-auth:1.0:fingerprintAuthMethod</Setting>
<Setting Name="authMethodClass" Type="xsd:string">org.mycorp.customMethods.FingerPrintAuthMethod</Setting>
<!-- Custom settings for this authentication method would go here -->
</Setting>
<!-- Other authentication methods would be siblings to the fingerprint authentication method defined above -->
</Setting>
Authentication Material Gatherer Object
Authentication methods (except for anonymous) require authentication materials to be provided (such as username/password). Multi-step methods may require authentication materials to be provided at different points during the authentication process. Multi-step methods, by definition, cannot receive all required authentication materials up front, because the materials needed for a given authentication step may be dependent on validation of materials received in previous steps. This means that a mechanism must be provided which allows authentication materials to be gathered as needed during authentication. This is true for even single-step authentication methods, because a generic application may allow policy to decide what authentication method is going to be used, and hence cannot pre-gather the required authentication materials.
With pluggable custom authentication, there will be be many different kinds of custom authentication materials that may need to be collected. The mechanisms for collecting those materials will be as varied as there are custom authentication methods and applications. It is neither desirable or possible to provide a single common mechanism for collecting those materials from an end user. Even for materials as simple and well understood as username and password, the technique used to collect them may need to vary a great deal from application to application. In some cases, it may be desirable to simply read the username and password from a file. In other cases, the application may want to prompt the user, but wants the UI to have an application-specific look and feel. And so on.
Out of this arises a need for a pluggable interface that can be used on the client side to gather authentication materials. This is the IGatherAuthMaterial interface. The OTIS client-side SDK relies on implementations of this interface to collect authentication materials. Implementers of the interface determine how authentication materials are to be gathered from an end user - UI, file, device, etc. OTIS allows a specific authentication material gatherer object to be registered for each authentication method. This may be done via configuration (see here), or by calling the IAuthSession.registerAuthMethodGatherer method. When OTIS needs to collect authentication material for an authentication method, it will call the registered gatherer object to get those materials. If no gatherer object is registered, the authentication will fail.
The IGatherAuthMaterial interface has a single method, requestAuthMaterial, shown below:
AuthMaterial requestAuthMaterial(String strMethodID, AuthMaterial authMaterialReq) throws AuthSessionException;
Deploying Your Custom Authentication Method in the OTIS Server
The easiest way to deploy your IAuthMethod implementation is to produce a Java jar file which contains the class. This jar file, along with any jar files it depends on, may then simply be dropped into the WEB-INF/lib directory for the OTIS server application. The OTIS server application will need to be restarted in order for it to see new jar files. All jar files in the WEB-INF/lib directory are included in the OTIS server application's classpath when it is started up.
The OTIS configuration file also needs to be configured so that OTIS knows how to instantiate the proper Java class for a given custom authentication method (see above). There is a LocalAuthSession setting inside the OTIS settings which will contain the authMethods setting that is described above. Custom authentication method settings should be placed there. See here for documentation on settings for the OTIS server.
OTIS Client SDK Use of Custom Authentication Methods
If you use the OTIS client SDK and want to ensure that custom authentication methods types are accessible there in local-only mode (no OTIS server), you must make sure that your custom Java class can be found in the classpath for your application when it runs. There are a number of ways to do this, all well known to Java developers. The OTIS client configuration file also needs to be properly modified so that the OTIS client knows how to instantiate the proper Java class for a given custom authentication method (see above).
Using a Custom Authentication Method in an Application
Once a new authentication method has been created and made available in OTIS, developers will want to take advantage of it. A developer's access to an authentication method is controlled by authentication policy in the configuration of the OTIS client. For more information on how authentication policy is configured and how it works, please see the documentation here.
A developer may attempt to explictly use an authentication method (if authentication policy allows it), or they may simply code their application to use whatever authentication policy has been configured. Both of these techniques are described in more detail below. In both cases, an application may be required to provide authentication materials.
Explicitly Using an Authentication Method
An application may explicitly invoke an authentication method, either with or without authentication materials. If an application invokes an authentication method without passing authentication materials, one of two things will happen, depending on the authentication method being invoked.
- If the authentication method does not require any authentication materials (like the anonymous method), no authentication materials will be requested.
- If the authentication method requires authentication materials, OTIS will see if an IGatherAuthMaterial object is registered for the method. If so, the object will be called to requested the needed authentication materials. If no IGatherAuthMaterial object is registered, OTIS will throw an exception.
If the application passes in authentication materials, they are considered to be authentication materials for the method's first authentication step. If the authentication method is multi-step, OTIS will request more authentication materials when it goes on to the next step(s). Thus, for multi-step authentication methods, it is ALWAYS necessary to have an appropriate IGatherAuthMaterial object registered for the method. For single-step authentication methods, it is only necessary if the authentication materials are not supplied in the initial request.
Note that although an application can request a specific authentication method, authentication policy may not allow the request. Note also that if an application requests a specific method, but the method fails to authenticate, alternative methods in the authentication policy are not automatically tried. Below are some examples of authentication policies and the outcomes:
- Policy: AAuthMethod and BAuthMethod. Application can request AAuthMethod, but not BAuthMethod, because this policy states that AAuthMethod must be done first. If AAuthMethod is successful, OTIS will automatically go on to BAuthMethod.
- Policy: AAuthMethod or BAuthMethod or CAuthMethod. Application can request any of AAuthMethod, BAuthMethod, or CAuthMethod. If the one the application request fails, the others are NOT automatically tried.
- Policy: (AAuthMethod and BAuthMethod) or (CAuthMethod and DAuthMethod). Application can request AAuthMethod or CAuthMethod, but not BAuthMethod (it must be preceded by AAuthMethod) or DAuthMethod (it must be preceded by CAuthMethod). If AAuthMethod is requested and is successful, OTIS will automatically go on to BAuthMethod. If CAuthMethod is requested and is successful, OTIS will automatically go on to DAuthMethod.
Below is an example of calling the username/password authentication method, passing in the username and password authentication material.
import org.bandit.otis.impl.UsernamePasswordAuthMethod; // Assume that session has been previously obtained. It is of type IAuthSession. // Authenticate with the username/password method. username="joe", password="abcdef78" // We call the static getMaterialResponse method on the UsernamePasswordAuthMethod class to generate an appropriate // AuthMaterial object to pass into the authenticate method as the authentication material. session.authenticate( "urn:bandit-project:otis:authmethod:1.0:usernamePassword", UsernamePasswordAuthMethod.getMaterialResponse( "joe", "abcdef78"));
Below is an example of calling the username/password authentication method, but NOT passing in the username and password authentication material. In this case, OTIS will end up looking for a registered IGatherAuthMaterial object to call to get the username and password authentication material. This example does not show it, but it is assumed that an appropriate IGatherAuthMaterial object has been registered for the username/password authentication method either via configuration, or explicitly by the application elsewhere. If no IGatherAuthMaterial object has been registered, an exception will be thrown by the call to authenticate.
import org.bandit.otis.impl.UsernamePasswordAuthMethod; // Assume that session has been previously obtained. It is of type IAuthSession. // Authenticate with the username/password method. No authentication material is given, so OTIS will see if // an IGatherAuthMaterial object has been registered for the authentication method. If not, an exception // will be thrown. session.authenticate( "urn:bandit-project:otis:authmethod:1.0:usernamePassword", null);
Policy Driven Authentication
An application may choose not to use a specific authentication method. In this case, OTIS will determine what authentication methods to try and the order to try them in according to the logic of the configured authentication policy. Here are some examples:
- Policy: AAuthMethod or BAuthMethod or CAuthMethod. OTIS will try AAuthMethod first. If it fails, it will try BAuthMethod. If that fails, it will try CAuthMethod. As soon as one of the three methods succeeds, no other methods are tried.
- Policy: AAuthMethod and BAuthMethod and CAuthMethod. OTIS will require that all three methods be successfully executed in the order specified: AAuthMethod, BAuthMethod, CAuthMethod.
- Policy: (AAuthMethod and BAuthMethod) or (CAuthMethod and DAuthMethod). OTIS will start with AAuthMethod, followed by BAuthMethod. If either of those fail, it will try CAuthMethod followed by DAuthMethod.
- Policy: (AAuthMethod or BAuthMethod) and (CAuthMethod or DAuthMethod). OTIS will start with AAuthMethod. If that fails, it will try BAuthMethod. If both AAuthMethod and BAuthMethod fails, it will not try anything else. Otherwise it will try CAuthMethod. If CAuthMethod succeeds, it is done. Otherwise, it will try DAuthMethod. If both CAuthMethod and DAuthMethod fail, authentication fails.
Below is example java code that allows OTIS to determine what authentication methods to try. Note that neither an authentication method or authentication materials are specified in the call to authenticate. As OTIS tries authentication methods (determined by configured authentication policy) and needs to collect authentication materials, it will lookup whatever IGatherAuthMaterial object is registered for the authentication method it is using. If no IGatherAuthMaterial object has been registered, an exception will be thrown by the call to authenticate.
// Assume that session has been previously obtained. It is of type IAuthSession. // Authenticate with no method name or authentication material. Authentication policy will determine // what authentication methods get called and the order in which they are called. session.authenticate( null, null);
REST Protocol Example
Let's suppose that the following custom authentication method has been defined:
- Authentication Method ID: urn:my-custom-auth:1.0:fingerprintAuthMethod
- Java Class Implementing the IAuthMethod Interface: org.mycorp.customMethods.FingerPrintAuthMethod.
Further, let's suppose that this custom method is multi-step. It first validates an employee ID number and then a fingerprint:
- Employee ID Number. A String that must be in the format of "xxx-xx-xxxx". MaterialID = urn:my-custom-authmaterial:1.0:employeeid.
- Fingerprint. A binary data array. MaterialID = urn:my-custom-authmaterial:1.0:fingerprint.
Finally let's suppose that the OTIS server authentication policy is set up to use this custom authentication method. Below is the exchange of REST messages between some client that knows the REST protocol and the OTIS server.
Step 1. Client Sends Authenticate Request
This request does not specify an authentication method or any authentication materials. It is very simple:
<otis:Authenticate xmlns:otis="http://code.bandit-project.org/schemas/2008/otis"> </otis:Authenticate>
Step 2. OTIS Responds With Request For Authentication Material - Employee ID
The OTIS server looks up its authentication policy and discovers that it is to use the fingerprint authentication method. It asks the method what authentication materials are needed, and sends a request for those materials back to the client.
<otis:AuthenticateResponse xmlns:otis="http://code.bandit-project.org/schemas/2008/otis"
methodID="urn:my-custom-auth:1.0:fingerprintAuthMethod">
<!-- Items the client will need to respond back to the OTIS server. There are three things:
1. $sessionID: a HEX string
2. $sessionSecret: a BIG HEX string. This needs to be sent back to the OTIS server in
all subsequent HTTP requests in an HTTP header called SessionSecret
3. $sessionURL: This is the URL that should be used in subsequent HTTP requests.
-->
<otis:sessionID>$sessionID</otis:sessionID>
<otis:sessionSecret>$sessionSecret</otis:sessionSecret>
<otis:sessionURL>$sessionURL</otis:sessionURL>
<!-- Presence of the AuthMaterial element means that this is a request for some authentication material.
This represents a request for the employee id -->
<otis:AuthMaterial materialID="urn:my-custom-authmaterial:1.0:employeeid">
</otis:AuthMaterial>
</otis:AuthenticateResponse>
Step 3. Client Gets Employee ID and Sends To OTIS Server
The client sees that OTIS wants an employee ID number, prompts the user to enter it, and sends it back to the OTIS server. The client does a PUT operation to the $sessionURL it received from the OTIS server in step 2 (see above). He also sets an HTTP header called SessionSecret to the $sessionSecret he received from the OTIS server in step 2 (see above). Content of the PUT is as follows:
<otis:Authenticate xmlns:otis="http://code.bandit-project.org/schemas/2008/otis"
methodID="urn:my-custom-auth:1.0:fingerprintAuthMethod">
<!-- Return the requested employee ID material -->
<otis:AuthMaterial materialID="urn:my-custom-authmaterial:1.0:employeeid">
<otis:AuthMaterialValue Type="string">128-44-3782</otis:AuthMaterialValue>
</otis:AuthMaterial>
</otis:Authenticate>
Step 4. OTIS Receives and Authenticates Employee ID, Requests Fingerprint
OTIS verifies the session secret it receives in the HTTP header, and looks up the session using the session ID found in the URL. It discovers that the session is in the middle of authenticating using the fingerprint authentication method. OTIS passes the employee ID number it received to the fingerprint authentication method, then asks the fingerprint method what to do next. Fingerprint authentication method tells OTIS that it now needs a fingerprint authentication material. OTIS sends that request back to the client.
<otis:AuthenticateResponse xmlns:otis="http://code.bandit-project.org/schemas/2008/otis"
methodID="urn:my-custom-auth:1.0:fingerprintAuthMethod">
<otis:sessionID>$sessionID</otis:sessionID>
<otis:sessionSecret>$sessionSecret</otis:sessionSecret>
<otis:sessionURL>$sessionURL</otis:sessionURL>
<!-- Presence of the AuthMaterial element means that this is a request for some authentication material.
This represents a request for the fingerprint -->
<otis:AuthMaterial materialID="urn:my-custom-authmaterial:1.0:fingerprint">
</otis:AuthMaterial>
</otis:AuthenticateResponse>
Step 5. Client Gets Fingerprint and Sends To OTIS Server
The client sees that OTIS wants a fingerprint, prompts the user to enter it, and sends it back to the OTIS server. The client does a PUT operation to the $sessionURL it received from the OTIS server in step 2 (see above). He also sets an HTTP header called SessionSecret to the $sessionSecret he received from the OTIS server in step 2 (see above). Content of the PUT is as follows:
<otis:Authenticate xmlns:otis="http://code.bandit-project.org/schemas/2008/otis"
methodID="urn:my-custom-auth:1.0:fingerprintAuthMethod">
<!-- Return the requested employee ID material -->
<otis:AuthMaterial materialID="urn:my-custom-authmaterial:1.0:fingerprint">
<otis:AuthMaterialValue Type="base64Binary">... base 64 encoded value for fingerprint ...</otis:AuthMaterialValue>
</otis:AuthMaterial>
</otis:Authenticate>
Step 6. OTIS Authenticates Fingerprint, Authentication Complete
OTIS verifies the session secret it receives in the HTTP header, and looks up the session using the session ID found in the URL. It discovers that the session is in the middle of authenticating using the fingerprint authentication method. OTIS passes the fingerprint it received to the fingerprint authentication method, then asks the fingerprint method what to do next. Fingerprint authentication method tells OTIS that authentication is complete. OTIS requests the authenticated entity ID from the fingerprint authentication method. OTIS then sends a response to client containing the authenticated entity ID. The presence of the AuthEntityID element tells the client that the authentication completed successfully.
<otis:AuthenticateResponse xmlns:otis="http://code.bandit-project.org/schemas/2008/otis"
methodID="urn:my-custom-auth:1.0:fingerprintAuthMethod">
<otis:sessionID>$sessionID</otis:sessionID>
<otis:sessionSecret>$sessionSecret</otis:sessionSecret>
<otis:sessionURL>$sessionURL</otis:sessionURL>
<!-- Presence of the AuthEntityID element means that the authentication is complete -->
<otis:AuthEntityID>ralphsmith</otis:AuthEntityID>
</otis:AuthenticateResponse>