Authentication against Triplesec can be conducted using standard LDAP for static passwords and Kerberos for 2-Factor One Time Passwords. This way any language or platform can interoperate with Triplesec. This is how operating systems like Windows, *NIX and MacOSX can authenticate users. Here we are specifically concerned with Java based authentication. For Java based authenttication we recommend using the supplied SafehausLoginModule.
Setup
Make sure your host is configured to point to Triplesec in terms of it's Kerberos configuration. For more information on how to configure the Kerberos client libraries on your OS Platform see Kerberos Client Configuration.
Dependencies
To use the Safehaus JAAS LoginModule in your application you need the following runtime dependencies:
Module | Maven ArtifactId | Maven GroupId | Download URL |
---|---|---|---|
crypto | triplesec-crypto | triplesec | |
otp | triplesec-otp | triplesec | |
guardian-api | triplesec-guardian-api | triplesec | |
jaas | triplesec-jaas | triplesec | |
nlog4j | nlog4j | org.slf4j |
If you use Maven 2 you can just add the following dependencies to your POM in the dependencies section:
No Format |
---|
<dependency> <groupId>${project.groupId}</groupId> <artifactId>triplesec-crypto</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>triplesec-otp</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>triplesec-jaas</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>${project.groupId}</groupId> <artifactId>triplesec-guardian-api</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>nlog4j</artifactId> <version>1.2.24</version> </dependency> |
Building a CallbackHandler
The SafehausLoginModule like other JAAS Modules uses Callbacks to obtain parameters from an application to perform authentication. There are 5 different parameters expected. These parameters are the username (really a profileId), the static password, the realm, a passcode (2-factor OTP), and an Guardian ApplicationPolicy instance. There are multiple ways to obtain an ApplicationPolicy object. The mechanisms are discussed in other trails. See the following trials for more information on obtaining an ApplicationPolicy instance:
Authorization Using Guardian API
Using the LDIF Guardian Driver on Triplesec Exports
For this trail we'll presume you've obtained a valid ApplicationPolicy instance ahead of time. Below we have some code which passes these parameters to the SafehausLoginModule. The class is an implementation of a CallbackHandler:
Code Block |
---|
/** * Simple handler implementation for this Demo. */ class DemoHandler implements CallbackHandler { public void handle( Callback[] callbacks ) throws IOException, UnsupportedCallbackException { for ( int ii = 0; ii < callbacks.length; ii++ ) { if ( callbacks[ii] instanceof NameCallback ) { NameCallback ncb = ( NameCallback ) callbacks[ii]; ncb.setName( userId ); } else if ( callbacks[ii] instanceof PasswordCallback ) { PasswordCallback pcb = ( PasswordCallback ) callbacks[ii]; pcb.setPassword( password.toCharArray() ); } else if ( callbacks[ii] instanceof SafehausLoginModule.RealmCallback ) { RealmCallback rcb = ( RealmCallback ) callbacks[ii]; rcb.setRealm( realm ); } else if ( callbacks[ii] instanceof SafehausLoginModule.PolicyCallback ) { PolicyCallback pcb = ( PolicyCallback ) callbacks[ii]; pcb.setPolicy( policy ); } else if ( callbacks[ii] instanceof SafehausLoginModule.PasscodeCallback ) { PasscodeCallback pcb = ( PasscodeCallback ) callbacks[ii]; pcb.setPasscode( passcode ); } } } } |
As you can see this handler processes all the callbacks calling setters to populate callbacks with specific parameters. This handler is supplied as we'll see soon as an argument when calling the initialize method of the SafehausLoginModule.
Note |
---|
The username parameter supplied with the NameCallback is the profileId rather than the name of the user associated with the profile. Most of the time the id of the profile is the same as the user but sometimes additional profiles are created for a user which will not have the same name. For example user mcurie may have two profiles in an application: mcurie and mcurie-superuser. The user may login using mcurie-superuser but use the same credentials for both authorization profiles. The authentication is the same but the authorization is different. |
Triplesec allows for accounts without 2-Factor authentication. These users will not supply a passcode in which case a null value is handed off to the PasscodeCallback. This is ok since the login module optionally authenticates users based on the presence or absense of the passcode. When a passcode is not supplied for a user configured to use 2-factor authentication the authentication will fail.
Initialize and Login with the SafehausLoginModule
LoginModules are instantiated using the default constructor. They must then be initialized with configuration parameters and a handler like the one above. The intialize method takes 4 arguments: the subject to populate with Principals, the handler, a map for shared state and configuration options.
The subject can just be a newly instantiated Subject object. The handler is the one we built above. The shared state can be an empty HashMap and the options can be empty as well. There is an option worth mentioning however. By default the module does not allow the admin user to authenticate unless a special property is set to "true". This property key is SafehausLoginModule.ALLOW_ADMIN. The code below creates, initializes and login:
Code Block |
---|
LoginModule module = new SafehausLoginModule(); Subject subject = new Subject(); Map options = new HashMap(); options.put( SafehausLoginModule.ALLOW_ADMIN, "true" ); module.initialize( subject, new DemoHandler(), new HashMap(), options ); boolean result = module.login(); result &= module.commit(); |
This is pretty much it for the mechanics of using the SafehausLoginModule. For a complete working example see the Servlet or Swing demos:
Simple Demo Servlet Application
Simple Demo Swing Application