User Authentication

Visto 339 veces
Saltar al primer mensaje no leído

Nicholas

no leída,
13 feb 2008, 10:49:1413/2/08
a Google Web Toolkit
I'm trying to build session-based user authentication into my app. I
added a user session check to each of my RPC service methods. It
throws an exception "ExpiredSessionException" if a user makes an RPC
call without being logged in (or after session expires).

On my client side whenever I do an RPC call and get that exception I
show a login dialog. After the user logs in successfully they can
redo their request (clicking a button / link etc).

What I would rather do is have the system automatically reissue their
request after successful login. Any suggestions on how I could
implement that? Here's how it looks right now...

In my ServiceImpl class, I have methods such as:

public ResultList findAllCustomers(int pageNum, int pageSize, String
orderByField)
throws InvalidSessionException {
authenticateUser();
TechShopDB db = new TechShopDB();
return db.findAllCustomers(pageNum, pageSize, orderByField);
}

The authenticateUser() method:

private void authenticateUser() throws InvalidSessionException {
if (!isSessionAlive()) {
throw new InvalidSessionException("User session is
invalidated, user must login.");
}
}

On the client side, when I want to query for that list:
... happens within an onclick ...
try {
TechShopEntryPoint.getCustomerService().findAllCustomers(
currentPage, PAGE_SIZE, null, gotCustomerList);
} catch(InvalidSessionException ex) {
new LoginDialogBox().center();
}

So user clicks on the link, executes the RPC call which throws an
exception the first time prompting user to login, then user has to
click the link again and the RPC call returns correctly.

Any thoughts on how I should re-work this?

Nick

Jason Essington

no leída,
13 feb 2008, 13:19:0413/2/08
a Google-We...@googlegroups.com
I do something exactly as you want ...

I have an abstract Callback that handles the authentication exceptions by showing the login dialog and issuing a login request ...

The tricky part is that all of my other RPCs need to extend this abstract AsyncCallback, as well as implement Command

the Callbacks must have an execute() method that can fire off the RPC request.

so, to perform an RPC I do something like:

new MyServiceCallback(some, params, required, by, the, rpc).execute();

The abstract ApplicationCallback that MyServiceCallback extends can handle AuthenticationExceptions in its onFailure() method by creating a new request to authenticate, then this new authentication callback's onSuccess() simply calls execute() on the original instance of MyServiceCallback to reissue the original request that failed.

an example Callback would look something like:

public class AccountCallback extends ApplicationCallback{

   HasAccounts reportPanel;

   

   public AccountCallback(HasAccounts reportPanel){
      this.reportPanel = reportPanel;
   }

   

   protected void onSuccessSub(Object result){
      if (result != null)
      {
         reportPanel.setAccounts((List) result);
      }
   }

   public void execute(){
      BalanceReportServiceAsync.impl.getAccounts(this);
   }
}

once everything is setup, it is pretty simple to handle.

There is a more in-depth discussion of this technique here:

Also, you can find me in the GWT IRC channel (##gwt on freenode) for a more synchronous discussion.


-jason

Nicholas

no leída,
2 mar 2008, 21:29:442/3/08
a Google Web Toolkit
From the discussion you linked to:

> If there is a problem, I throw an
> AuthenticationException. On the client my AsyncCallback catches the
> exception

What does the code for this look like? If your server side method is
declared to throw an AuthenticationException then would you have to do
a try/catch inside your execute method when you try to call it?

Nick




On Feb 13, 12:19 pm, Jason Essington <jason.essing...@gmail.com>
wrote:
> There is a more in-depth discussion of this technique here:http://groups.google.com/group/Google-Web-Toolkit/browse_thread/threa...

Arthur Lance

no leída,
3 mar 2008, 8:14:513/3/08
a Google-We...@googlegroups.com
 
You asked for an example of implementing AuthenticationException
Here it is:
 
try
{
//depending on what kind of authentication you are calling.
//The example below uses a hashtable that is loaded up with all authentication credentials
 
DirContext authContext =
new InitialDirContext(Env);

System.out.println(

"You are authenticated.");

authContext.close();

return true;

}

catch (AuthenticationException ae) {

System.out.println(

"Authentication failed!");

}

Jason Essington

no leída,
3 mar 2008, 12:49:353/3/08
a Google-We...@googlegroups.com
The authentication exception is handled in the onFailure() method of
the AsynchronousCallback ... as is any declared SerializableException
which is thrown on the server.

-jason

Nicholas

no leída,
3 mar 2008, 23:24:273/3/08
a Google Web Toolkit
So I have ApplicationCallback which looks like this:

public abstract class ApplicationCallback implements AsyncCallback,
Command {

public void onFailure(Throwable caught) {
onFailureBefore(caught);

if (caught instanceof AuthenticationException) {
LoginDialog.getLoginDialog(caught.getMessage(), this);
}

onFailureAfter(caught);
}

protected void onSuccessAfter(Object result) {
}

protected void onFailureBefore(Throwable caught) {
}

protected void onFailureAfter(Throwable caught) {
}

public void onSuccess(Object result) {
onSuccessAfter(result);
}

}



Then I have in my RPC impl class, a method such as:

public Customer findCustomerById(Long customerId) throws
AuthenticationException {
authenticateUser(); // this throws AuthenticationException if
user is not logged in or session has timed out.
Customer customer = db.findCustomerById(customerId);
return customer;
}

But since that's declared to throw an exception, when I try to call it
from the client side I have to call it with a try/catch, so in my
execute method I end up with:

public void execute() {
try {

TechShopEntryPoint.getCustomerService().customerStar(c.getId().longValue(),
c.getStarred().booleanValue(), this);
} catch (AuthenticationException ex) {
LoginDialog.getLoginDialog(ex.getMessage(), this);
}
}

What am I missing - I don't think I should have to wrap all my service
calls in a try / catch. That's duplicating the job of the onFailure
method?

Erle-Mantos

no leída,
4 mar 2008, 0:15:154/3/08
a Google Web Toolkit
Hmmm .. looks like my problem. I did have a "hacked" solution for it
though.

The real solution would have been to be able to throw unexpected
exceptions
(a checked exception not declared in the serviceMethod's signature) as
the Throwable in
onFailure(...). Sadly, I have not been able to do that. If anybody
knows, do tell.

Generally, I like security to be non-intrusive and this case, I don't
like to write my
method to throw an authentication exception, otherwise, every method
that needs to be
authenticated would have the "throw AuthenticationException" which is
quite tedious
and you have to write the "authentication checking code" in the method
itself, another tedious job.

My solution for this is to extend the RemoteServiceServlet, so it can
examine every RPC method
call and check if the user's role that you saved in the session has
authority to execute it, and if it has,
continue the execution, but if not, halt the execution and throw the
authentication exception.

The method to override in RemoteServiceServlet to be able to do that
is

public String processCall( String payload ) throws
SerializationException

which does the decoding of the rpc request and turns it into a Method
to be executed. From
there, you can intercept the rpc call and do the appropriate action
( to continue it or throw the
authentication exception ). The problem though is that if you throw an
unexpected exception
(a checked exception not declared in the serviceMethod's signature),
it doesn't reach the client
(maybe it can, I just don't know how.). So, the next thing to override
is

protected void doUnexpectedFailure(Throwable e)

which handles any unexpected exception, and throw a customized failure
message with enough
information as to be able to recreate the exception in the client.
This failure message will reach your
client via the "InvocationException" passed to the onFailure(...) as
the Throwable. You can then
get the message from the InvocationException, try to recreate the
"authentication exception" based
on the message. Voila, you have passed your "authentication exception"
to the client non-intrusively.

Of course, your service implementations would need to extend your
customized servlet, not the
RemoteServiceServlet.

When that exception reaches the client, it is then trivial to
implement an asynccallback that calls
the login dialog, and if it authenticates, execute the onSuccess()
part of it.

Maybe I'll write a blog about this detailing the actual solution.

BarefootSanders

no leída,
20 mar 2008, 15:47:2220/3/08
a Google Web Toolkit
That looks like it would work to me but like I said im new to gwt.
Could you post a small example of what you are talking about?

Thanks a lot!

Nicholas

no leída,
20 mar 2008, 16:05:3420/3/08
a Google Web Toolkit
I've got something working now, I'll try to clean up and post some
working code this weekend to demonstrate it.

Nick
> > > > >>> Nick- Hide quoted text -
>
> - Show quoted text -

BarefootSanders

no leída,
20 mar 2008, 16:18:4120/3/08
a Google Web Toolkit
Thanks!
> ...
>
> read more »

Nicholas

no leída,
25 mar 2008, 23:14:1225/3/08
a Google Web Toolkit
I've snipped out the relevant code and posted it, available at
http://nakedcoder.blogspot.com/2008/03/google-web-toolkit-user-authentication.html

If anything is confusing or missing let me know, been a long day :)

Nick
> ...
>
> read more »
Responder a todos
Responder al autor
Reenviar
0 mensajes nuevos