go to  ForumEasy.com   
JavaPro  
 
 
   Home  |  MyForum  |  FAQ  |  Archive    You are not logged in. [Login] or [Register]  
Forum Home » Java Authentication and Authorization Service (JAAS) » JAAS in Simple
Email To Friend  |   Set Alert To This Topic Rewarding Points Availabe: 0 (What's this) New Topic  |   Post Reply
Author Topic: JAAS in Simple
authen
member
offline   
 
posts: 56
joined: 06/05/2006
from: San Diego, CA
  posted on: 10/20/2012 12:40:24 AM    Edit  |   Quote  |   Report 
JAAS in Simple
What is JAAS?

JAAS stands for Java Authentication and Authorization Service (JAAS).

 Profile | Reply Points Earned: 0
authen
member
offline   
 
posts: 56
joined: 06/05/2006
from: San Diego, CA
  posted on: 10/20/2012 12:42:24 AM    Edit  |   Quote  |   Report 
The Beauty of JAAS

The beauty of JAAS is attributed to its simplest layout architecture. No matter how complicated the underlying implementation is, the interface remains essentially the same. Once the JAAS interface is integrated into your business layer, it's a done deal -- regardless of the change and upgrade at the actual authentication layer.

Here is a minimal example to integrate JAAS:
    /* JAAS Part I -- Authentication  */
    LoginContext lc = new LoginContext("myLoginEntity");
    try {
        lc.login();
    } catch (LoginException e) {
	throw e;
    }

    /* JAAS Part II -- Authorization */
    Subject sub = lc.getSubject();
    Subject.doAs(sub, new MyPrivilegedAction());



That's it. Just that simple!
 Profile | Reply Points Earned: 0
authen
member
offline   
 
posts: 56
joined: 06/05/2006
from: San Diego, CA
  posted on: 10/20/2012 12:44:52 AM    Edit  |   Quote  |   Report 
JAAS Pluggable Login Module

JAAS implements a Java version of the standard Pluggable Authentication Module (PAM) framework. All login modules are implementing the common interface LoginModule:
                    +---------------+
                    |  LoginModule  | <-- {login,logout,...}
                    +---------------+
                         /       \ 
                        /         \
         +-----------------+    +-----------------+
         | MyLoginModule_1 |    | MyLoginModule_2 |  ...
         +-----------------+    +-----------------+


For example, you can use com.sun.security.auth.module.Krb5LoginModule to handle Kerberos authentication to KDC.

 Profile | Reply Points Earned: 0
authen
member
offline   
 
posts: 56
joined: 06/05/2006
from: San Diego, CA
  posted on: 10/20/2012 12:48:48 AM    Edit  |   Quote  |   Report 
Injection of Customized JAAS Login Module
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.


  •  Profile | Reply Points Earned: 0
    authen
    member
    offline   
     
    posts: 56
    joined: 06/05/2006
    from: San Diego, CA
      posted on: 10/20/2012 12:53:55 AM    Edit  |   Quote  |   Report 
    How to create my own JAAS login module
    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);
        }
    
    }
    

     Profile | Reply Points Earned: 0
    authen
    member
    offline   
     
    posts: 56
    joined: 06/05/2006
    from: San Diego, CA
      posted on: 10/20/2012 12:57:07 AM    Edit  |   Quote  |   Report 
    Stand alone test before let your custom module out
        public static void main(String[] args) throws Exception 
        {
        	try{
    
        	    Subject subject = new Subject();
    
        	    MyLoginModule myLoginModule = new MyLoginModule();
                Map <String, String> map = new HashMap <String, String>();
                map.put("anonymousAllowed", "false");
    
                // CallbackHandler
                final String name = "Joe";
                final String password = "Joe";
                CallbackHandler ch = new CallbackHandler(){
                    public void handle (Callback[] callbacks) throws
                        UnsupportedCallbackException, IOException
                    {
                        for(int j=0; j<callbacks.length; j++) {
                        	
                            Callback callBack = callbacks[j];
    
                            // Handles username callback.
                            if (callBack instanceof NameCallback) {
                                NameCallback nc = (NameCallback)callBack;
                                nc.setName(name);
    
                            // Handles password callback.
                            } else if (callBack instanceof PasswordCallback) {
                                PasswordCallback pc = (PasswordCallback)callBack;
                                pc.setPassword(password.toCharArray());
    
                            } else {
                                throw new UnsupportedCallbackException(callBack, 
                                		"Call back not supported");
                            }
                        }
                    }
                };
    
                myLoginModule.initialize(subject, ch, null, map);
                myLoginModule.login();
                myLoginModule.commit();
    
                System.out.println(subject);
    
        	}catch(Exception e){
                e.printStackTrace();
        	}
        }
    


    Here is the output:
    My Login Module - Constructor called
    My Login Module - initialize() called
    My Login Module - login() called
    Succeeded!
    My Login Module - commit() called
    Subject:
    	Principal: Joe
    

     Profile | Reply Points Earned: 0
    authen
    member
    offline   
     
    posts: 56
    joined: 06/05/2006
    from: San Diego, CA
      posted on: 10/20/2012 01:00:32 AM    Edit  |   Quote  |   Report 
    Inject your own login module into JAAS framework -- Put all pieces together
    Now that you have your own login module ready, you can integrate it into your business layer with the help of configuration file named C:\temp\jaas_login.conf:
    myLoginEntity {
        com.myCompany.MyLoginModule required
        anonymousAllowed=true
        debug=true;
    };
    


    Integration:
        public static void main(String[] args) throws Exception 
        {
        	
            System.setProperty("java.security.auth.login.config",
                                              "C:\\temp\\jaas_login.conf");
        	
        	try{
    
                // CallbackHandler
                final String name = "Joe";
                final String password = "Joe";
                CallbackHandler ch = new CallbackHandler(){
                    public void handle (Callback[] callbacks) throws
                        UnsupportedCallbackException, IOException
                    {
                        for(int j=0; j<callbacks.length; j++) {
                        	
                            Callback callBack = callbacks[j];
    
                            // Handles username callback.
                            if (callBack instanceof NameCallback) {
                                NameCallback nc = (NameCallback)callBack;
                                nc.setName(name);
    
                            // Handles password callback.
                            } else if (callBack instanceof PasswordCallback) {
                                PasswordCallback pc = (PasswordCallback)callBack;
                                pc.setPassword(password.toCharArray());
    
                            } else {
                                throw new UnsupportedCallbackException(callBack, 
                                		"Call back not supported");
                            }
                        }
                    }
                };
                
                LoginContext lc = new LoginContext("myLoginEntity", ch);
                lc.login();
    
                Subject subject = lc.getSubject();
    
                System.out.println(subject);
                
        	}catch(Exception e){
                e.printStackTrace();
        	}
        }
    


    Here is the output:
    My Login Module - Constructor called
    My Login Module - initialize() called
    My Login Module - login() called
    Succeeded!
    My Login Module - commit() called
    Subject:
    	Principal: Joe
    

     Profile | Reply Points Earned: 0
    authen
    member
    offline   
     
    posts: 56
    joined: 06/05/2006
    from: San Diego, CA
      posted on: 12/18/2013 08:47:04 PM    Edit  |   Quote  |   Report 
    JAAS framework is a perfect example of Strategy Design Pattern
    The strategy pattern is a behavioral design pattern. In the strategy pattern, different behaviors are represented as Concrete Strategy classes and they share a common Strategy interface. A Context class contains a reference to the common Strategy interface. By changing the Context's Strategy, different behaviors can be obtained.
           +-------------+                 +------------+
           |   Context   |* -------------->|  Strategy  |
           +-------------+                 +------------+
           | # logic()   |                 |  # hook(); |
           +-------------+                 +------------+
                                                 ^
                                                 |
                                        ----------------------
                                        |                    |
                                  +------------+       +------------+ 
                                  |  Strategy1 |       |  Strategy2 |
                                  +------------+       +------------+ 
                                  |  # hook()  |       |  # hook()  |
                                  +------------+       +------------+
    

    The strategy pattern is based on separation principle (in contrast to unification principle as in subclass inheritance) where Strategy specifying hook methods is defined on one side and business logic and user's data are processed inside Context on the other side (with help, for sure, for calling hook methods).

    Here, LoginContext serves as business logic Context and LoginModule serves as Strategy interface. With different input as to strategy "myLoginEntity" and user's data "CallBack", different authentication behavior can be achieved.

     Profile | Reply Points Earned: 0

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