From 4282da5ef2d6e0d69fdf1c0df49a60f017751794 Mon Sep 17 00:00:00 2001 From: j2blake Date: Tue, 14 Jun 2011 17:11:26 +0000 Subject: [PATCH] NIHVIVO-2696 External user gets an account on first login. --- .../UserAccountsFirstTimeExternalPage.java | 72 ++++++++++++++----- .../user/UserAccountsUserController.java | 33 +++++++-- .../authenticate/Authenticator.java | 11 --- .../authenticate/BasicAuthenticator.java | 19 +---- .../authenticate/LoginExternalAuthReturn.java | 32 +++------ .../authenticate/AuthenticatorStub.java | 6 -- .../userAccounts-firstTimeExternal.ftl | 1 + 7 files changed, 94 insertions(+), 80 deletions(-) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsFirstTimeExternalPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsFirstTimeExternalPage.java index f180d23c9..7b1d00572 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsFirstTimeExternalPage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsFirstTimeExternalPage.java @@ -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 body = new HashMap(); + 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; + } + } + } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsUserController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsUserController.java index 322dd6c2b..3dafd87f9 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsUserController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsUserController.java @@ -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; } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java index cddad2bdc..45b676164 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java @@ -105,17 +105,6 @@ public abstract class Authenticator { public abstract void recordLoginAgainstUserAccount(UserAccount userAccount, AuthenticationSource authSource); - /** - *
-	 * 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.
-	 * 
- * - * TODO JB This goes away. - */ - public abstract void recordLoginWithoutUserAccount(String individualUri); - /** *
 	 * Record that the current user has logged out: - notify other users of the
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java
index 2135f007f..f84bf041b 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java
@@ -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);
 	}
 
 	/**
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginExternalAuthReturn.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginExternalAuthReturn.java
index d970db6cd..ce008c64e 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginExternalAuthReturn.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginExternalAuthReturn.java
@@ -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 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) {
diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AuthenticatorStub.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AuthenticatorStub.java
index 6171387f9..3dd4fabd0 100644
--- a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AuthenticatorStub.java
+++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AuthenticatorStub.java
@@ -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.");
-	}
-
 }
diff --git a/webapp/web/templates/freemarker/body/accounts/userAccounts-firstTimeExternal.ftl b/webapp/web/templates/freemarker/body/accounts/userAccounts-firstTimeExternal.ftl
index 1b6b78791..8367ca164 100644
--- a/webapp/web/templates/freemarker/body/accounts/userAccounts-firstTimeExternal.ftl
+++ b/webapp/web/templates/freemarker/body/accounts/userAccounts-firstTimeExternal.ftl
@@ -39,6 +39,7 @@
 
         
+