NIHVIVO-2299 Create the root user policy and changes to deploy.properties
This commit is contained in:
parent
7a451c069c
commit
f88be755cf
11 changed files with 260 additions and 5 deletions
|
@ -114,8 +114,8 @@ deploy - Deploy the application directly into the Tomcat webapps directory.
|
|||
message="${deploy.properties.file} must contain a value for VitroConnection.DataSource.username" />
|
||||
<fail unless="VitroConnection.DataSource.password"
|
||||
message="${deploy.properties.file} must contain a value for VitroConnection.DataSource.password" />
|
||||
<fail unless="initialAdminUser"
|
||||
message="${deploy.properties.file} must contain a value for initialAdminUser" />
|
||||
<fail unless="rootUser.emailAddress"
|
||||
message="${deploy.properties.file} must contain a value for rootUser.emailAddress" />
|
||||
|
||||
</target>
|
||||
|
||||
|
|
|
@ -83,11 +83,11 @@ VitroConnection.DataSource.validationQuery = SELECT 1
|
|||
# vitro.local.solr.url =
|
||||
|
||||
#
|
||||
# The name of your first admin user for the Vitro application. The password
|
||||
# for this user is initially set to "defaultAdmin", but you will be asked to
|
||||
# The email address of the root user for the VIVO application. The password
|
||||
# for this user is initially set to "rootPassword", but you will be asked to
|
||||
# change the password the first time you log in.
|
||||
#
|
||||
initialAdminUser = defaultAdmin
|
||||
rootUser.emailAddress = root@myDomain.com
|
||||
|
||||
#
|
||||
# How is a logged-in user associated with a particular Individual? One way is
|
||||
|
|
|
@ -24,6 +24,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.Individual;
|
|||
import edu.cornell.mannlib.vitro.webapp.beans.SelfEditingConfiguration;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
|
||||
/**
|
||||
|
@ -49,6 +50,7 @@ public class CommonIdentifierBundleFactory implements IdentifierBundleFactory {
|
|||
ArrayIdentifierBundle bundle = new ArrayIdentifierBundle();
|
||||
|
||||
bundle.addAll(createUserIdentifiers(req));
|
||||
bundle.addAll(createRootUserIdentifiers(req));
|
||||
bundle.addAll(createRoleLevelIdentifiers(req));
|
||||
bundle.addAll(createBlacklistOrAssociatedIndividualIdentifiers(req));
|
||||
|
||||
|
@ -68,6 +70,16 @@ public class CommonIdentifierBundleFactory implements IdentifierBundleFactory {
|
|||
}
|
||||
}
|
||||
|
||||
private Collection<? extends Identifier> createRootUserIdentifiers(
|
||||
HttpServletRequest req) {
|
||||
UserAccount user = LoginStatusBean.getCurrentUser(req);
|
||||
if (isRootUser(user)) {
|
||||
return Collections.singleton(new IsRootUser());
|
||||
} else {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an identifier that shows the role level of the current user, or
|
||||
* PUBLIC if the user is not logged in.
|
||||
|
@ -131,6 +143,25 @@ public class CommonIdentifierBundleFactory implements IdentifierBundleFactory {
|
|||
return individuals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this user a root user?
|
||||
*/
|
||||
private boolean isRootUser(UserAccount user) {
|
||||
if (user == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WebappDaoFactory wdf = (WebappDaoFactory) context
|
||||
.getAttribute("webappDaoFactory");
|
||||
if (wdf == null) {
|
||||
log.error("Could not get a WebappDaoFactory from the ServletContext");
|
||||
return false;
|
||||
}
|
||||
|
||||
UserAccountsDao uaDao = wdf.getUserAccountsDao();
|
||||
return uaDao.isRootUser(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getClass().getSimpleName() + " - " + hashCode();
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.auth.identifier.common;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.Identifier;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
|
||||
|
||||
/**
|
||||
* The current user is a root user.
|
||||
*/
|
||||
public class IsRootUser extends AbstractCommonIdentifier implements Identifier {
|
||||
public static boolean isRootUser(IdentifierBundle ids) {
|
||||
return !getIdentifiersForClass(ids, IsRootUser.class).isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "IsRootUser";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,164 @@
|
|||
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||
|
||||
package edu.cornell.mannlib.vitro.webapp.auth.policy;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
import javax.servlet.ServletContextListener;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import com.hp.hpl.jena.ontology.OntModel;
|
||||
import com.hp.hpl.jena.rdf.model.Resource;
|
||||
import com.hp.hpl.jena.shared.Lock;
|
||||
import com.hp.hpl.jena.vocabulary.RDF;
|
||||
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.IsRootUser;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface;
|
||||
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
|
||||
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
|
||||
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext;
|
||||
import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup;
|
||||
|
||||
/**
|
||||
* If the user has an IsRootUser identifier, they can do anything!
|
||||
*
|
||||
* On setup, check to see that there is a root user. If not, create one. If we
|
||||
* can't create one, abort.
|
||||
*/
|
||||
public class RootUserPolicy implements PolicyIface {
|
||||
private static final Log log = LogFactory.getLog(RootUserPolicy.class);
|
||||
|
||||
private static final String PROPERTY_ROOT_USER_EMAIL = "rootUser.emailAddress";
|
||||
private static final String ROOT_USER_INITIAL_PASSWORD = "rootPassword";
|
||||
|
||||
/**
|
||||
* This is the entire policy. If you are a root user, you are authorized.
|
||||
*/
|
||||
@Override
|
||||
public PolicyDecision isAuthorized(IdentifierBundle whoToAuth,
|
||||
RequestedAction whatToAuth) {
|
||||
if (IsRootUser.isRootUser(whoToAuth)) {
|
||||
return new BasicPolicyDecision(Authorization.AUTHORIZED,
|
||||
"RootUserPolicy: approved");
|
||||
} else {
|
||||
return new BasicPolicyDecision(Authorization.INCONCLUSIVE,
|
||||
"not root user");
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// Setup class
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
public static class Setup implements ServletContextListener {
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce) {
|
||||
ServletContext ctx = sce.getServletContext();
|
||||
|
||||
if (AbortStartup.isStartupAborted(ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
UserAccountsDao uaDao = getUserAccountsDao(ctx);
|
||||
OntModel userAccountsModel = getUserAccountsModel(ctx);
|
||||
|
||||
if (!rootUserExists(uaDao)) {
|
||||
createRootUser(ctx, uaDao, userAccountsModel);
|
||||
}
|
||||
|
||||
ServletPolicyList.addPolicy(ctx, new RootUserPolicy());
|
||||
} catch (Exception e) {
|
||||
log.error("could not run " + this.getClass().getSimpleName()
|
||||
+ ": " + e);
|
||||
AbortStartup.abortStartup(ctx);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private UserAccountsDao getUserAccountsDao(ServletContext ctx) {
|
||||
WebappDaoFactory wadf = (WebappDaoFactory) ctx
|
||||
.getAttribute("webappDaoFactory");
|
||||
if (wadf == null) {
|
||||
throw new IllegalStateException(
|
||||
"No webappDaoFactory on the servlet context");
|
||||
}
|
||||
return wadf.getUserAccountsDao();
|
||||
}
|
||||
|
||||
private OntModel getUserAccountsModel(ServletContext ctx) {
|
||||
return ModelContext.getBaseOntModelSelector(ctx)
|
||||
.getUserAccountsModel();
|
||||
}
|
||||
|
||||
private boolean rootUserExists(UserAccountsDao uaDao) {
|
||||
for (UserAccount ua : uaDao.getAllUserAccounts()) {
|
||||
if (uaDao.isRootUser(ua)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO The first and last name should be left blank, so the user will
|
||||
* be forced to edit them. However, that's not in place yet.
|
||||
*/
|
||||
private void createRootUser(ServletContext ctx, UserAccountsDao uaDao,
|
||||
OntModel userAccountsModel) {
|
||||
String emailAddress = ConfigurationProperties.getBean(ctx)
|
||||
.getProperty(PROPERTY_ROOT_USER_EMAIL);
|
||||
if (emailAddress == null) {
|
||||
throw new IllegalStateException(
|
||||
"deploy.properties must contain a value for '"
|
||||
+ PROPERTY_ROOT_USER_EMAIL + "'");
|
||||
}
|
||||
|
||||
if (null != uaDao.getUserAccountByEmail(emailAddress)) {
|
||||
throw new IllegalStateException("Can't create root user - "
|
||||
+ "an account already exists with email address '"
|
||||
+ emailAddress + "'");
|
||||
}
|
||||
|
||||
UserAccount ua = new UserAccount();
|
||||
ua.setEmailAddress(emailAddress);
|
||||
ua.setFirstName("root");
|
||||
ua.setLastName("user");
|
||||
ua.setMd5Password(Authenticator
|
||||
.applyMd5Encoding(ROOT_USER_INITIAL_PASSWORD));
|
||||
ua.setPasswordChangeRequired(true);
|
||||
ua.setStatus(Status.ACTIVE);
|
||||
|
||||
uaDao.insertUserAccount(ua);
|
||||
|
||||
userAccountsModel.enterCriticalSection(Lock.WRITE);
|
||||
try {
|
||||
Resource r = userAccountsModel.getResource(ua.getUri());
|
||||
Resource t = userAccountsModel
|
||||
.getResource(VitroVocabulary.USERACCOUNT_ROOT_USER);
|
||||
userAccountsModel.add(r, RDF.type, t);
|
||||
} finally {
|
||||
userAccountsModel.leaveCriticalSection();
|
||||
}
|
||||
|
||||
log.info("Created root user as '" + emailAddress + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contextDestroyed(ServletContextEvent sce) {
|
||||
// Nothing to destroy
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,6 +40,11 @@ public interface UserAccountsDao {
|
|||
*/
|
||||
UserAccount getUserAccountByExternalAuthId(String externalAuthId);
|
||||
|
||||
/**
|
||||
* Is this UserAccount a root user?
|
||||
*/
|
||||
boolean isRootUser(UserAccount userAccount);
|
||||
|
||||
/**
|
||||
* Create a new UserAccount in the model.
|
||||
*
|
||||
|
|
|
@ -174,6 +174,7 @@ public class VitroVocabulary {
|
|||
// =============== Vitro UserAccount and PermissionSet vocabulary ===========
|
||||
|
||||
public static final String USERACCOUNT = VITRO_AUTH + "UserAccount";
|
||||
public static final String USERACCOUNT_ROOT_USER = VITRO_AUTH + "RootUserAccount";
|
||||
public static final String USERACCOUNT_EMAIL_ADDRESS = VITRO_AUTH + "emailAddress";
|
||||
public static final String USERACCOUNT_FIRST_NAME = VITRO_AUTH + "firstName";
|
||||
public static final String USERACCOUNT_LAST_NAME = VITRO_AUTH + "lastName";
|
||||
|
|
|
@ -47,6 +47,11 @@ public class UserAccountsDaoFiltering extends BaseFiltering implements
|
|||
return innerDao.getUserAccountByExternalAuthId(externalAuthId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRootUser(UserAccount userAccount) {
|
||||
return innerDao.isRootUser(userAccount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String insertUserAccount(UserAccount userAccount) {
|
||||
return innerDao.insertUserAccount(userAccount);
|
||||
|
|
|
@ -155,6 +155,7 @@ public class JenaBaseDaoCon {
|
|||
/* ***************** User Account Model constants ***************** */
|
||||
|
||||
protected OntClass USERACCOUNT = _constModel.createClass(VitroVocabulary.USERACCOUNT);
|
||||
protected OntClass USERACCOUNT_ROOT_USER = _constModel.createClass(VitroVocabulary.USERACCOUNT_ROOT_USER);
|
||||
protected DatatypeProperty USERACCOUNT_EMAIL_ADDRESS = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_EMAIL_ADDRESS);
|
||||
protected DatatypeProperty USERACCOUNT_FIRST_NAME = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_FIRST_NAME);
|
||||
protected DatatypeProperty USERACCOUNT_LAST_NAME = _constModel.createDatatypeProperty(VitroVocabulary.USERACCOUNT_LAST_NAME);
|
||||
|
|
|
@ -157,6 +157,21 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao
|
|||
return getUserAccountByUri(userUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRootUser(UserAccount userAccount) {
|
||||
if (userAccount == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
getOntModel().enterCriticalSection(Lock.READ);
|
||||
try {
|
||||
OntResource r = getOntModel().getOntResource(userAccount.getUri());
|
||||
return isResourceOfType(r, USERACCOUNT_ROOT_USER);
|
||||
} finally {
|
||||
getOntModel().leaveCriticalSection();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String insertUserAccount(UserAccount userAccount) {
|
||||
if (userAccount == null) {
|
||||
|
@ -361,6 +376,13 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao
|
|||
* There should already be a lock on the model when this is called.
|
||||
*/
|
||||
private boolean isResourceOfType(OntResource r, OntClass type) {
|
||||
if (r == null) {
|
||||
return false;
|
||||
}
|
||||
if (type == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
StmtIterator stmts = getOntModel().listStatements(r, RDF.type, type);
|
||||
if (stmts.hasNext()) {
|
||||
stmts.close();
|
||||
|
|
|
@ -48,6 +48,11 @@ public class UserAccountsDaoStub implements UserAccountsDao {
|
|||
"UserAccountsDaoStub.getUserAccountByEmail() not implemented.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRootUser(UserAccount userAccount) {
|
||||
throw new RuntimeException("UserAccountsDao.isRootUser() not implemented.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String insertUserAccount(UserAccount userAccount) {
|
||||
throw new RuntimeException(
|
||||
|
|
Loading…
Add table
Reference in a new issue