diff --git a/webapp/config/tlds/VitroUtils.tld b/webapp/config/tlds/VitroUtils.tld
new file mode 100644
index 000000000..1bdbe1fb6
--- /dev/null
+++ b/webapp/config/tlds/VitroUtils.tld
@@ -0,0 +1,47 @@
+
+
+
+
+
+ Vitro Utilities taglib
+ 1.0
+
+ Library of JSP utility tags for Vitro
+
+
+
+ confirmLoginStatus
+ Confirm that the user is logged in as required
+
+ Check to see that the user is logged in (optionally at a certain minimum level).
+ If not, then redirect them to the login page, with the current request stored as
+ a post-login destination.
+
+ If "level" is specified, then the user must be logged in at least at that level
+ in order to avoid being redirected. "level" may be a String like "DBA" or "EDITOR",
+ or it may be an integer like 50 or 4.
+
+ If "bean" is specified, it is taken as the name of a request attribute where the
+ LoginStatusBean will be stored.
+
+ edu.cornell.mannlib.vitro.webapp.web.jsptags.ConfirmLoginStatus
+ empty
+
+ level
+ false
+ true
+
+
+ bean
+ false
+ true
+
+
+
+
\ No newline at end of file
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/jsptags/ConfirmLoginStatus.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/jsptags/ConfirmLoginStatus.java
new file mode 100644
index 000000000..5b2a2d5bc
--- /dev/null
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/jsptags/ConfirmLoginStatus.java
@@ -0,0 +1,95 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+
+package edu.cornell.mannlib.vitro.webapp.web.jsptags;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.BodyTagSupport;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
+import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
+
+/**
+ * JSP tag to generate the HTML of links for edit, delete or add of a Property.
+ *
+ * Maybe we should have a mode where it just sets a var to a map with "href" =
+ * "edit/editDatapropDispatch.jsp?subjectUri=..." and "type" = "delete"
+ *
+ * @author bdc34
+ *
+ */
+public class ConfirmLoginStatus extends BodyTagSupport {
+ private static final Log log = LogFactory.getLog(ConfirmLoginStatus.class);
+
+ int level;
+ String beanAttributeName;
+
+ public String getLevel() {
+ return String.valueOf(level);
+ }
+
+ public void setLevel(String levelString) {
+ if ("DBA".equals(levelString)) {
+ this.level = LoginStatusBean.DBA;
+ } else if ("CURATOR".equals(levelString)) {
+ this.level = LoginStatusBean.CURATOR;
+ } else if ("EDITOR".equals(levelString)) {
+ this.level = LoginStatusBean.EDITOR;
+ } else if ("NON_EDITOR".equals(levelString)) {
+ this.level = LoginStatusBean.NON_EDITOR;
+ } else {
+ throw new IllegalArgumentException("Level attribute '"
+ + levelString + "' is not valid.");
+ }
+ }
+
+ public String getBean() {
+ return this.beanAttributeName;
+ }
+
+ public void setbean(String beanAttributeName) {
+ this.beanAttributeName = beanAttributeName;
+ }
+
+ @Override
+ public int doEndTag() throws JspException {
+ LoginStatusBean loginBean = LoginStatusBean.getBean(getRequest());
+ if (loginBean.isLoggedInAtLeast(level)) {
+ return setBeanAndReturn(loginBean);
+ } else {
+ return redirectAndSkipPage();
+ }
+ }
+
+ private int setBeanAndReturn(LoginStatusBean loginBean) {
+ if (beanAttributeName != null) {
+ getRequest().setAttribute(beanAttributeName, loginBean);
+ }
+ return EVAL_PAGE;
+ }
+
+ private int redirectAndSkipPage() throws JspException {
+ try {
+ VitroHttpServlet.redirectToLoginPage(getRequest(), getResponse());
+ return SKIP_PAGE;
+ } catch (IOException ioe) {
+ throw new JspException(
+ " could not redirect to login page",
+ ioe);
+ }
+ }
+
+ private HttpServletRequest getRequest() {
+ return ((HttpServletRequest) pageContext.getRequest());
+ }
+
+ private HttpServletResponse getResponse() {
+ return (HttpServletResponse) pageContext.getResponse();
+ }
+}