NIHVIVO-2696 External user gets an account on first login.

This commit is contained in:
j2blake 2011-06-14 17:11:26 +00:00
parent cedd095a07
commit 4282da5ef2
7 changed files with 94 additions and 80 deletions

View file

@ -9,6 +9,8 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.commons.lang.StringUtils;
import edu.cornell.mannlib.vitro.webapp.auth.permissions.PermissionSetsLoader;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
@ -22,13 +24,14 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.Tem
* Handle the first-time login of an Externally Authenticated user who has no
* UserAccount - let's create one!
*
* If they get here from the login, there should an externalAuthId waiting in
* the session. Otherwise, they should get here by submitting the form, which
* will have the externalAuthId as a hidden field.
* If they get here from the login, there should be an ExternalLoginInfo waiting
* in the session. Otherwise, they should get here by submitting the form, which
* will have the info in hidden fields.
*/
public class UserAccountsFirstTimeExternalPage extends UserAccountsPage {
private static final String PARAMETER_SUBMIT = "submit";
private static final String PARAMETER_EXTERNAL_AUTH_ID = "externalAuthId";
private static final String PARAMETER_AFTER_LOGIN_URL = "afterLoginUrl";
private static final String PARAMETER_EMAIL_ADDRESS = "emailAddress";
private static final String PARAMETER_FIRST_NAME = "firstName";
private static final String PARAMETER_LAST_NAME = "lastName";
@ -41,23 +44,25 @@ public class UserAccountsFirstTimeExternalPage extends UserAccountsPage {
private static final String TEMPLATE_NAME = "userAccounts-firstTimeExternal.ftl";
private static final String ATTRIBUTE_EXTERNAL_AUTH_ID = UserAccountsFirstTimeExternalPage.class
private static final String ATTRIBUTE_EXTERNAL_LOGIN_INFO = UserAccountsFirstTimeExternalPage.class
.getName();
/**
* Let some other request set the External Auth ID before redirecting to
* here.
* Let some other request set the External Auth ID and the afterLogin URL
* before redirecting to here.
*/
public static void setExternalAuthId(HttpServletRequest req,
String externalAuthId) {
req.getSession().setAttribute(ATTRIBUTE_EXTERNAL_AUTH_ID,
externalAuthId);
public static void setExternalLoginInfo(HttpServletRequest req,
String externalAuthId, String afterLoginUrl) {
req.getSession().setAttribute(ATTRIBUTE_EXTERNAL_LOGIN_INFO,
new ExternalLoginInfo(externalAuthId, afterLoginUrl));
}
private final UserAccountsFirstTimeExternalPageStrategy strategy;
private boolean submit = false;
private String externalAuthId = "";
private String afterLoginUrl = "";
private boolean submit = false;
private String emailAddress = "";
private String firstName = "";
private String lastName = "";
@ -71,7 +76,7 @@ public class UserAccountsFirstTimeExternalPage extends UserAccountsPage {
this.strategy = UserAccountsFirstTimeExternalPageStrategy.getInstance(
vreq, this, isEmailEnabled());
checkSessionForExternalAuthId();
checkSessionForExternalLoginInfo();
if (externalAuthId.isEmpty()) {
parseRequestParameters();
}
@ -83,20 +88,26 @@ public class UserAccountsFirstTimeExternalPage extends UserAccountsPage {
}
}
private void checkSessionForExternalAuthId() {
private void checkSessionForExternalLoginInfo() {
HttpSession session = vreq.getSession();
Object o = session.getAttribute(ATTRIBUTE_EXTERNAL_AUTH_ID);
session.removeAttribute(ATTRIBUTE_EXTERNAL_AUTH_ID);
Object o = session.getAttribute(ATTRIBUTE_EXTERNAL_LOGIN_INFO);
session.removeAttribute(ATTRIBUTE_EXTERNAL_LOGIN_INFO);
if (o instanceof String) {
externalAuthId = (String) o;
if (o instanceof ExternalLoginInfo) {
externalAuthId = ((ExternalLoginInfo) o).externalAuthId;
afterLoginUrl = ((ExternalLoginInfo) o).afterLoginUrl;
if (afterLoginUrl == null) {
afterLoginUrl = "";
}
}
}
private void parseRequestParameters() {
submit = isFlagOnRequest(PARAMETER_SUBMIT);
externalAuthId = getStringParameter(PARAMETER_EXTERNAL_AUTH_ID, "");
afterLoginUrl = getStringParameter(PARAMETER_AFTER_LOGIN_URL, "");
submit = isFlagOnRequest(PARAMETER_SUBMIT);
emailAddress = getStringParameter(PARAMETER_EMAIL_ADDRESS, "");
firstName = getStringParameter(PARAMETER_FIRST_NAME, "");
lastName = getStringParameter(PARAMETER_LAST_NAME, "");
@ -156,10 +167,12 @@ public class UserAccountsFirstTimeExternalPage extends UserAccountsPage {
public final ResponseValues showPage() {
Map<String, Object> body = new HashMap<String, Object>();
body.put("externalAuthId", externalAuthId);
body.put("afterLoginUrl", afterLoginUrl);
body.put("emailAddress", emailAddress);
body.put("firstName", firstName);
body.put("lastName", lastName);
body.put("externalAuthId", externalAuthId);
body.put("formUrls", buildUrlsMap());
if (!errorCode.isEmpty()) {
@ -191,4 +204,25 @@ public class UserAccountsFirstTimeExternalPage extends UserAccountsPage {
return u;
}
/**
* If the afterLoginUrl is missing, go to the home page. If it is relative,
* make sure it doesn't start with the cotext path.
*/
public String getAfterLoginUrl() {
if (StringUtils.isEmpty(afterLoginUrl)) {
return null;
}
return afterLoginUrl;
}
private static class ExternalLoginInfo {
final String externalAuthId;
final String afterLoginUrl;
public ExternalLoginInfo(String externalAuthId, String afterLoginUrl) {
this.externalAuthId = externalAuthId;
this.afterLoginUrl = afterLoginUrl;
}
}
}

View file

@ -4,10 +4,10 @@ package edu.cornell.mannlib.vitro.webapp.controller.accounts.user;
import static edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource.EXTERNAL;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.EditOwnAccount;
import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage;
@ -115,9 +115,7 @@ public class UserAccountsUserController extends FreemarkerHttpServlet {
UserAccount userAccount = page.createAccount();
Authenticator auth = Authenticator.getInstance(vreq);
auth.recordLoginAgainstUserAccount(userAccount, EXTERNAL);
LoginProcessBean.removeBean(vreq);
return showLoginRedirection(vreq);
return showLoginRedirection(vreq, page.getAfterLoginUrl());
} else {
return page.showPage();
}
@ -132,10 +130,31 @@ public class UserAccountsUserController extends FreemarkerHttpServlet {
return new RedirectResponseValues("/");
}
private ResponseValues showLoginRedirection(VitroRequest vreq) {
LoginRedirector lr = new LoginRedirector(vreq, null);
private ResponseValues showLoginRedirection(VitroRequest vreq,
String afterLoginUrl) {
LoginRedirector lr = new LoginRedirector(vreq, afterLoginUrl);
DisplayMessage.setMessage(vreq, lr.assembleWelcomeMessage());
String uri = lr.getRedirectionUriForLoggedInUser();
return new RedirectResponseValues(uri);
return new RedirectResponseValues(stripContextPath(vreq, uri));
}
/**
* TODO The LoginRedirector gives a URI that includes the context path. But
* the RedirectResponseValues wants a URI that does not include the context
* path.
*
* Bridge the gap.
*/
private String stripContextPath(VitroRequest vreq, String uri) {
if ((uri == null) || uri.isEmpty() || uri.equals(vreq.getContextPath())) {
return "/";
}
if (uri.contains("://")) {
return uri;
}
if (uri.startsWith(vreq.getContextPath() + '/')) {
return uri.substring(vreq.getContextPath().length());
}
return uri;
}
}

View file

@ -105,17 +105,6 @@ public abstract class Authenticator {
public abstract void recordLoginAgainstUserAccount(UserAccount userAccount,
AuthenticationSource authSource);
/**
* <pre>
* Record that the user has logged in but with only external authentication
* info, so no internal user account.
* - this involves everything except updating the user record.
* </pre>
*
* TODO JB This goes away.
*/
public abstract void recordLoginWithoutUserAccount(String individualUri);
/**
* <pre>
* Record that the current user has logged out: - notify other users of the

View file

@ -3,7 +3,6 @@
package edu.cornell.mannlib.vitro.webapp.controller.authenticate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -123,24 +122,12 @@ public class BasicAuthenticator extends Authenticator {
}
recordLoginOnUserRecord(userAccount);
recordLoginWithOrWithoutUserAccount(userAccount.getUri(), authSource);
}
// TODO JB This goes away.
@Override
public void recordLoginWithoutUserAccount(String individualUri) {
recordLoginWithOrWithoutUserAccount(individualUri,
AuthenticationSource.EXTERNAL);
}
/** This much is in common on login, whether or not you have a user account. */
private void recordLoginWithOrWithoutUserAccount(String userUri,
AuthenticationSource authSource) {
HttpSession session = request.getSession();
createLoginStatusBean(userUri, authSource, session);
createLoginStatusBean(userAccount.getUri(), authSource, session);
setSessionTimeoutLimit(session);
recordInUserSessionMap(userUri, session);
notifyOtherUsers(userUri, session);
recordInUserSessionMap(userAccount.getUri(), session);
notifyOtherUsers(userAccount.getUri(), session);
}
/**

View file

@ -5,7 +5,6 @@ package edu.cornell.mannlib.vitro.webapp.controller.authenticate;
import static edu.cornell.mannlib.vitro.webapp.controller.authenticate.LoginExternalAuthSetup.ATTRIBUTE_REFERRER;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -16,6 +15,8 @@ import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.user.UserAccountsFirstTimeExternalPage;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean;
/**
@ -57,37 +58,26 @@ public class LoginExternalAuthReturn extends BaseLoginServlet {
MESSAGE_LOGIN_FAILED);
return;
}
String afterLoginUrl = LoginProcessBean.getBean(req).getAfterLoginUrl();
removeLoginProcessArtifacts(req);
UserAccount userAccount = getAuthenticator(req)
.getAccountForExternalAuth(externalAuthId);
if (userAccount != null) {
if (userAccount == null) {
log.debug("Creating new account for " + externalAuthId
+ ", return to '" + afterLoginUrl + "'");
UserAccountsFirstTimeExternalPage.setExternalLoginInfo(req,
externalAuthId, afterLoginUrl);
resp.sendRedirect(UrlBuilder.getUrl("/accounts/firstTimeExternal"));
return;
} else {
log.debug("Logging in as " + userAccount.getUri());
getAuthenticator(req).recordLoginAgainstUserAccount(userAccount,
AuthenticationSource.EXTERNAL);
new LoginRedirector(req, afterLoginUrl).redirectLoggedInUser(resp);
return;
}
List<String> associatedUris = getAuthenticator(req)
.getAssociatedIndividualUris(userAccount);
// TODO JB - this case should lead to creating a new account.
if (!associatedUris.isEmpty()) {
log.debug("Recognize '" + externalAuthId + "' as self-editor for "
+ associatedUris);
String uri = associatedUris.get(0);
getAuthenticator(req).recordLoginWithoutUserAccount(uri);
new LoginRedirector(req, afterLoginUrl).redirectLoggedInUser(resp);
return;
}
log.debug("User is not recognized: " + externalAuthId);
removeLoginProcessArtifacts(req);
new LoginRedirector(req, afterLoginUrl).redirectUnrecognizedExternalUser(resp,
externalAuthId);
}
private void removeLoginProcessArtifacts(HttpServletRequest req) {

View file

@ -182,10 +182,4 @@ public class AuthenticatorStub extends Authenticator {
"AuthenticatorStub.accountRequiresEditing() not implemented.");
}
@Override
public void recordLoginWithoutUserAccount(String individualUri) {
throw new RuntimeException(
"AuthenticatorStub.recordLoginWithoutUserAccount() not implemented.");
}
}

View file

@ -39,6 +39,7 @@
<form method="POST" action="${formUrls.firstTimeExternal}" class="customForm" role="my account">
<input type="hidden" name="externalAuthId" value="${externalAuthId}" />
<input type="hidden" name="afterLoginUrl" value="${afterLoginUrl}" />
<label for="first-name">First name<span class="requiredHint"> *</span></label>
<input type="text" name="firstName" value="${firstName}" id="first-name" role="input "/>