}
public static void checkLoginStatus(final String user, final String password, final AsyncCallback<Subject> callback) {
//initiate request to portal.war(SessionAccessServlet) to retrieve existing session info if exists
//session has valid user then <subjectId>:<sessionId>:<lastAccess> else ""
final RequestBuilder b = createSessionAccessRequestBuilder();
try {
b.setCallback(new RequestCallback() {
public void onResponseReceived(final Request request, final Response response) {
Log.info("response text = " + response.getText());
String sessionIdString = response.getText();
if (sessionIdString.startsWith("booting")) {
// "booting" is the string we get back from SessionAccessServlet if StartupBean hasn't finished
new LoginView().showLoginDialog(MSG.view_core_serverInitializing());
return;
}
// If a session is active it will return valid session strings
if (sessionIdString.length() > 0) {
String[] parts = sessionIdString.split(":");
final int subjectId = Integer.parseInt(parts[0]);
final String sessionId = parts[1]; // not null
final long lastAccess = Long.parseLong(parts[2]);
Log.info("sessionAccess-subjectId: " + subjectId);
Log.info("sessionAccess-sessionId: " + sessionId);
Log.info("sessionAccess-lastAccess: " + lastAccess);
// There is a window of LOGOUT_DELAY ms where the coreGui session is logged out but the
// server session is valid (to allow in-flight requests to process successfully). During
// this window prevent a browser refresh (F5) from being able to bypass the
// loginView and hijack the still-valid server session. We need to allow:
// 1) a browser refresh when coreGui is logged in (no doomedSession)
// 2) a valid, quick re-login (sessionState loggedOut, not unknown)
// Being careful of these scenarios, catch the bad refresh situation and
// redirect back to loginView
if (State.IS_UNKNOWN == sessionState && sessionId.equals(getDoomedSessionId())) {
// a browser refresh kills any existing logoutTimer. Reschedule the logout.
sessionState = State.IS_LOGGED_OUT;
scheduleLogoutServerSide(sessionId);
new LoginView().showLoginDialog(true);
return;
}
String previousSessionId = getPreviousSessionId(); // may be null
Log.info("sessionAccess-previousSessionId: " + previousSessionId);
if (previousSessionId == null || previousSessionId.equals(sessionId) == false) {
// persist sessionId if different from previously saved sessionId
Log.info("sessionAccess-savingSessionId: " + sessionId);
saveSessionId(sessionId);
// new sessions get the full SESSION_TIMEOUT period prior to expire
Log.info("sessionAccess-schedulingSessionTimeout: " + sessionTimeout);
coreGuiSessionTimer.schedule(sessionTimeout);
} else {
// existing sessions should expire SESSION_TIMEOUT minutes from the previous access time
long expiryTime = lastAccess + sessionTimeout;
long expiryMillis = expiryTime - System.currentTimeMillis();
// can not schedule a time with millis less than or equal to 0
if (expiryMillis < 1) {
expiryMillis = 1; // expire VERY quickly
} else if (expiryMillis > sessionTimeout) {
expiryMillis = sessionTimeout; // guarantees maximum
}
Log.info("sessionAccess-reschedulingSessionTimeout: " + expiryMillis);
coreGuiSessionTimer.schedule((int) expiryMillis);
}
// Certain logins may not follow a "LogOut" history item. Specifically, if the session timer
// causes a logout the History token will be the user's current view. If the same user
// logs in again his view should be maintained, but if the subsequent login is for a
// different user we want him to start fresh, so in this case ensure a proper
// History token is set.
if (!History.getToken().equals("LogOut")) {
if (null != sessionSubject && sessionSubject.getId() != subjectId) {
// on user change register the logout
History.newItem("LogOut", false);
}
// TODO else {
// We don't currently capture enough state info to solve this scenario:
// 1) session expires
// 2) browser refresh
// 3) log in as different user.
// In this case the previous user's path will be the initial view for the new user. To
// solve this we'd need to somehow flag that a browser refresh has occurred. This may
// be doable by looking for state transitions from UNKNOWN to other states.
// }
}
// set the session subject, so the fetch to load the configuration works
final Subject subject = new Subject();
subject.setId(subjectId);
subject.setSessionId(Integer.valueOf(sessionId));
// populate the username for the subject for isUserWithPrincipal check in ldap processing
subject.setName(user);
sessionSubject = subject;
if (subject.getId() == 0) {//either i)ldap new user registration ii)ldap case sensitive match
if ((subject.getName() == null) || (subject.getName().trim().isEmpty())) {
//we've lost crucial information, probably in a browser refresh. Send them back through login
Log.trace("Unable to locate information critical to ldap registration/account lookup. Log back in.");
sessionState = State.IS_LOGGED_OUT;
new LoginView().showLoginDialog(true);
return;
}
Log.error("Proceeding with case insensitive login of ldap user '" + user + "'.");
GWTServiceLookup.getSubjectService().processSubjectForLdap(subject, password,
new AsyncCallback<Subject>() {
public void onFailure(Throwable caught) {
// this means either: a) we mapped the username to a previously registered LDAP
// user but login via LDAP failed, or b) we were not able to map the username
// to any LDAP users, previously registered or not.
Log.debug("Failed to complete ldap processing for subject: "
+ caught.getMessage());
new LoginView().showLoginDialog(MSG.view_login_noUser());
return;
}
public void onSuccess(final Subject processedSubject) {
//Then found case insensitive and returned that logged in user
//Figure out of this is new user registration
boolean isNewUser = false;
if (processedSubject.getUserConfiguration() != null) {
isNewUser = Boolean.valueOf(processedSubject.getUserConfiguration()
.getSimpleValue("isNewUser", "false"));
}
if (!isNewUser) {
// otherwise, we successfully logged in as an existing LDAP user case insensitively.
Log.trace("Logged in case insensitively as ldap user '"
+ processedSubject.getName() + "'");
callback.onSuccess(processedSubject);
} else {// if account is still active assume new LDAP user registration.
Log.trace("Proceeding with registration for ldap user '" + user + "'.");
sessionState = State.IS_REGISTERING;
sessionSubject = processedSubject;
new LoginView().showRegistrationDialog(subject.getName(),
String.valueOf(processedSubject.getSessionId()), password, callback);
}
return;
}
});//end processSubjectForLdap call
} else {//else send through regular session check
SubjectCriteria criteria = new SubjectCriteria();
criteria.fetchConfiguration(true);
criteria.addFilterId(subjectId);
GWTServiceLookup.getSubjectService().findSubjectsByCriteria(criteria,
new AsyncCallback<PageList<Subject>>() {
public void onFailure(Throwable caught) {
CoreGUI.getErrorHandler().handleError(MSG.util_userSession_loadFailSubject(),
caught);
Log.info("Failed to load user's subject");
//TODO: pass message to login ui.
new LoginView().showLoginDialog(true);
return;
}
public void onSuccess(PageList<Subject> results) {
final Subject validSessionSubject = results.get(0);
//update the returned subject with current session id
validSessionSubject.setSessionId(Integer.valueOf(sessionId));
Log.trace("Completed session check for subject '" + validSessionSubject + "'.");
//initiate ldap check for ldap authz update(wrt roles) of subject with silent update
//as the subject.id > 0 then only group authorization updates will occur if ldap configured.
GWTServiceLookup.getSubjectService().processSubjectForLdap(validSessionSubject,
"", new AsyncCallback<Subject>() {
public void onFailure(Throwable caught) {
Log.warn("Errors occurred processing subject for LDAP."
+ caught.getMessage());
//TODO: pass informative message to Login UI.
callback.onSuccess(validSessionSubject);
return;
}
public void onSuccess(Subject result) {
Log.trace("Successfully processed subject '"
+ validSessionSubject.getName() + "' for LDAP.");
callback.onSuccess(validSessionSubject);
return;
}
});
}
});
}//end of server side session check;
} else {
//invalid client session. Back to login
sessionState = State.IS_LOGGED_OUT;
new LoginView().showLoginDialog(true);
return;
}
}
public void onError(Request request, Throwable exception) {
callback.onFailure(exception);
}
});
b.send();
} catch (RequestException e) {
callback.onFailure(e);
}
}