Skip to content

Instantly share code, notes, and snippets.

@danbev
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danbev/ef3a2a08b5d8e41d6879 to your computer and use it in GitHub Desktop.
Save danbev/ef3a2a08b5d8e41d6879 to your computer and use it in GitHub Desktop.
contacts-mobile-webapp and contacts-picketlink-secured

This gist describes the steps and a question about why the contacts-picketlink-secured quickstart requires two login attempt to function properly.

This branch which requires a local build of Fabric8.

The following interactions start with the signin-page to walk through the requests made from contacts-mobile-webapp and contacts-picketlink-secured (the backend).

Chrome

  1. I enter my username and credentials (admin, admin) and submit the request.
    security.js contains the following jquery that will submit the request to the server:
var jqxhr = $.ajax({
  url: restSecurityEndpoint + "user/info",
  contentType: "application/json",
  dataType: "json",
  headers: {
    "Authorization": "Basic " + btoa(serializedForm.loginName + ":" + serializedForm.password)
  },
  type: "GET"

The first request to the server will be a CORS preflight request which the CORSFilter will handle.
The next request is the actual GET request. This request will hit the AuthenticationFilter which will extract the basic auth header and if proceed to create a HTTP session, login the identity, and then pass the request and responst through the filter chain. The request will end up in UserService#getCurrentUser which will return the authenticated user in JSON format.

When this request returns control to the javascript we are back in security.js and in the done callback. done will clear the input form and the call CONTACTS.security.loadCurrentUser();

CONTACTS.security.loadCurrentUser()

var jqxhr = $.ajax({
      url: restSecurityEndpoint + "user/info",
      xhrFields: {withCredentials: true},
      contentType: "application/json",
      dataType: "json",
      type: "GET",
      //async: false

I modified this to be [async](http://api.jquery.com/jquery.ajax/] as sync is not supported with CORS. Notice that we are making another GET request to the same resource as we did for the login process.
By setting a breakpoint in the doFilter method of AuthenticationFilter I can see that the current identity is not logged in. Interesting though is that this request also contains the authentication headers even though these were never added for this request. But since they are, a second login is done just as above. Since I made the above request async I also moved the displaying of the contacts list to the done callback of loadCurrentUser so that this would only happen after that call has been completed. When this was a sync call the call to CONTACTS.app.getContacts was done as the last thing in the done callback:

$( "body" ).pagecontainer( "change", "#contacts-list-page");

CONTACTS.app.getContacts

This will perform the following request:

var jqxhr = $.ajax({
  url: restEndpoint,
  xhrFields: {withCredentials: true},
  cache: false,
  type: "GET"

This call accesses the resources which is protected by @UserLoggedIn:

@Secures
    @UserLoggedIn
    public boolean isLoggedIn() {
        return this.identityInstance.get().isLoggedIn();
    }

This returns true and the calls is successful.

FireFox

Work pretty much the same as Chrome above.

Safari

In this case the second authentication request does not have the Authorization header. What happens in this case is that the AuthenticationFilter will send a WWW-Authenticate challenge to the browser which will popup a dialog for basic authentiation.

Opera

Works in the same way as Safari

Why is the Authorization header sent?

Even though it is not added to Chrome or FireFox it is still sent by the browser. It seems that these brower cache the Authorization header when a 401 is returned for an authorization. This is the reason for it existing in the second request. But this is not done by Safari and Opera which means that the second call get getCurrentUser will not succeed and the 401 challenge will be returned triggering the browser to popup user/password dialog.

Why is a second request for user data needed. With all browser the first request is successful and a http session is created and the identity is populated
Both request return the same data so why can't we just store the data upon the first response and then transition to the getContacts page? I tried this but the this.identityInstance.get().isLoggedIn() returns false in this case.

Questions

  1. Is LoginService#login ever invoked?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment