Login form auto-complete and GWT-RPC (or RequestBuilder), a solution!

2,446 views
Skip to first unread message

Thomas Broyer

unread,
Feb 26, 2009, 12:21:23 PM2/26/09
to Google Web Toolkit
If you want to have browsers auto-complete username/password in your
application's login form, you probably did (*I* did) this:
1. follow recommandations from http://code.google.com/p/google-web-toolkit-incubator/wiki/LoginSecurityFAQ,
i.e. your form and fields have to be in the original markup and you
mustn't use .submit() but let the browser submit using, say... a
submit button?
2. use something like that in your code:
// note the "true" second argument, to create a hidden iframe
FormPanel form = FormPanel.wrap(Document.get().getElementById
("login"), true);
form.addFormPanel(new FormPanel() {
public void onSubmit(FormSubmitEvent event) {
// do some validation before submitting (non-empty fields)
// and call event.setCancelled(true) if needed.
}
public void onSubmitComplete(FormSubmitCompleteEvent event) {
// somehow "parse" event.getResults() to know whether it
// succeeded or not.
}
});
3. Your server have to send its response in with Content-Type:text/
html, even if its JSON (hence the "parse" above)


But there's actually an alternative!

It never occured to me before someone pointed me to a login page that
does it: if your form submits to a javascript: URL, then the browser's
"auto-complete" feature will work (provided the form and fields were
in the original HTML page markup, same limitation as above).

What it means is that you can use GWT-RPC or RequestBuilder!!!

Your code now looks like:
private static native void injectLoginFunction() /*-{
$wnd.__gwt_login = @com.example.myapp.client.App::doLogin();
}-*/;

private static void doLogin() {
// get the fields values and do your GWT-RPC call or
// RequestBuilder thing here.
}
...
// notice that we now pass "false" as the second argument
FormPanel form = FormPanel.wrap(Document.get().getElementById
("login"), false);
form.setAction("javascript:__gwt_login()");

And of course, you can still validate the form before it's submitted:

form.addFormPanel(new FormPanel() {
public void onSubmit(FormSubmitEvent event) {
// do some validation before submitting (non-empty fields)
// and call event.setCancelled(true) if needed.
}
public void onSubmitComplete(FormSubmitCompleteEvent event) {
// will never be called.
}
});


Tested in IE7, Firefox 3.0 and Opera 10alpha; please update if it
works (or doesn't work) for you in other browsers.
The previous solution (using the iframe) was successfully tested in
IE6, IE7, IE8 (beta 1 at that time), Firefox 2 and 3.0, Opera (9.62 at
that time), Safari 3 for Windows and Google Chrome (1 and 2).

jrray

unread,
Apr 20, 2009, 10:21:43 PM4/20/09
to Google Web Toolkit
This is a useful technique, thanks. You didn't mention that
injectLoginFunction() needs to be called around the same time as
form.setAction(...).

This technique would be more convenient if "doLogin" wasn't a static
method.

I tried to change to non-static, such as:

private native void injectLoginFunction() /*-{
$wnd.__gwt_login = this.@com.example.myapp.client.App::doLogin
();
}-*/;

private void doLogin() {}

This causes a stack trace (GWT 1.6.4, hosted mode):

[java] Exception occurred in MethodDispatch.invoke:
[java] Exception in thread "main" java.lang.ClassCastException
[java] at java.lang.Class.cast(Class.java:2990)
[java] at com.google.gwt.dev.shell.JsValueGlue.get
(JsValueGlue.java:128)
[java] at com.google.gwt.dev.shell.moz.MethodDispatch.invoke
(MethodDispatch.java:70)
[java] at org.eclipse.swt.internal.gtk.OS._gtk_main_do_event
(Native Method)
[java] at org.eclipse.swt.internal.gtk.OS.gtk_main_do_event
(OS.java:5273)
[java] at org.eclipse.swt.widgets.Display.eventProc
(Display.java:1135)
[java] at
org.eclipse.swt.internal.gtk.OS._g_main_context_iteration(Native
Method)
[java] at
org.eclipse.swt.internal.gtk.OS.g_main_context_iteration(OS.java:1428)
[java] at org.eclipse.swt.widgets.Display.readAndDispatch
(Display.java:2840)
[java] at com.google.gwt.dev.SwtHostedModeBase.processEvents
(SwtHostedModeBase.java:235)
[java] at com.google.gwt.dev.HostedModeBase.pumpEventLoop
(HostedModeBase.java:558)
[java] at com.google.gwt.dev.HostedModeBase.run
(HostedModeBase.java:405)
[java] at com.google.gwt.dev.HostedMode.main(HostedMode.java:
232)


So I stuck with a static method.

When I tried to wrap a form element inside doLogin(), the wrap call
would silently fail and terminate the doLogin() function.

Example:

private static void doLogin() {
GWT.log("before", null);
TextBox.wrap(Document.get().getElementById("login_username"));
GWT.log("after", null);
}

The "before" is printed to the log, but the "after" is not. The
getElementById() succeeds, I tried printing that out before the wrap()
call and that works.

I opted to wrap all the elements beforehand into static fields of my
class. I also saved "this" to a static field so I can call back into
my instance from doLogin().

Hope this helps others trying to use this technique.

On Feb 26, 10:21 am, Thomas Broyer <t.bro...@gmail.com> wrote:
> If you want to have browsers auto-complete username/password in your
> application's login form, you probably did (*I* did) this:
> 1. follow recommandations fromhttp://code.google.com/p/google-web-toolkit-incubator/wiki/LoginSecur...,

Thomas Broyer

unread,
Apr 22, 2009, 10:17:07 PM4/22/09
to Google Web Toolkit


On 21 avr, 04:21, jrray <jrobert...@gmail.com> wrote:
>
> This technique would be more convenient if "doLogin" wasn't a static
> method.
>
> I tried to change to non-static, such as:
>
>    private native void injectLoginFunction() /*-{
>       $wnd.__gwt_login = th...@com.example.myapp.client.App::doLogin
> ();
>    }-*/;

var that = this;
$wnd.__gwt_login = function() {
that.@com.example.myapp.client.App::doLogin()();
}

or change the method's signature:
private native void injectLoginFunction(App that) /*-{
$wnd.__gwt_login = function() {
that.@com.example.myapp.client.App::doLogin()();
}
}-*/;
and call it like that:
injectLoginFunction(this);

That's "JSNI 101" ;-)

J Robert Ray

unread,
Apr 23, 2009, 4:21:47 PM4/23/09
to Google-We...@googlegroups.com
Thanks. I see now that this is discussed in the GWT FAQ and I
understand why my attempt at using "this" in a callback doesn't work.

Viliam Durina

unread,
Apr 27, 2010, 3:32:39 AM4/27/10
to Google-We...@googlegroups.com
There is even a simpler solution without using JSNI at all. Set the
form's action to just "javascript:;" and put the login logic to the
form's submitHandler:

FormPanel form =
FormPanel.wrap(Document.get().getElementById("login"), false);
form.setAction("javascript:;");

form.addFormPanel(new FormPanel() {
public void onSubmit(FormSubmitEvent event) {
// do some validation before submitting (non-empty fields)
// and call event.setCancelled(true) if needed.

// get the fields values and do your GWT-RPC call or
// RequestBuilder thing here.
}
public void onSubmitComplete(FormSubmitCompleteEvent event) {
// will never be called.
}
});

Tested in IE8, firefox 3.5 and chrome 4.1 and chrome 5 beta, works in
the first two, the last two don't offer to save the password.
Confirmed with Thomas Broyer that the original solution does not work
there either. Going to file a bug there.

Viliam

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

markww

unread,
May 5, 2010, 11:29:37 PM5/5/10
to Google Web Toolkit
What version of GWT are you using Viliam, form.addFormPanel() doesn't
seem to exist anymore?

markww

unread,
May 6, 2010, 10:45:47 AM5/6/10
to Google Web Toolkit
Actually, just confirming this, all the solutions presented here *do
not* work in webkit browsers (chrome, safari), right? Looks like it
works in firefox ok. I haven't found any alternative solutions in my
searches, so seems like our options are still:

1) Use methods presented here, but won't work in chrome or safari
2) Use standard login submit form (outside of gwt, but will work on
all browsers)

Thanks

Thomas Broyer

unread,
May 6, 2010, 11:49:33 AM5/6/10
to Google Web Toolkit


On May 6, 4:45 pm, markww <mar...@gmail.com> wrote:
> Actually, just confirming this, all the solutions presented here *do
> not* work in webkit browsers (chrome, safari), right? Looks like it
> works in firefox ok. I haven't found any alternative solutions in my
> searches, so seems like our options are still:
>
>   1) Use methods presented here, but won't work in chrome or safari
>   2) Use standard login submit form (outside of gwt, but will work on
> all browsers)

I'm using GWT-controlled auth (i.e. without "exiting" the app when
logging out) for more than 2 years now (initially sending the form to
the server, then using the above solution) and I must say that...

if you can, don't make the same mistake!

