JAAS Security in Websphere

Discussions

XML & Web services: JAAS Security in Websphere

  1. JAAS Security in Websphere (1 messages)

    I am developing a webservice. I have a requirement to accept user credentials in the SOAP request header, authenticate the user and use the authenticated user info in the service business logic. My service will be hosted on Websphere and I am using WSAD 5.1.2 for development purpose. For authentication, I need to use a custom JAAS login module. I am able to successfully authenticate the user, but I am not able to retrieve the user principal within my service code. Here is my LoginModule implementation code: import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; 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.FailedLoginException; import javax.security.auth.login.LoginException; import javax.security.auth.spi.LoginModule; public class FileLoginModule implements LoginModule { private static final String classLogName = "[FileLoginModule] "; // initial state private Subject subject; private CallbackHandler callbackHandler; private Map sharedState; private Map options; // configurable options private String usersFile; //Mandatory - Full path of the file containing user list private String groupsFile; //Mandatory - Full path of the file containing group list private boolean debug = false; //Optional - if true, debug mode is on // the authentication status private boolean loginSucceeded = false; private boolean commitSucceeded = false; // username and password private String username; private char[] password; // User's Principal private SampleAuthPrincipal userPrincipal; /** * Initialize this FileLoginModule object. * *

    * * @param subject the Subject to be authenticated. * @param callbackHandler for communicating with the end user * (prompting for user names and passwords, for example). * * @param sharedState shared LoginModule state. * * @param options options specified in the login configurationc for FileLoginModule. *

    Folowing options can be set: *

      *
    • usersFile - Full path of the file containing user list *
    • groupsFile - Full path of the file containing group list *
    • debug - can be set to "true" to set debug on. Default is false. *
    */ public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { this.subject = subject; this.callbackHandler = callbackHandler; this.sharedState = sharedState; this.options = options; // initialize any configured options debug = "true".equalsIgnoreCase((String) options.get("debug")); usersFile = (String) options.get("usersFile"); groupsFile = (String) options.get("groupsFile"); } /** * Retrieves username and password by calling methods on callback handler * and then authenticates the user. * * @return true if suer exists in the user registry and password matches. * * @exception FailedLoginException if the authentication fails. * * @exception LoginException if this LoginModule is unable to perform the authentication. */ public boolean login() throws LoginException { final String methodLogName = classLogName + "[login] "; if (debug) { System.out.println(methodLogName + " method called"); } // retrieve user id & password by calling methods on callbackHandler. if (callbackHandler == null) throw new LoginException("Error: no CallbackHandler available"); Callback[] callbacks = new Callback[2]; callbacks[0] = new NameCallback("user name: "); callbacks[1] = new PasswordCallback("password: ", false); try { callbackHandler.handle(callbacks); username = ((NameCallback) callbacks[0]).getName(); char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword(); if (debug) { System.out.println( methodLogName + "Input from caller: user name: " + username + ", password: " + (tmpPassword == null ? "" : "XXXXXX")); } if (tmpPassword == null) { // treat a NULL password as an empty password tmpPassword = new char[0]; } password = new char[tmpPassword.length]; System.arraycopy(tmpPassword, 0, password, 0, tmpPassword.length); ((PasswordCallback) callbacks[1]).clearPassword(); } catch (java.io.IOException ioe) { throw new LoginException(ioe.toString()); } catch (UnsupportedCallbackException uce) { throw new LoginException( "Error: " + uce.getCallback().toString() + " not available to garner authentication information " + "from the user"); } try { authenticateUser(username, password); if (debug) { System.out.println(methodLogName + "login successful"); } loginSucceeded = true; } catch (FailedLoginException e) { // authentication failed -- clean out state loginSucceeded = false; username = null; for (int i = 0; i < password.length; i++) password[i] = ' '; password = null; throw e; } //if we reach here, authention was successful. return loginSucceeded; } /** * Authenticates username/password against the user name list in the file. * @param username * @param password */ private void authenticateUser(String username, char[] password) throws FailedLoginException { final String methodLogName = classLogName + "[authenticateUser] "; if (debug) { System.out.println(methodLogName + " method called"); } String s = null; BufferedReader in = null; String inPasswd = new String(password); boolean authenticated = false; if (debug) { System.out.println(methodLogName + "authenticating user " + username); } try { in = fileOpen(usersFile); while ((s = in.readLine()) != null) { if (!(s.startsWith("#") || s.trim().length() <= 0)) { int index = s.indexOf(":"); int index1 = s.indexOf(":", index + 1); if (debug) { System.out.println(methodLogName + "user from registry " + s.substring(0, index)); } //check if the userSecurityName:passwd combination exists if (s.substring(0, index).equals(username)) { //user found if (s.substring(index + 1, index1).equals(inPasswd)) { // Authentication successful authenticated = true; } else { throw new FailedLoginException("Password does not match for user " + username); } break; } } } } catch (Exception ex) { ex.printStackTrace(System.err); throw new FailedLoginException(ex.getMessage()); } finally { fileClose(in); } if (!authenticated) { throw new FailedLoginException("User name " + username + " not found"); } } /** * <p> This method is called if the LoginContext's overall authentication succeeded * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules succeeded). * *

    If this LoginModule's own authentication attempt succeeded (checked by retrieving * the private state saved by the login method), then this method associates a * SampleAuthPrincipal with the Subject located in the LoginModule. * If this LoginModule's own authentication attempted failed, then this method removes * any state that was originally saved. * * @exception LoginException if the commit fails. * * @return true if this LoginModule's own login and commit attempts succeeded, or false otherwise. */ public boolean commit() throws LoginException { final String methodLogName = classLogName + "[commit] "; if (debug) { System.out.println(methodLogName + "method called"); } if (!loginSucceeded) { if (debug) { System.out.println(methodLogName + "login did not succeed, returning false"); } return false; } else { // add a Principal (authenticated identity) to the Subject userPrincipal = new SampleAuthPrincipal(username); if (!subject.getPrincipals().contains(userPrincipal)) { subject.getPrincipals().add(userPrincipal); } //Add the group in the subject if (!subject.getPrincipals().contains(userGroup)) { subject.getPrincipals().add(userGroup); } if (debug) { System.out.println(methodLogName + "added SampleServiceAuthPrincipal to Subject"); } // in any case, clean out state username = null; for (int i = 0; i < password.length; i++) password[i] = ' '; password = null; commitSucceeded = true; if (debug) { System.out.println(methodLogName + "commit successful"); } return commitSucceeded; } } /** *

    This method is called if the LoginContext's overall authentication failed. * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules did not succeed). * *

    If this LoginModule's own authentication attempt succeeded (checked by retrieving * the private state saved by the login and commit methods), then this method cleans up * any state that was originally saved. * *

    * * @exception LoginException if the abort fails. * * @return false if this LoginModule's own login and/or commit attempts failed, and true otherwise. */ public boolean abort() throws LoginException { final String methodLogName = classLogName + "[abort] "; if (debug) { System.out.println(methodLogName + "method called"); } if (!loginSucceeded) { if (debug) { System.out.println(methodLogName + "login did not succeed, retruning false"); } return false; } else if (!commitSucceeded) { //login succeeded but overall authentication failed if (debug) { System.out.println(methodLogName + "login succeeded, but commit failed, clearing state"); } loginSucceeded = false; username = null; if (password != null) { for (int i = 0; i < password.length; i++) password[i] = ' '; password = null; } userPrincipal = null; userGroup = null; roles = null; } else { // overall authentication succeeded and commit succeeded, // but someone else's commit failed if (debug) { System.out.println(methodLogName + "login and commit succeeded, calling logout()"); } logout(); } return true; } /** * Logout the user. * *

    This method removes the SampleAuthPrincipal that was added by the commit method. * *

    * * @exception LoginException if the logout fails. * * @return true in all cases since this LoginModule should not be ignored. */ public boolean logout() throws LoginException { final String methodLogName = classLogName + "[logout] "; if (debug) { System.out.println(methodLogName + "method called, clearing all state"); } subject.getPrincipals().remove(userPrincipal); loginSucceeded = false; commitSucceeded = false; username = null; if (password != null) { for (int i = 0; i < password.length; i++) password[i] = ' '; password = null; } userPrincipal = null; userGroup = null; roles = null; return true; } // private methods private BufferedReader fileOpen(String fileName) throws FileNotFoundException { try { return new BufferedReader(new FileReader(fileName)); } catch (FileNotFoundException e) { throw e; } } private void fileClose(BufferedReader in) { try { if (in != null) in.close(); } catch (Exception e) { System.out.println("Error closing file" + e); } } } Here is my code in service impl class trying to retrieve user principal: public class SomeOperations implements ServiceLifecycle { protected ServletEndpointContext serviceEndPointContext; protected Principal securityPrincipal; public void init(Object context) throws ServiceException { serviceEndPointContext = (ServletEndpointContext) context; securityPrincipal = serviceEndPointContext.getUserPrincipal(); } public void destroy() { } public int addNumbers(int x, int y) { System.out.println("Executing add opetation"); if (securityPrincipal == null) { System.out.println("No security principal found in the context"); } else { System.out.println("User Name: " + securityPrincipal.getName()); } return x+y; } } Here is the output I get: SystemOut O Executing add opetation SystemOut O No security principal found in the context If I change the login module from my custom to Websphere inbuild WSLogin, I get proper Principal info within my service code. What is wrong with this code? Isn't the user principal getting propagated from the Login Module to the WebserviceContext? Please help.

  2. Re: JAAS Security in Websphere[ Go to top ]

    Hi CodePoet, Where you able to solve this issue? I am stuck exactly at the same place. I want my custom principal to be returned in my servlet code, but when I do request.getUserPrincipal(), I get the default implementation from websphere. As a result, my instanceof check is failing. How do I get my custom principal to be returned? I will really appreciate any help. I replied to a similar thread of yours on another forum, but not sure if you got the reply over there. This seems like a fairly recent post, so I thought of trying here :-) Regards.