You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Ken Johanson <to...@kensystem.com> on 2006/01/19 03:34:53 UTC

Calling Realm.authenticate() doesn't register Principal in with the Session??

Hi all,

I am able to access the current context's org.apache.catalina.Realm 
object using Yoav Shapira's Tomcat-Realm example; however, when I call 
Realm.authenticate(String user, String pass), the Principal object that 
it returns is not being registered with the session..

In other words, subsequent requests (inside the same webapp / context 
that I'm calling invoking Realm.authenticate from) just return null for 
getRemoteUser() and getPrincipal()...

Shouldn't authenticate() register the Principal with the Session 
automatically? Or do I need to call register() in interface Authenticator?

Thank,
ken



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Calling Realm.authenticate() doesn't register Principal in with the Session??

Posted by Ken Johanson <to...@kensystem.com>.
I'm trying to re-word these two concepts in a more elegant way:

1) I'm looking for a way to use form based authentication - but unlike 
with the current form login Realm, I need a way to intercept the persons 
email address(s) (typed into the username field), so that I can convert 
that into its corresponding username *before* passing it to the Realm 
(this cannot be done with the current form based login).

For this method, I would *prefer* not to write an override to any 
existing Realm (Form or WWW-Authenticate) - because users may already 
have their own. In other words, I would like to be able to call into 
whatever Realm the user already has configured (provided it's a 
user/pass one).

2) As an alternative, being able to simply register a given username 
(void doLogin(Principal p)) with a session via the server API would also 
be very useful - one could perform their own password or X509 validation 
inside of a servlet/jsp (using rules that are much more strict than what 
the current impls support, e.g trust levels/rules for issuers, and 
revocation checks, and critical subject flags for x509 certs). One could 
also implement the simplest possible (yet highly customizable) login 
logic against say, a database:

ResultSet rs = ps.exec("SELECT pass FROM auth WHERE user = ?"
	,request.getParameter("user"));