For all my new projects, I'm using a separate page for the login
screen adn the GWT app (which can safely assume it is authenticated),
just like Google does. Yes it means you could loose your work when
your session expires but it makes the development sooo much easier!
In our app where we still do this, the session automatically ends
after 30' of inactivity (calculated only based on requests to the
server, or rather, responses from the server). You're then showed the
login screen but you cannot change the username, your only option is
to give your password (much like a "session locked" screen, as in MS
Windows), or refresh the page. All your work is kept behind though, so
when you "unlock" the app, you didn't loose anything. Only when the
user explicitly logs out the login screen is shown with the ability to
log back in as any user (and switch locale, which reloads the page
with the appropriate GWT locale selected), and only in this case the
whole app (except the login screen) is blown out, and cached data is
cleared. This is really a PITA to maintain as there's always a risk
you forget clearing something out.
So let me reiterate:

if you can, don't make the same mistake!

Sripathi Krishnan

unread,
May 6, 2010, 12:30:08 PM5/6/10
to google-we...@googlegroups.com
+1 on that - if you can, don't make the same mistake!

We also put in some hacks to get the login page "GWT controlled". In retrospect, it was a poor decision. Its much cleaner to assume that the GWT page is only reachable once authenticated.

--Sri
P.S. And as luck would have it, as I typed this email, my gmail session timed out. I got a popup - "Your session has timedout". So, I was able to copy the draft, login again and then continue on this email. Not too bad for usability, I didn't loose my work.

markww

unread,
May 6, 2010, 1:03:30 PM5/6/10
to Google Web Toolkit
Thanks for the heads up, was just going down that route.

I'm fine with using a regular html form, just not sure where to put
it. Twitter has a login form on their main splash page, which is
ideal. I am thinking I could do the same. My main page is already a
jsp page. I can do something like:

// myproject.jsp
<form action="myproject.jsp">
... login text fields ...
</form>

<%
String login = request.getParameter("login");
String password = request.getParameter("password");
if (login and password exist and are correct) {
startSession();
showProtectedUserInfoEtc();
}
else {
showGeneralInfo();
}
%>

this could work, the form just re-posts itself back to my main project
page. The downside is that I have to add the login logic on the main
page which is kind of ugly, but I think this will work correctly?

Thank you


On May 6, 9:30 am, Sripathi Krishnan <sripathikrish...@gmail.com>
wrote:
> +1 on that - if you can, don't make the same mistake!
>
> We also put in some hacks to get the login page "GWT controlled". In
> retrospect, it was a poor decision. Its much cleaner to assume that the GWT
> page is only reachable once authenticated.
>
> --Sri
> P.S. And as luck would have it, as I typed this email, my gmail session
> timed out. I got a popup - "Your session has timedout". So, I was able to
> copy the draft, login again and then continue on this email. Not too bad for
> usability, I didn't loose my work.
>
> > google-web-tool...@googlegroups.com<google-web-toolkit%2Bunsubs cr...@googlegroups.com>
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/google-web-toolkit?hl=en.
>
> --
> You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
> To post to this group, send email to google-we...@googlegroups.com.
> To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
> For more options, visit this group athttp://groups.google.com/group/google-web-toolkit?hl=en.

Sripathi Krishnan

unread,
May 6, 2010, 1:24:31 PM5/6/10
to google-we...@googlegroups.com
Why don't you just use JAAS? You could then protect your GWT page in web.xml, and then instruct your app server to "redirect" to login page if the user is not logged in. You can also setup custom roles and permissions - the code is largely copy/paste and rest of the stuff is declarative in your web.xml.

Just do a google search on JAAS + your application server, you'll get detailed notes on how to setup.

--Sri

Craig Mitchell

unread,
Jul 3, 2012, 3:07:44 AM7/3/12
to google-we...@googlegroups.com
The submitting to a javascript URL was working great.  However, Chrome has decided to stop working (currently on version 20.0.1132.47 m).

And the only thing that seems to make it work, is doing a submit straight to the servlet from the login form, which is a real pain (and a major change).

Anyone else notice that Chrome has stopped working for auto complete?

> > To post to this group, send email to google-web-toolkit@googlegroups.com.

> > To unsubscribe from this group, send email to
> > .
> > For more options, visit this group at
> >http://groups.google.com/group/google-web-toolkit?hl=en.
>
> --
> You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
> To post to this group, send email to google-web-toolkit@googlegroups.com.
> To unsubscribe from this group, send email to google-web-toolkit+unsub...@googlegroups.com.
> For more options, visit this group athttp://groups.google.com/group/google-web-toolkit?hl=en.

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to google-web-toolkit+unsub...@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.


--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To post to this group, send email to google-web-toolkit@googlegroups.com.
To unsubscribe from this group, send email to google-web-toolkit+unsub...@googlegroups.com.

Craig Mitchell

unread,
Jul 3, 2012, 3:34:39 AM7/3/12
to google-we...@googlegroups.com
I should point out that it still works great in IE and Firefox.  Just not Chrome.

jopaki

unread,
Aug 28, 2012, 1:20:05 AM8/28/12
to google-we...@googlegroups.com, Google-We...@googlegroups.com
So all this form/FormPanel mangling implies that the <form> tag is required to be present in the original markup yes?  Otherwise, one could just have the username and password fields in the orig. markup and manually submit to server by trapping an onclick to a simple button and then construct the request via RequestBuilder.  What do you guys think about this?

Craig Mitchell

unread,
Aug 28, 2012, 1:47:18 AM8/28/12
to google-we...@googlegroups.com, Google-We...@googlegroups.com
Correct.  The form must be the thing doing the submit.

Although, as I pointed out, Chrome stopped working with a JavaScript call to trigger the form to submit.  So I now let the form do its own submit.  All I use GWT for is positioning the widgets.

It sucks, but it's the only way I could get it to work.

jopaki

unread,
Aug 28, 2012, 1:57:53 AM8/28/12
to google-we...@googlegroups.com, Google-We...@googlegroups.com
Gotcha.  Thanks much for the quick reply and good info! - j

Fille

unread,
Aug 28, 2012, 8:19:37 AM8/28/12
to google-we...@googlegroups.com, Google Web Toolkit

Is there any reason for not using just gwt HTML or somthing else with @UiHandler("loginButton") to make a RPC-call for log in?

Ex:

UiBinder:
<g:HTMLPanel>
     <g:TextBox ui:field="username" />
     <g:PasswordTextBox ui:field="password" />
     <g:HTML ui:field="loginButton"> LOGIN </g:HTML>
</g:HTMLPanel>


Composite:
@UiHandler("loginButton")
void onLoginClick(ClickEvent e) {
    // make RPC-call and validate user.....
}

Or is it just for autocomplete?

Craig Mitchell

unread,
Aug 28, 2012, 8:39:15 PM8/28/12
to google-we...@googlegroups.com, Google Web Toolkit
Just for autocomplete.  If you don't care about autocomplete, I'd recommend doing it as you say with GWT RPC.

Kara Rawsonkara

unread,
Aug 28, 2012, 1:33:38 AM8/28/12
to google-we...@googlegroups.com, google-we...@googlegroups.com
forms??? thats so 2000s. use event based design like u mentioned and submit via restful. using post get or update or whatever ur backend or api require. sometimes u need to use forms for file xfer or other specialized means. just keep in mind that not using forms can and does break usability / accessabilty guidelines. but then again i was never good at coloring or following the rules. 

Sent from my iPhone

On Aug 28, 2012, at 1:20 AM, jopaki <jop...@gmail.com> wrote:

So all this form/FormPanel mangling implies that the <form> tag is required to be present in the original markup yes?  Otherwise, one could just have the username and password fields in the orig. markup and manually submit to server by trapping an onclick to a simple button and then construct the request via RequestBuilder.  What do you guys think about this?

--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.

Craig Mitchell

unread,
Sep 3, 2012, 7:26:37 PM9/3/12
to google-we...@googlegroups.com
I'm a little confused.  The way Tomas showed (above) used to work with Autocomplete, however, Chrome decided it wasn't going to play nice with that any more.

The only solution I could find was to do a login with a form.  Eg: <form action="login" method="GET">...</form>

I don't know how to get Autocomplete working in Chrome with GWT RPC, and I don't understand what you're talking about with switching to a restful approach.

If you (or anyone) can offer a solution not using a form, I'm all ears.  As, yes, forms are so 2000s, and I would rather not use them.

Cheers.
To unsubscribe from this group, send email to google-web-toolkit+unsub...@googlegroups.com.

Thomas Broyer

unread,
Sep 4, 2012, 3:33:07 AM9/4/12
to google-we...@googlegroups.com


On Tuesday, September 4, 2012 1:26:37 AM UTC+2, Craig Mitchell wrote:
I'm a little confused.  The way Tomas showed (above) used to work with Autocomplete, however, Chrome decided it wasn't going to play nice with that any more.

The only solution I could find was to do a login with a form.  Eg: <form action="login" method="GET">...</form>

I don't know how to get Autocomplete working in Chrome with GWT RPC, and I don't understand what you're talking about with switching to a restful approach.

If you (or anyone) can offer a solution not using a form, I'm all ears.  As, yes, forms are so 2000s, and I would rather not use them.

Best way to do auth IMO is to either:

Lukas Glowania

unread,
Jun 19, 2013, 7:54:55 AM6/19/13
to google-we...@googlegroups.com, Google Web Toolkit
Apparently in recent Chrome the HTML form elements need name attributes for the setAction()-approach to work.
Reply all
Reply to author
Forward
0 new messages