Follow
the below steps and setup the application first. Run and experiment it, then go
through the description that I provided at the end.
Step 1: Create new java
project in Eclipse.
Open
Eclipse, right click on Package explorer -> New -> Java Project.
Give
the project name as 'jaas_tutorial'.
Step 2: Create package
'com.sample.handler' and define BasicAuthCallbackHandler class.
BasicAuthCallbackHandler.java
package com.sample.handler; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; 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; public class BasicAuthCallbackHandler implements CallbackHandler{ @Override public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { NameCallback nameCallBack = (NameCallback)callbacks[0]; PasswordCallback passwordCallback = (PasswordCallback)callbacks[1]; BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println(nameCallBack.getPrompt()); nameCallBack.setName(br.readLine()); System.out.println(passwordCallback.getPrompt()); passwordCallback.setPassword(br.readLine().toCharArray()); } }
Step 3: Create package
'com.sample.login' and define class BasicLoginModule like below.
BasicLoginModule.java
package com.smaple.login; import java.io.IOException; import java.util.Map; 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.LoginException; import javax.security.auth.spi.LoginModule; public class BasicLoginModule implements LoginModule { private String username = "krishna"; private String password = "krishna"; CallbackHandler callbackHandler; @Override public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options) { this.callbackHandler = callbackHandler; } @Override public boolean login() throws LoginException { Callback[] callbackArray = new Callback[2]; callbackArray[0] = new NameCallback("Enter logon id:"); callbackArray[1] = new PasswordCallback("Enter password:", false); try { callbackHandler.handle(callbackArray); } catch (IOException | UnsupportedCallbackException e) { e.printStackTrace(); throw new LoginException(e.getMessage()); } String logonId = ((NameCallback) callbackArray[0]).getName(); char[] passwordArr = ((PasswordCallback) callbackArray[1]).getPassword(); String password = new String(passwordArr); if (username.equals(logonId) && this.password.equals(password)) { System.out.println("Login successful"); return true; } throw new LoginException("Logon failed"); } @Override public boolean commit() throws LoginException { return true; } @Override public boolean abort() throws LoginException { return false; } @Override public boolean logout() throws LoginException { return true; } }
Step 4: Create a file
'jaasAuth.config' with below content.
jaasAuth.config
JaasTutorial{ com.smaple.login.BasicLoginModule required; };
Step 5: Define class
'com.sample.app' and define the class Test like below.
Test.java
package com.sample.app; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import com.sample.handler.BasicAuthCallbackHandler; public class Test { public static void main(String args[]) { System.setProperty("java.security.auth.login.config", "jaasAuth.config"); LoginContext loginContext = null; try { loginContext = new LoginContext("JaasTutorial", new BasicAuthCallbackHandler()); } catch (LoginException e) { // TODO Auto-generated catch block e.printStackTrace(); return; } try { loginContext.login(); } catch (LoginException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
Run
the application with improper username and password.
Enter logon id: kk Enter password: aaa javax.security.auth.login.LoginException: Logon failed at com.smaple.login.BasicLoginModule.login(BasicLoginModule.java:50) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at javax.security.auth.login.LoginContext.invoke(LoginContext.java:755) at javax.security.auth.login.LoginContext.access$000(LoginContext.java:195) at javax.security.auth.login.LoginContext$4.run(LoginContext.java:682) at javax.security.auth.login.LoginContext$4.run(LoginContext.java:680) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680) at javax.security.auth.login.LoginContext.login(LoginContext.java:587) at com.sample.app.Test.main(Test.java:23)
Run
the application with username and password as ‘krishna’, you can able to see
below output.
Enter logon id: krishna Enter password: krishna Login successful
There
are 4 components in above application.
a.
jaasAuth.config
file
b.
Initialize
LoginContext
c.
BasicLoginModule
d.
BasicAuthCallbackHandler
a. jaasAuth.config
We
should specify the login modules in this configuration file. You can give any
name to this file.
You
can specify one or more login modules and they will be executed in the order you defined.
Syntax of
configuration file
Name { ModuleClass Flag ModuleOptions; ModuleClass Flag ModuleOptions; ModuleClass Flag ModuleOptions; }; Name { ModuleClass Flag ModuleOptions; ModuleClass Flag ModuleOptions; }; other { ModuleClass Flag ModuleOptions; ModuleClass Flag ModuleOptions; };
In
this example, I defined the login module like below.
JaasTutorial{
com.smaple.login.BasicLoginModule
required;
};
Each
entry in the configuration file has unique name and list of module classes that
are used while authenticating the users. The login modules will execute the
order they specified in the entry.
For ex:
JaasTutorial{
com.smaple.login.BasicLoginModule
required;
com.smaple.login.OtpLoginModule
required;
};
In
above case, BasicLoginModule is executed first and OtpLoginModule will be
executed next.
What is other in the
config file?
If
application do not have specific entry, it uses the other module by default.
Flag attribute
It
can be set to one of the four values.
a.
Required
b.
Requisite
c.
Sufficient
d.
Optional
Below
table summarizes each attribute in detail.
Value
|
Description
|
Required
|
The LoginModule is required to succeed. If it
succeeds or fails, authentication still continues
to proceed down the LoginModule list.
|
Requisite
|
The LoginModule is required to succeed. If it
succeeds, authentication continues down the LoginModule list. If it fails, control immediately returns to
the application (authentication does
not proceed down the LoginModule list).
|
Sufficient
|
The LoginModule is not required to
succeed. If it does succeed, control
immediately returns to the application (authentication does not proceed down
the LoginModule list). If it fails,
authentication continues down the LoginModule list.
|
Optional
|
The LoginModule is not required to
succeed. If it succeeds or fails, authentication still continues to proceed
down the LoginModule list.
|
Module Options
By
using module options, we can pass the values directly to the login module. For
example, we can define the option, whether we should log the information, while
authenticating or not.
How to specify module
options?
By
using key=value pair syntax, we can specify the module options. the value must
be enclosed in double quotes.
Ex:
JaasTutorial{
com.smaple.login.BasicLoginModule
required
debug="true"
cache="enable";
};
Is there any limit on
number of module options?
No,
you can specify any number of options.
Can I specify system
properties?
Yes,
you can specify the system properties in the form of ${system.property}
Ex:
JaasTutorial{
com.smaple.login.BasicLoginModule
required
debug="true"
cache="enable"
userHome="${user.home}"
appHome =
"${user.home}${/}app";
};
I
am going to explain the complete example about the module options in my next
post.
b. Initialize
LoginContext
LoginContext
class reads the configuration file (Ex: jaasAuth.config) and initialize all the
login modules defines the configuration file. Each login module initialized
with subject, callbackHandler, sharedState and options (Check the initialize
method of BasicLoginModule class). Subject specifies the entity that is currently
being authenticated and the callbackHandler is used to communicate with
external world, for example, I defined BasicAuthCallbackHandler class to get
the username and password from user. 'sharedState' is used by login modules to
share the information among them.
System.setProperty("java.security.auth.login.config",
"jaasAuth.config");
LoginContext
loginContext = new LoginContext("JaasTutorial", new
BasicAuthCallbackHandler());
System
property ‘java.security.auth.login.config’ is used to specify the login
configuration file that should be used.
c. BasicLoginModule
All the authentication providers (login modules) must
implement LoginModule interface. LoginContext use the login() method of the
login module to check the authenticity of the users. The login() method
performs actual authentication and return true (or) false (or) can throw
LoginException.
Authentication
process in login module is divided into two phases.
Phase1
LoginContext
invokes the login method of login module.
Phase2
If
the overall logincontext authentication is successful, then the commit method
of the login module is invoked. If the overall LoginContext authentication
succeeded and the LoginModule's own authentication succeeded, then the commit
method associates the relevant Principals (authenticated identities) and
Credentials (authentication data such as cryptographic keys) with the Subject
located within the LoginModule.
If
the LoginContext's overall authentication failed (the relevant REQUIRED,
REQUISITE, SUFFICIENT and OPTIONAL LoginModules did not succeed), then the
abort method for each LoginModule gets invoked. In this case, the LoginModule
removes/destroys any authentication state originally saved.
D.
BasicAuthCallbackHandler
All
callback handlers must implement CallbackHandler interface. These are used to
interact with the application to retrieve authentication data like username and
password.
Can I provide the
jaas configuration file at run time?
Yes,
you can do like below.
java
-Djava.security.auth.login.config=jaasAuth.config App
Reference
No comments:
Post a Comment