if (Digest.sha1(request.getParameter("pass"))
	.equals(rs.getString("pwdSha"))
)
  Tomcat5.doLogin(session, new Principal(request.getParameter("user"));


I hope that these two (very different) concepts will be tantalizing 
enough that some highly simplified auth APIs/concepts will make their 
way into the server. I have tried to build the first one - but the 
protected request/response fields in CoyoteRequestFacade cannot be 
accessed from a external class, and reflection would be needed to 
cast/call the method. An 'expert' will do much better than I.

class Tomcat5:

public static boolean tryLogin(HttpServletRequest request, 
HttpServletRequest response, String user, String pass)
   throws Exception
{
   Server server = ServerFactory.getServer();
   Service service = server.findService("Catalina");
   if (service==null)
     throw new NullPointerException("login: Cannot load Service 
'Catalina'");
   Engine engine = (Engine) service.getContainer();
   if (engine==null)
     throw new NullPointerException("login: Cannot load Container for 
Service 'Catalina'");

   Host host = null;
   String hostname = Strings.norm(request.getHeader("Host"));
   Object[] o = engine.findChildren();
   for (int i=0; i<o.length; i++)
   {
     if (!(o[i] instanceof Host))
       continue;
     Host h = (Host)o[i];
     String[] list = h.findAliases();
     for (int j=0; j<list.length; j++)
       if (hostname.equalsIgnoreCase(list[j]))
       {
         host = h;
         break;
       }
   }
   if (host==null)
     throw new NullPointerException("login: Cannot load Host 
'"+hostname+"'");
   String reqbase  = Strings.norm(req.getContextPath())+"/";
   Context context = (Context) host.findChild(reqbase);
   if (context==null)
   {
     context = (Context) host.findChild(Strings.clip(reqbase,-1));
   }
   if (context==null)
     throw new NullPointerException("login: Cannot load Context 
'"+reqbase+"'");
   Manager manager = context.getManager();
   HttpSession hses = request.getSession(true);
   Session session = null;
   try {
     session = manager.findSession(hses.getId());
   } catch (IOException e) {}
   if (session==null)
     throw new NullPointerException("login: Cannot load Session 
'"+reqbase+"'");
   Realm realm = context.getRealm();
   LoginConfig config = context.getLoginConfig();
   FormAuthenticator auth = null;
   Pipeline pipe = context.getPipeline();
   Valve[] v = pipe.getValves();
   for (int i=0; i<v.length; i++)
   {
     if (v[i] instanceof Authenticator)
     {
       auth = (FormAuthenticator)v[i];
       //if (true)throw new NullPointerException(o[i].toString());
       break;
     }
   }
   if (auth==null)
     throw new NullPointerException("login: Cannot load Authenticator 
'"+reqbase+"'");
   Principal principal = realm.authenticate(user, pass);
   if (principal==null)
     return false;
   session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal);
   session.setNote(Constants.SESS_USERNAME_NOTE, user);
   session.setNote(Constants.SESS_PASSWORD_NOTE, pass);
   if (true) throw new 
NullPointerException(request.getClass().toString()+" 
"+response.getClass().toString());
   auth.authenticate(((CoyoteRequestFacade)request).request, 
((CoyoteResponseFacade)response).response, config);
   return true;
}



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Calling Realm.authenticate() doesn't register Principal in with the Session??

Posted by Ken Johanson <to...@kensystem.com>.
Mark Thomas wrote:
> Ken Johanson wrote:
> 
>> Mark, are you saying that you agree, or disagree, with the usefulness of
>> the idea?
> I am -0 to the idea as a whole. I don't see the point but am happy to
> proivde pointers where I can.
> 
> Mark
> 

Okay - do you have any pointers for this need?: (please forgive me for 
possibly repeating what may have been mentioned earlier)

-A third party API (that I'm writing, just as could anyone else) must be 
'dropped in' to any recent Tomcat version; it must allow users of the 
API to authenticate (using only username and passwd) against whatever 
existing realm they have configured, without ANY changes to that realm's 
config or impl. This INSURES that any existing authentication code 
(form, jdbc) continues to work.

-OR- if there is a way already without using the third party API, what 
is it? Say, something along the lines of setting request-context 
attributes, or beans props (beans being less ideal)..

-Finally, the solution (existing or new) MUST allow code within a 
servlet, jsp, bean, or POJO, etc to pass ONLY a username + password, or 
alternatively only an X509Certificate, into some class who will simply 
return a true|false, or throw an exception on authentication failure.

Hence, the idea allows more flexibility when additional layers are 
REQUIRED atop the authentication pre-processing. An example, would be to 
perform a database lookup of an email address(s) (entered into a login 
form's username field) and translate it into a Principal, is then passed 
into the webapp's preconfigured Realm.

Ken



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Calling Realm.authenticate() doesn't register Principal in with the Session??

Posted by Mark Thomas <ma...@apache.org>.
Ken Johanson wrote:

> Mark, are you saying that you agree, or disagree, with the usefulness of
> the idea?
I am -0 to the idea as a whole. I don't see the point but am happy to
proivde pointers where I can.

Mark


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Calling Realm.authenticate() doesn't register Principal in with the Session??

Posted by Ken Johanson <to...@kensystem.com>.
Mark Thomas wrote:
> 
> Given users are going to have to modify their app to use this library,
> not modifying the associated context.xml looks to be a nice to have
> requirement that is making things more difficult. Removing this
> requirement opens up a number of alternative implementation options
> including custom realms.
> 
> Mark
> 

Mark, are you saying that you agree, or disagree, with the usefulness of 
the idea?

Your point about 'users have to modify their app' is true, but a one 
time requirement, and thereafter their app will be compatible with 
whatever underlying realm impl is used, which I find enticing. Currently 
there is no mechanism (that I can see) to programtically perform login - 
say from an html form - this 'new' proposed method fills that. And by 
the same token, a user would already have to modify their app (to use a 
custom POST url or form names or redirect), with the built-in form based 
login (or subclass of it's impl), so that doesn't seem to be a drawback.

Sorry to be redundant of you're already agreeing with the idea.

Ken



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Calling Realm.authenticate() doesn't register Principal in with the Session??

Posted by Mark Thomas <ma...@apache.org>.
Ken Johanson wrote:
> ...
> 
>>> I'm trying to write a facade API that will call into whatever
>>> Realm/Authenticator that the user already has configured (though an
>>> abstract/overridden method)... the idea being that no changes to the
>>> user's existing auth config or modules are required, nor that the user
>>> should need to change out any custom realm/authenticator that they may
>>> have written, for mine. So the solution needs to transparently call into
>>> some existing method(s) in the 'Base' classes or interface impls..
>>
>> To do what? What user requirement are you trying to meet? Technically
>> I understand what you are trying to do but not the fundamental why.
>> Knowing your ultimate aim may enable people on this list to suggest an
>> alternative approach.
>>
>> Mark
>>
> 
> The intent is that a simple library can be deployed into the (at
> server/lib or shared/lib), and from any webapp, calling into that
> wrapper class will allow the app to authenticate and register the user..
> irregardless of what specific authenticate/realm modules are being used.
> 
> A very simple example, is that I would like for users to login on a html
> form, by entering not just their username - but maybe their email
> address (any number of them), or pub key (to be hypothetical)... then
> its it will be up to the webapp to search a database beforehand, to
> lookup the email address or pub key, and get the userid, then pass it to
> the auth module if, say, the account is current, the password age isn't
> expired, etc.
> 
> All completely independent of what Realm/Authent. is config'd for any
> webapp. Only the username and password (and which webapp as implied by
> the context path contained in Request).: static boolean
> Tomcat5.authenticate(request, response, user, pass);
> 
> Creating and deploying my own version of this class is not feasible,
> because :
> 
> -users should have the option to write the account validation logic in JSP
> 
> -Users may already have a custom impl, and should not have to extend or
> implement or compile anything in that impl. to support this lib. Be it
> their own impl or their choice-use of tomcat JDBC realm.
> 
> Thanks,
> Ken

Given users are going to have to modify their app to use this library,
not modifying the associated context.xml looks to be a nice to have
requirement that is making things more difficult. Removing this
requirement opens up a number of alternative implementation options
including custom realms.

Mark


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Calling Realm.authenticate() doesn't register Principal in with the Session??

Posted by Ken Johanson <to...@kensystem.com>.
...

>> I'm trying to write a facade API that will call into whatever
>> Realm/Authenticator that the user already has configured (though an
>> abstract/overridden method)... the idea being that no changes to the
>> user's existing auth config or modules are required, nor that the user
>> should need to change out any custom realm/authenticator that they may
>> have written, for mine. So the solution needs to transparently call into
>> some existing method(s) in the 'Base' classes or interface impls..
> To do what? What user requirement are you trying to meet? Technically
> I understand what you are trying to do but not the fundamental why.
> Knowing your ultimate aim may enable people on this list to suggest an
> alternative approach.
> 
> Mark
> 

The intent is that a simple library can be deployed into the (at 
server/lib or shared/lib), and from any webapp, calling into that 
wrapper class will allow the app to authenticate and register the user.. 
irregardless of what specific authenticate/realm modules are being used.

A very simple example, is that I would like for users to login on a html 
form, by entering not just their username - but maybe their email 
address (any number of them), or pub key (to be hypothetical)... then 
its it will be up to the webapp to search a database beforehand, to 
lookup the email address or pub key, and get the userid, then pass it to 
the auth module if, say, the account is current, the password age isn't 
expired, etc.

All completely independent of what Realm/Authent. is config'd for any 
webapp. Only the username and password (and which webapp as implied by 
the context path contained in Request).: static boolean 
Tomcat5.authenticate(request, response, user, pass);

Creating and deploying my own version of this class is not feasible, 
because :

-users should have the option to write the account validation logic in JSP

-Users may already have a custom impl, and should not have to extend or 
implement or compile anything in that impl. to support this lib. Be it 
their own impl or their choice-use of tomcat JDBC realm.

Thanks,
Ken



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Calling Realm.authenticate() doesn't register Principal in with the Session??

Posted by Mark Thomas <ma...@apache.org>.
Ken Johanson wrote:
> Mark Thomas wrote:
>> Ken Johanson wrote:
>>> I am able to access the current context's org.apache.catalina.Realm
>>> object using Yoav Shapira's Tomcat-Realm example; however, when I call
>>> Realm.authenticate(String user, String pass), the Principal object that
>>> it returns is not being registered with the session..
<snip>
>>> Shouldn't authenticate() register the Principal with the Session
>>> automatically? Or do I need to call register() in interface
>>> Authenticator?
You would need to find a way to call register()

>> What are you trying to do? From the amount of access you seem to need
>> to Tomcat internals, you might be better off just writing a custom
>> realm and/or authenticator.
>>
>> Mark
>>
>>
> 
> Mark,
> 
> I'm trying to write a facade API that will call into whatever
> Realm/Authenticator that the user already has configured (though an
> abstract/overridden method)... the idea being that no changes to the
> user's existing auth config or modules are required, nor that the user
> should need to change out any custom realm/authenticator that they may
> have written, for mine. So the solution needs to transparently call into
> some existing method(s) in the 'Base' classes or interface impls..
To do what? What user requirement are you trying to meet? Technically
I understand what you are trying to do but not the fundamental why.
Knowing your ultimate aim may enable people on this list to suggest an
alternative approach.

Mark


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Calling Realm.authenticate() doesn't register Principal in with the Session??

Posted by Ken Johanson <to...@kensystem.com>.
Mark Thomas wrote:
> Ken Johanson wrote:
>> Hi all,
>>
>> I am able to access the current context's org.apache.catalina.Realm
>> object using Yoav Shapira's Tomcat-Realm example; however, when I call
>> Realm.authenticate(String user, String pass), the Principal object that
>> it returns is not being registered with the session..
>>
>> In other words, subsequent requests (inside the same webapp / context
>> that I'm calling invoking Realm.authenticate from) just return null for
>> getRemoteUser() and getPrincipal()...
>>
>> Shouldn't authenticate() register the Principal with the Session
>> automatically? Or do I need to call register() in interface Authenticator?
>>
>> Thank,
>> ken
> What are you trying to do? From the amount of access you seem to need
> to Tomcat internals, you might be better off just writing a custom
> realm and/or authenticator.
> 
> Mark
> 
> 

Mark,

I'm trying to write a facade API that will call into whatever 
Realm/Authenticator that the user already has configured (though an 
abstract/overridden method)... the idea being that no changes to the 
user's existing auth config or modules are required, nor that the user 
should need to change out any custom realm/authenticator that they may 
have written, for mine. So the solution needs to transparently call into 
some existing method(s) in the 'Base' classes or interface impls..

This would be exposed in something like: static boolean 
Tomcat5.authenticate(request, response, user, pass); (Or an X509 chain)

Hope this makes sense,

ken




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org


Re: Calling Realm.authenticate() doesn't register Principal in with the Session??

Posted by Mark Thomas <ma...@apache.org>.
Ken Johanson wrote:
> Hi all,
> 
> I am able to access the current context's org.apache.catalina.Realm
> object using Yoav Shapira's Tomcat-Realm example; however, when I call
> Realm.authenticate(String user, String pass), the Principal object that
> it returns is not being registered with the session..
> 
> In other words, subsequent requests (inside the same webapp / context
> that I'm calling invoking Realm.authenticate from) just return null for
> getRemoteUser() and getPrincipal()...
> 
> Shouldn't authenticate() register the Principal with the Session
> automatically? Or do I need to call register() in interface Authenticator?
> 
> Thank,
> ken
What are you trying to do? From the amount of access you seem to need
to Tomcat internals, you might be better off just writing a custom
realm and/or authenticator.

Mark


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org