go to  ForumEasy.com   
JavaPro
Home » Archive » Message


[Email To Friend][View in Live Context][prev topic « prev post | next post » next topic]
  How to create my own JAAS login module
 
Subject: How to create my own JAAS login module
Author: authen
In response to: Injection of Customized JAAS Login Module
Posted on: 10/20/2012 12:53:55 AM

package com.myCompany;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.security.Principal;
import com.sun.security.auth.UserPrincipal;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;


public class MyLoginModule implements LoginModule {

    private Subject subject;
    private CallbackHandler callbackHandler;
    private Map sharedState;
    private Map options;

    private boolean succeeded = false;
    private String username;
    
    public MyLoginModule() {
        System.out.println("My Login Module - Constructor called");
    }

    @Override
    // Required
    public boolean abort() throws LoginException {
        System.out.println("My Login Module - abort() called");
        return false;
    }

    @Override
    // Required
    public boolean commit() throws LoginException {
        System.out.println("My Login Module - commit() called");
        if(succeeded){
    	    Set princSet  = subject.getPrincipals();
    	    Principal principal = new UserPrincipal(username);
    	    princSet.add(principal);
        }
        return succeeded;
    }

    @Override
    // Required
    public void initialize(Subject subject, 
                           CallbackHandler callbackHandler, 
                           Map<String, ?> sharedState,
                           Map<String, ?> options) 
    {
        System.out.println("My Login Module - initialize() called");
        this.subject = subject;
        this.callbackHandler = callbackHandler;
        this.sharedState = sharedState;
        this.options = options;
        succeeded = false;
    }

    @Override
    // Required
    public boolean login() throws LoginException 
    {
        System.out.println("My Login Module - login() called");
        if (callbackHandler == null) {
            throw new LoginException("Oops, callbackHandler is null");
        }

        Callback[] callbacks = new Callback[2];
        callbacks[0] = new NameCallback("name:");
        callbacks[1] = new PasswordCallback("password:", false);

        try {
            callbackHandler.handle(callbacks);
        } catch (IOException e) {
            throw new LoginException(
            		"Oops, IOException calling handle on callbackHandler");
        } catch (UnsupportedCallbackException e) {
            throw new LoginException("Oops, UnsupportedCallbackException " +
                                        "calling handle on callbackHandler");
        }

        NameCallback nameCallback = (NameCallback) callbacks[0];
        PasswordCallback passwordCallback = (PasswordCallback) callbacks[1];

        // name & password from callback handler	
        String name = nameCallback.getName();
        String password = new String(passwordCallback.getPassword());

        // options from configuration settings
        String option = (String)options.get("anonymousAllowed");
        if(password==null || "".equals(password)){
            if( option!=null && option.equalsIgnoreCase("true") ){
                System.out.println("Succeeded!");
                username = name;
                succeeded = true;
                return succeeded;
            }
        }else if(authenticate(name, password)){
            System.out.println("Succeeded!");
            username = name;
            succeeded = true;
            return succeeded;
        }

        System.out.println("Failed!");
        succeeded = false;
        throw new FailedLoginException("Name and password not matched.");

    }

    @Override
    // Required
    public boolean logout() throws LoginException {
        System.out.println("My Login Module - logout() called");
        return false;
    }
    
    private boolean authenticate(String name, String password)
    {
	/* just an exmaple, you can put whatever your authenticating logic here */
    	return name.equals(password);
    }

}


 

> On 10/20/2012 12:48:48 AM authen wrote:

In order for your customized login module to be injected, you have to tell JAAS the following:
  • Where to find your configuration file;
  • Which login module to load and how it is loaded.

    Where to find your configuration file?
    If you name your JAAS login configuration file as jaas_login.conf and put it under directory c:\temp, then you can instruct your JVM to find it by property setting:
      System.setProperty("java.security.auth.login.config", "c:\\temp\\jaas_login.conf");
    


    Which login module to load and how it is loaded?
    The configuration file has the following structure:
          myLoginEntity {
              ModuleClass  Flag  Options;
              ModuleClass  Flag  Options;
              ...
          };
          myLoginEntity {
              ModuleClass  Flag  Options;
              ...
          };
          ...
    


    As an example:
    myLoginEntity {
        com.sun.security.auth.module.Krb5LoginModule required
        principal="myName@MY_REALM"
        useTicketCache=true
        ticketCache="C:\\temp\\krb5cc_myName"
        renewTGT=true
        useKeyTab=true
        keyTab="C:\\temp\\myName.keytab"
        storeKey=true;
    };
    


    Which instructs that Krb5LoginModule is to be injected with required flag and the corresponding options:
  • using principal myName@MY_REALM as login name and retrieving TGT ticket from cache C:\temp\krb5cc_myName; if a valid ticket found, no need to proceed.
  • if ticket expired (renewTGT=true) or ticket not found, retrieving the private key from keytab C:\temp\myName.keytab; if key is not found, prompting user for password input;
  • requesting Kerberos authentication to KDC by using the above principal and private key (or password); Confirmed by WireShark traffic KRB5 with AS-REQ/AS-REP
  • storing (storeKey=true) the private key into Subject's private space after successful authentication.

    Note:
  • By spec, when multiple mechanisms to retrieve a ticket or key is provided, the preference order looks like this:
    ---- 1. ticket cache
    ---- 2. keytab
    ---- 3. shared state
    ---- 4. user prompt
    For example, if "principal" is provided both from config and user specified, the value from config would take precedence.
  • The keyTab's path must be double-quote protected, otherwise exception would be thrown.
  • The back-slash (\) in path must be escaped(\\), otherwise, keyTab would be ignored and the user's password would be used instead.






    References:

  •  


     
    Powered by ForumEasy © 2002-2022, All Rights Reserved. | Privacy Policy | Terms of Use
     
    Get your own forum today. It's easy and free.