{"id":139,"date":"2012-10-21T03:16:40","date_gmt":"2012-10-21T03:16:40","guid":{"rendered":"http:\/\/softwareeveryday.wordpress.com\/?p=139"},"modified":"2014-04-27T20:52:19","modified_gmt":"2014-04-27T20:52:19","slug":"playing-with-jaas","status":"publish","type":"post","link":"https:\/\/www.softwareeverydayblog.com\/?p=139","title":{"rendered":"Playing with JAAS"},"content":{"rendered":"<p>Just playing with JAAS the other day. Basically its a general set of interfaces and classes (framework) provided by Java to perform authorization and authentication.<\/p>\n<ol>\n<li>Here is the top level code used for authorization using JAAS.\n<pre lang=\"java\" line=\"1\">\r\npackage com.jassdemo;\r\n\r\nimport java.security.Principal;\r\nimport java.util.Set;\r\nimport javax.security.auth.Subject;\r\nimport javax.security.auth.login.LoginContext;\r\nimport javax.security.auth.login.LoginException;\r\nimport com.handler.DummyCallbackHandler;\r\n\r\npublic class JaasTest {\r\n\r\n\tpublic static void main(String args[]) {\r\n\t\tSystem.setProperty(\"java.security.auth.login.config\", \"jaas.config\");\t\/\/config file!\t\t\r\n\t\tLoginContext lc = null;\r\n\t\ttry {\r\n\t\t\tlc = new LoginContext(\"Example\", new DummyCallbackHandler(\"username\",\"password\"));\r\n\t\t\tlc.login();\t        \r\n\t\t\tSubject sub=lc.getSubject();\r\n\t\t\tSet<Principal> principals=sub.getPrincipals();\r\n\t\t\tSet<Object> credentials=sub.getPublicCredentials();\t        \r\n\t\t\tSystem.out.println(principals);\r\n\t\t\tSystem.out.println(credentials);\r\n\t\t} catch (LoginException e) {\r\n\t\t\t\/\/ Authentication failed.\r\n\t\t\te.printStackTrace();\r\n\t\t}\t\t\r\n\t\t\/\/ Authentication successful, we can now continue.\r\n\t\t\/\/ We can use the returned Subject if we like.\r\n\t\tSubject sub = lc.getSubject();\t    \r\n\t}\r\n\r\n}\r\n<\/pre>\n<\/li>\n<li>Create a jaas.config file that contains names of modules that are responsible for authentication. &#8220;Example&#8221; represents a set of LoginModules used to authenticate someone (called a Subject). jaas.config should be in the classpath. We use this name when creating a new <a href=\"http:\/\/docs.oracle.com\/javase\/7\/docs\/api\/javax\/security\/auth\/login\/LoginContext.html\" title=\"LoginContext\" target=\"_blank\">LoginContext(String name, CallbackHandler callbackHandler)<\/a>.\n<pre lang=\"text\">\r\nExample {\r\n  com.module.DummyLoginModule optional username=\"username\" password=\"password\";\r\n  com.module.AlwaysLoginModule required;\r\n};\r\n<\/pre>\n<\/li>\n<li>Every source that you wish to authenticate\u00a0against\u00a0will have its own LoginModule. Your login module implements the\u00a0LoginModule interface.\u00a0You have some built in ones, make sure you check if any of them work for you. However, if you want to authenticate\u00a0against\u00a0some custom data source (webservice? DB? etc) you would need to create your own modules. In case of my example i have a\u00a0AlwaysLoginModule (which always logs in irrespective of username\/pass) and a\u00a0DummyLoginModule which authenticates\u00a0against\u00a0a hardcoded user\/pass.\n<p>Here is a brief description of methods in a module.<\/p>\n<ul>\n<li>initialize() method\u00a0initialize&#8217;s objects for the LoginModule. Parameters passed in the Example config can be read here.<\/li>\n<li>login() method is where authentication happens. Principal and Credential objects are initialized.<\/li>\n<li>commit(). One config can have multiple LoginModules. commit is called if\u00a0LoginContext&#8217;s overall authentication succeeded. \u00a0In the example above, since\u00a0DummyLoginModule is optional, even if it doesn&#8217;t succeed the overall authentication will succeed if\u00a0AlwaysLoginModule\u00a0succeeds. So commit will be called.<\/li>\n<li>abort()\u00a0One config can have multiple LoginModules. abort is called if\u00a0LoginContext&#8217;s overall authentication failed. \u00a0In the example above, since AlwaysLoginModule is required, if it doesn&#8217;t succeed the overall authentication will fail and abort will be called.<\/li>\n<li>logout() method uninitialize&#8217;s objects within the LoginModule.<\/li>\n<\/ul>\n<pre lang=\"java\" line=\"1\">\r\npackage com.module;\r\n\r\nimport java.util.Map;\r\n\r\nimport javax.security.auth.Subject;\r\nimport javax.security.auth.callback.CallbackHandler;\r\nimport javax.security.auth.login.LoginException;\r\nimport javax.security.auth.spi.LoginModule;\r\n\r\nimport com.credentials.MyUserCredentials;\r\nimport com.principal.MyUserPrincipal;\r\n\r\npublic class AlwaysLoginModule implements LoginModule {\r\n\t\r\n\tprivate Subject subject;\r\n\tprivate CallbackHandler callbackHandler;\r\n\tprivate Map<String, ?> sharedState;\r\n\tprivate Map<String, ?> options;\r\n\t\r\n\tprivate MyUserPrincipal principal;\r\n\tprivate MyUserCredentials credentials;\r\n\tprivate boolean success;\r\n\t\r\n\t@Override\r\n\tpublic void initialize(Subject subject, CallbackHandler callbackHandler,\r\n\t\t\tMap<String, ?> sharedState, Map<String, ?> options) {\r\n\t\tthis.subject = subject;\r\n\t\tthis.callbackHandler = callbackHandler;\r\n\t\tthis.sharedState = sharedState;\r\n\t\tthis.options = options;\t\r\n\r\n\t\tsuccess = false;\r\n\t}\r\n\r\n\t@Override\r\n\tpublic boolean login() throws LoginException {\r\n\t\t\t\t\r\n\t\t\/\/ always login success!\r\n\t\t\/\/ add these if commit was called!\r\n\t\tprincipal=new MyUserPrincipal(\"alwaysloggedinusername\");\r\n\t\tcredentials=new MyUserCredentials();\r\n\t\tcredentials.put(\"guestpermission\", true);\r\n\t\t\t\r\n\t\tsuccess = true;\r\n\t\t\r\n\t\treturn true;\r\n\t\t\r\n\t}\r\n\r\n\t@Override\r\n\tpublic boolean commit() throws LoginException {\r\n\t\t\r\n\t\tif ( success ) {\r\n\t\t\t\r\n\t\t\tsubject.getPrincipals().add(principal);\r\n\t\t\tsubject.getPublicCredentials().add(credentials);\r\n\t\t\t\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\t\r\n\t\treturn false;\r\n\t}\r\n\r\n\t@Override\r\n\tpublic boolean abort() throws LoginException {\r\n\t\t\r\n\t\tif ( success ) {\r\n\t\t\t\r\n\t\t\tcallbackHandler = null;\r\n\t\t\tsharedState = null;\r\n\t\t\toptions = null;\r\n\t\t\t\t\t\t\r\n\t\t\tsubject.getPrincipals().remove(principal);\r\n\t\t\tsubject.getPublicCredentials().remove(credentials);\r\n\t\t\t\r\n\t\t\tprincipal = null;\r\n\t\t\tcredentials = null;\r\n\t\t\t\r\n\t\t\t\/\/ TODO Auto-generated method stub\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\r\n\t\treturn false;\r\n\t\t\t\r\n\t}\r\n\r\n\t@Override\r\n\tpublic boolean logout() throws LoginException {\r\n\t\t\r\n\t\tcallbackHandler = null;\r\n\t\tsharedState = null;\r\n\t\toptions = null;\r\n\t\t\r\n\t\tsuccess = false;\r\n\t\t\r\n\t\tsubject.getPrincipals().remove(principal);\r\n\t\tsubject.getPublicCredentials().remove(credentials);\r\n\r\n\t\tprincipal = null;\r\n\t\tcredentials = null;\r\n\r\n\t\treturn true;\r\n\t\r\n\t}\r\n\r\n}\r\n<\/pre>\n<pre lang=\"java\" line=\"1\">\r\npackage com.module;\r\n\r\nimport java.io.IOException;\r\nimport java.util.Map;\r\n\r\nimport javax.security.auth.Subject;\r\nimport javax.security.auth.callback.Callback;\r\nimport javax.security.auth.callback.CallbackHandler;\r\nimport javax.security.auth.callback.UnsupportedCallbackException;\r\nimport javax.security.auth.login.LoginException;\r\nimport javax.security.auth.spi.LoginModule;\r\n\r\nimport com.callback.NamePassCallback;\r\nimport com.credentials.MyUserCredentials;\r\nimport com.principal.MyUserPrincipal;\r\nimport com.principal.MyUserRole;\r\n\r\npublic class DummyLoginModule implements LoginModule {\r\n\t\r\n\tprivate Subject subject;\r\n\tprivate CallbackHandler callbackHandler;\r\n\tprivate Map<String, ?> sharedState;\r\n\tprivate Map<String, ?> options;\r\n\t\r\n\tprivate MyUserPrincipal principal;\r\n\tprivate MyUserCredentials credentials;\r\n\tprivate boolean success;\r\n\t\r\n\t@Override\r\n\tpublic void initialize(Subject subject, CallbackHandler callbackHandler,\r\n\t\t\tMap<String, ?> sharedState, Map<String, ?> options) {\r\n\t\tthis.subject = subject;\r\n\t\tthis.callbackHandler = callbackHandler;\r\n\t\tthis.sharedState = sharedState;\r\n\t\tthis.options = options;\t\r\n\t\tsuccess = false;\r\n\t}\r\n\r\n\t@Override\r\n\tpublic boolean login() throws LoginException {\r\n\t\t\r\n\t\tif ( callbackHandler == null ) {\r\n\t\t\tthrow new LoginException(\"no handler\");\r\n\t\t}\r\n\t\t\r\n\t\t\/\/ Callback is just like a VO object, that the handler will populate!\r\n\t\tNamePassCallback namePassCallback=new NamePassCallback(\"NamePassCallback Prompt!!\");\r\n\t\tCallback[] callbacks = new Callback[] { namePassCallback };\r\n\t\t\r\n\t\ttry {\r\n\t\t\r\n\t\t\tcallbackHandler.handle(callbacks);\r\n\t\t\r\n\t\t} catch (IOException e) {\r\n\t\t\t\r\n\t\t\tthrow new LoginException(\"handler io error\");\r\n\t\t\r\n\t\t} catch (UnsupportedCallbackException e) {\r\n\t\t\r\n\t\t\tthrow new LoginException(\"unsupported callback error\");\r\n\t\t\r\n\t\t}\r\n\t\t\r\n\t\tString username = namePassCallback.getUser();\r\n\t\tString password = new String(namePassCallback.getPass());\r\n\t\t\r\n\t\tif ( options.get(\"username\").equals(username) && options.get(\"password\").equals(password) ) {\r\n\t\t\t\r\n\t\t\t\/\/ add these if commit was called!\r\n\t\t\tprincipal=new MyUserPrincipal(username);\r\n\t\t\tcredentials=new MyUserCredentials();\r\n\t\t\tcredentials.put(\"allpermission\", true);\r\n\t\t\tcredentials.put(\"grantpermission\", true);\r\n\t\t\t\r\n\t\t\tsuccess = true;\r\n\t\t\t\t\r\n\t\t} else {\r\n\t\t\t\r\n\t\t\tthrow new LoginException(\"incorrect username\/password\");\r\n\r\n\t\t}\r\n\t\t\r\n\t\treturn true;\r\n\t}\r\n\r\n\t@Override\r\n\tpublic boolean commit() throws LoginException {\r\n\t\t\r\n\t\tif ( success ) {\r\n\t\t\t\r\n\t\t\tsubject.getPrincipals().add(principal);\r\n\t\t\tsubject.getPublicCredentials().add(credentials);\r\n\t\t\t\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\t\r\n\t\treturn false;\r\n\t}\r\n\r\n\t@Override\r\n\tpublic boolean abort() throws LoginException {\r\n\t\t\r\n\t\tif ( success ) {\r\n\t\t\t\r\n\t\t\tcallbackHandler = null;\r\n\t\t\tsharedState = null;\r\n\t\t\toptions = null;\r\n\t\t\t\r\n\t\t\tprincipal = null;\r\n\t\t\tcredentials = null;\r\n\t\t\t\r\n\t\t\treturn true;\r\n\t\t}\r\n\t\r\n\t\treturn false;\r\n\t\r\n\t}\r\n\r\n\t@Override\r\n\tpublic boolean logout() throws LoginException {\r\n\t\t\r\n\t\tcallbackHandler = null;\r\n\t\tsharedState = null;\r\n\t\toptions = null;\r\n\t\t\r\n\t\tsuccess = false;\r\n\t\t\r\n\t\tsubject.getPrincipals().remove(principal);\r\n\t\tsubject.getPublicCredentials().remove(credentials);\r\n\r\n\t\tprincipal = null;\r\n\t\tcredentials = null;\r\n\r\n\t\treturn true;\r\n\t\r\n\t}\r\n\r\n}\r\n<\/pre>\n<\/li>\n<li>LoginModules use CallbackHandlers to get authentication data from users. We use Callback objects to get data out of handlers. Your handlers need to know what callbacks need to be handled, put data into them and send them back. Basically, think of Callback as data transfer objects that the LoginModule sends to the CallbackHandler, which are populated by the handler and sent back to LoginModule for use.\n<pre lang=\"java\" line=\"1\">\r\npackage com.handler;\r\n\r\nimport javax.security.auth.callback.Callback;\r\nimport javax.security.auth.callback.CallbackHandler;\r\nimport javax.security.auth.callback.NameCallback;\r\nimport javax.security.auth.callback.PasswordCallback;\r\nimport javax.security.auth.callback.UnsupportedCallbackException;\r\n\r\nimport com.callback.NamePassCallback;\r\n\r\npublic class DummyCallbackHandler implements CallbackHandler {\r\n\t\r\n\tString user;\r\n\tString pass;\r\n\t\r\n\tpublic DummyCallbackHandler(String user, String pass) {\r\n\t\tthis.user = user;\r\n\t\tthis.pass = pass;\r\n\t}\r\n\t\r\n\t@Override\r\n\tpublic void handle(Callback[] callbacks) throws UnsupportedCallbackException {\t\t\r\n\t\tfor ( int i = 0; i < callbacks.length; i++ ) {\t\t\t \r\n\t\t\tif (callbacks[i] instanceof NamePassCallback) {\t\t\t\t\r\n\t\t\t\tNamePassCallback namepassCallback = (NamePassCallback)callbacks[i];\r\n\t\t\t\tSystem.out.println(\"No need for prompt, we'll just use values in: \" + namepassCallback.getPrompt());\r\n\t\t\t\tnamepassCallback.setUser(user);\r\n\t\t\t\tnamepassCallback.setPass(pass);\t\t\t \r\n\t\t\t} else if (callbacks[i] instanceof NameCallback) {\t\t\t\t\r\n\t\t\t\tNameCallback nameCallback = (NameCallback)callbacks[i];\r\n\t\t\t\tnameCallback.setName(user);\t\t\t \r\n\t\t\t} else if (callbacks[i] instanceof PasswordCallback) {\t\t\t\t\r\n\t\t\t\tPasswordCallback passCallback = (PasswordCallback)callbacks[i];\r\n\t\t\t\tpassCallback.setPassword(pass.toCharArray());\t\t\t \r\n\t\t\t} else {\t\t\t\t\r\n\t\t\t\tthrow new UnsupportedCallbackException(callbacks[i], \"UnsupportedCallbackException\");\t\t\t\t\r\n\t\t\t}\t\r\n\t\t}\t\r\n\t}\r\n}\r\n<\/pre>\n<\/li>\n<\/ol>\n<p><a href='https:\/\/www.softwareeverydayblog.com\/wp-content\/uploads\/2012\/10\/MyJaasTest.zip'>You can download my JAAS demo code here<\/a>. There is this great post on Jaas in java world titled \"<a href=\"http:\/\/www.javaworld.com\/jw-09-2002\/jw-0913-jaas.html\">All that JAAS<\/a>\" that was very helpful.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Just playing with JAAS the other day. Basically its a general set of interfaces and classes (framework) provided by Java to perform authorization and authentication. Here is the top level code used for authorization using JAAS. package com.jassdemo; import java.security.Principal; import java.util.Set; import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; import com.handler.DummyCallbackHandler; public class JaasTest { public [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-139","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.softwareeverydayblog.com\/index.php?rest_route=\/wp\/v2\/posts\/139","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.softwareeverydayblog.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.softwareeverydayblog.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.softwareeverydayblog.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.softwareeverydayblog.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=139"}],"version-history":[{"count":23,"href":"https:\/\/www.softwareeverydayblog.com\/index.php?rest_route=\/wp\/v2\/posts\/139\/revisions"}],"predecessor-version":[{"id":3094,"href":"https:\/\/www.softwareeverydayblog.com\/index.php?rest_route=\/wp\/v2\/posts\/139\/revisions\/3094"}],"wp:attachment":[{"href":"https:\/\/www.softwareeverydayblog.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=139"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.softwareeverydayblog.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=139"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.softwareeverydayblog.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=139"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}