users@glassfish.java.net

Re: Login not "standard"

From: Kumar Jayanti <Vbkumar.Jayanti_at_Sun.COM>
Date: Thu, 20 Aug 2009 17:46:29 +0530

Per Steffensen wrote:
> Hi
>
> Using Glassfish v2.1
>
> I want to do a programmatic login on the server-side.
JavaEE6 introduces a login() and authenticate() methods on the
HttpServletRequest which would obviate the need for programmatic login
atleast for within web applications.

>
> --------------- Questions/comments
> ----------------------------------------------
> I will start with my questions/comments (not to have them i the
> bottom, where no one sees them :-) ).
> 1) Why is Glassfish not made, so that it is possible to make
> programmatic login the standard way?
You may be in a J2SE environment and invoking a remote secure EJB, in
such cases you do need some API. And it is best if the same API is
usable elsewhere rather than having different API's for different places.
> 2) Why does Glassfish invent a SecurityContext class to to hold the
> current Subject, when that is supposed to be set by Subject.doAs
 From what i remember talking to our architect, there is a performance
impact in trying to access the Subject from the AccessControlContext,
especially when the SecurityManager is ON. This overhead is circumvented
by the use of SecurityContext.
> 3) Glassfish, beeing the standard implementation, should implement
> standard ways of doing things.
>
> The rest of the mail will explain details, to make my
> questions/comments qualified.
>
> ---------------- I have to do like this in Glassfish
> ------------------------------
> I have found out that programmatic login will work (at least when I
> use FileRealm and FileLoginModule) when I do like this:
>
> login(username, password);
> <call my business-login on secured EJBs>
>
> where the login method looks something like this:
>
> public static void login(String username, String password) throws
> LoginException
> {
> try {
> Subject sub = new Subject();
> sub.getPrivateCredentials().add(new new
> com.sun.enterprise.security.auth.login.PasswordCredential(username,
> password,
> com.sun.enterprise.security.auth.realm.Realm.getDefaultRealm()));
> LoginContext lc = new LoginContext("fileRealm", sub);
> lc.login();
> com.sun.enterprise.security.SecurityContext securityContext
> = new com.sun.enterprise.security.SecurityContext(username,
> lc.getSubject(),
> com.sun.enterprise.security.auth.realm.Realm.getDefaultRealm());
>
> com.sun.enterprise.security.SecurityContext.setCurrent(securityContext);
> } catch (Exception e) {
> // do something
> }
> }
>
> I know that I could simplify my login method by using the
> ProgrammaticLogin class, but it will not change the existence of the
> problems mentioned below.
>
But you are better off using ProgrammaticLogin here because it is an
exposed/supported Proprietary API whereas the code you have above might
change.
> ------------------ Problems ------------------------------
> This way of doing programmatic login is really non-standard. Glassfish
> as the reference implementation should be working the standard way, I
> think. My login-code should be able to be used (without changes) if I
> choose to move to another Java EE server.
> Problems:
> - I have to use alot of Glassfish-specific classes
> (com.sun.enterprise.security.auth.login.PasswordCredential,
> com.sun.enterprise.security.SecurityContext and
> com.sun.enterprise.security.auth.realm.Realm)
> - You do not even have to use Subject.doAs
> - My login code will not work on any other Java EE server.
>
> ---------------- The way I should be able to do it
> ---------------------------------
> I should be able to do it the "right" (compatible) way on the
> Glassfish server:
>
> LoginContext lc = login(username, password);
> Subject.doAs(lc.getSubject(), <call my business-login on secured EJBs
> packed in a PrivilegedAction>);
>
Can you be sure that doing it this way will work on all other JavaEE
Server's (yes doing it this way you are atleast using standard Java SE
API's but that does not guarantee that all JavaEE server's will work
when used this way, though i agree it would be ideal if they did).

regards,
kumar

> Where the login method looks something like this:
>
> public static LoginContext login(String username, String password)
> throws LoginException
> {
> try {
> LoginContext lc = new LoginContext("fileRealm", new
> UserPasswordCallbackHandler(username, password));
> lc.login();
> return lc;
> } catch (Exception e) {
> // do something
> }
> }
>
> Where UserPasswordCallbackHandler looks something like this:
>
> public class UserPasswordCallbackHandler implements CallbackHandler {
>
> private String username;
> private String password;
> public UserPasswordCallbackHandler(String username, String
> password) {
> super();
> this.username = username;
> this.password = password;
> }
>
> public void handle(Callback[] callbacks) throws IOException,
> UnsupportedCallbackException {
> for (int i = 0; i < callbacks.length; i++) {
> if (callbacks[i] instanceof TextOutputCallback) {
> // display the message according to the specified type
> TextOutputCallback toc = (TextOutputCallback)
> callbacks[i];
> switch (toc.getMessageType()) {
> case TextOutputCallback.INFORMATION:
> GeneralManager.log(toc.getMessage(), LogLevel.INFO);
> break;
> case TextOutputCallback.ERROR:
> GeneralManager.log(toc.getMessage(), LogLevel.ERROR);
> break;
> case TextOutputCallback.WARNING:
> GeneralManager.log(toc.getMessage(),
> LogLevel.WARNING);
> break;
> default:
> throw new IOException("Unsupported message type: "
> + toc.getMessageType());
> }
> } else if (callbacks[i] instanceof NameCallback) {
> // prompt the user for a username
> NameCallback nc = (NameCallback) callbacks[i];
>
> // ignore the provided defaultName
> // System.err.print(nc.getPrompt());
> // System.err.flush();
>
> nc.setName(username);
> } else if (callbacks[i] instanceof PasswordCallback) {
> // prompt the user for sensitive information
> PasswordCallback pc = (PasswordCallback) callbacks[i];
> //System.err.print(pc.getPrompt());
> //System.err.flush();
> pc.setPassword(password.toCharArray());
> } else {
> throw new UnsupportedCallbackException(callbacks[i],
> "Unrecognized Callback");
> }
> }
> }
> }
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: users-help_at_glassfish.dev.java.net
>
>