Java tutorial
/* * Copyright (C) 2011 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.opendatakit.common.security.server; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.opendatakit.common.persistence.CommonFieldsBase; import org.opendatakit.common.persistence.Datastore; import org.opendatakit.common.persistence.Query; import org.opendatakit.common.persistence.client.exception.DatastoreFailureException; import org.opendatakit.common.persistence.exception.ODKDatastoreException; import org.opendatakit.common.security.SecurityBeanDefs; import org.opendatakit.common.security.SecurityUtils; import org.opendatakit.common.security.User; import org.opendatakit.common.security.client.CredentialsInfo; import org.opendatakit.common.security.client.UserSecurityInfo; import org.opendatakit.common.security.client.UserSecurityInfo.UserType; import org.opendatakit.common.security.client.exception.AccessDeniedException; import org.opendatakit.common.security.common.EmailParser; import org.opendatakit.common.security.common.GrantedAuthorityName; import org.opendatakit.common.security.spring.*; import org.opendatakit.common.web.CallingContext; import org.springframework.security.access.hierarchicalroles.RoleHierarchy; import org.springframework.security.authentication.encoding.MessageDigestPasswordEncoder; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; /** * Common utility methods extracted from the AccessConfigurationServlet so they * can be shared between the servlet and GWT server classes. * * @author mitchellsundt@gmail.com * */ public class SecurityServiceUtil { private static final Log logger = LogFactory.getLog(SecurityServiceUtil.class.getName()); private static final Set<String> specialNames = new HashSet<String>(); public static final GrantedAuthority siteAuth = new SimpleGrantedAuthority( GrantedAuthorityName.GROUP_SITE_ADMINS.name()); public static final List<String> siteAdministratorGrants; public static final GrantedAuthority dataOwnerAuth = new SimpleGrantedAuthority( GrantedAuthorityName.GROUP_FORM_MANAGERS.name()); public static final List<String> dataOwnerGrants; public static final GrantedAuthority administerTablesAuth = new SimpleGrantedAuthority( GrantedAuthorityName.GROUP_ADMINISTER_TABLES.name()); public static final List<String> administerTablesGrants; public static final GrantedAuthority synchronizeTablesAuth = new SimpleGrantedAuthority( GrantedAuthorityName.GROUP_SYNCHRONIZE_TABLES.name()); public static final List<String> synchronizeTablesGrants; public static final GrantedAuthority dataViewerAuth = new SimpleGrantedAuthority( GrantedAuthorityName.GROUP_DATA_VIEWERS.name()); public static final List<String> dataViewerGrants; public static final GrantedAuthority dataCollectorAuth = new SimpleGrantedAuthority( GrantedAuthorityName.GROUP_DATA_COLLECTORS.name()); public static final List<String> dataCollectorGrants; public static final GrantedAuthority anonAuth = new SimpleGrantedAuthority( GrantedAuthorityName.USER_IS_ANONYMOUS.name()); // special grants for Google Earth work-around public static final List<String> anonAttachmentViewerGrants; static { List<String> isiteAdministratorGrants = new ArrayList<String>(); isiteAdministratorGrants.add(GrantedAuthorityName.ROLE_USER.name()); isiteAdministratorGrants.add(GrantedAuthorityName.ROLE_SITE_ACCESS_ADMIN.name()); isiteAdministratorGrants.add(GrantedAuthorityName.GROUP_ADMINISTER_TABLES.name()); isiteAdministratorGrants.add(GrantedAuthorityName.GROUP_SYNCHRONIZE_TABLES.name()); isiteAdministratorGrants.add(GrantedAuthorityName.GROUP_FORM_MANAGERS.name()); isiteAdministratorGrants.add(GrantedAuthorityName.GROUP_DATA_VIEWERS.name()); siteAdministratorGrants = Collections.unmodifiableList(isiteAdministratorGrants); List<String> iadministerTablesGrants = new ArrayList<String>(); iadministerTablesGrants.add(GrantedAuthorityName.ROLE_USER.name()); iadministerTablesGrants.add(GrantedAuthorityName.ROLE_ADMINISTER_TABLES.name()); iadministerTablesGrants.add(GrantedAuthorityName.GROUP_DATA_VIEWERS.name()); administerTablesGrants = Collections.unmodifiableList(iadministerTablesGrants); List<String> isynchronizeTablesGrants = new ArrayList<String>(); isynchronizeTablesGrants.add(GrantedAuthorityName.ROLE_USER.name()); isynchronizeTablesGrants.add(GrantedAuthorityName.ROLE_SYNCHRONIZE_TABLES.name()); isynchronizeTablesGrants.add(GrantedAuthorityName.GROUP_DATA_VIEWERS.name()); synchronizeTablesGrants = Collections.unmodifiableList(isynchronizeTablesGrants); List<String> idataOwnerGrants = new ArrayList<String>(); idataOwnerGrants.add(GrantedAuthorityName.ROLE_USER.name()); idataOwnerGrants.add(GrantedAuthorityName.ROLE_DATA_OWNER.name()); idataOwnerGrants.add(GrantedAuthorityName.GROUP_DATA_VIEWERS.name()); dataOwnerGrants = Collections.unmodifiableList(idataOwnerGrants); List<String> idataViewerGrants = new ArrayList<String>(); idataViewerGrants.add(GrantedAuthorityName.ROLE_USER.name()); idataViewerGrants.add(GrantedAuthorityName.ROLE_DATA_VIEWER.name()); dataViewerGrants = Collections.unmodifiableList(idataViewerGrants); List<String> idataCollectorGrants = new ArrayList<String>(); idataCollectorGrants.add(GrantedAuthorityName.ROLE_DATA_COLLECTOR.name()); dataCollectorGrants = Collections.unmodifiableList(idataCollectorGrants); // Work-around hack for Google Earth top-level balloon image List<String> ianonAttachmentViewerGrants = new ArrayList<String>(); ianonAttachmentViewerGrants.add(GrantedAuthorityName.ROLE_ATTACHMENT_VIEWER.name()); anonAttachmentViewerGrants = Collections.unmodifiableList(ianonAttachmentViewerGrants); } /** * Return all registered users and the Anonymous user. * * @param withAuthorities * @param cc * @return * @throws AccessDeniedException * @throws DatastoreFailureException */ public static ArrayList<UserSecurityInfo> getAllUsers(boolean withAuthorities, CallingContext cc) throws AccessDeniedException, DatastoreFailureException { ArrayList<UserSecurityInfo> users = new ArrayList<UserSecurityInfo>(); try { Query q = RegisteredUsersTable.createQuery(cc.getDatastore(), "SecurityServiceUtil.getAllUsers", cc.getCurrentUser()); RegisteredUsersTable.applyNaturalOrdering(q, cc); List<? extends CommonFieldsBase> l = q.executeQuery(); for (CommonFieldsBase cb : l) { RegisteredUsersTable t = (RegisteredUsersTable) cb; UserSecurityInfo i = new UserSecurityInfo(t.getUsername(), t.getFullName(), t.getEmail(), UserSecurityInfo.UserType.REGISTERED); if (withAuthorities) { SecurityServiceUtil.setAuthenticationLists(i, t.getUri(), cc); } users.add(i); } // TODO: why doesn't this work? UserSecurityInfo anonymous = new UserSecurityInfo(User.ANONYMOUS_USER, User.ANONYMOUS_USER_NICKNAME, null, UserSecurityInfo.UserType.ANONYMOUS); if (withAuthorities) { SecurityServiceUtil.setAuthenticationListsForSpecialUser(anonymous, GrantedAuthorityName.USER_IS_ANONYMOUS, cc); } users.add(anonymous); } catch (ODKDatastoreException e) { e.printStackTrace(); throw new DatastoreFailureException(e); } // the natural ordering (above) produces a sorted list... return users; } public static HashMap<String, UserSecurityInfo> getUriUserSecurityInfoMap(boolean withAuthorities, CallingContext cc) throws AccessDeniedException, DatastoreFailureException { HashMap<String, UserSecurityInfo> users = new HashMap<String, UserSecurityInfo>(); try { Query q = RegisteredUsersTable.createQuery(cc.getDatastore(), "SecurityServiceUtil.getAllUsers", cc.getCurrentUser()); RegisteredUsersTable.applyNaturalOrdering(q, cc); List<? extends CommonFieldsBase> l = q.executeQuery(); for (CommonFieldsBase cb : l) { RegisteredUsersTable t = (RegisteredUsersTable) cb; UserSecurityInfo i = new UserSecurityInfo(t.getUsername(), t.getFullName(), t.getEmail(), UserSecurityInfo.UserType.REGISTERED); if (withAuthorities) { SecurityServiceUtil.setAuthenticationLists(i, t.getUri(), cc); } users.put(t.getUri(), i); } // TODO: why doesn't this work? UserSecurityInfo anonymous = new UserSecurityInfo(User.ANONYMOUS_USER, User.ANONYMOUS_USER_NICKNAME, null, UserSecurityInfo.UserType.ANONYMOUS); if (withAuthorities) { SecurityServiceUtil.setAuthenticationListsForSpecialUser(anonymous, GrantedAuthorityName.USER_IS_ANONYMOUS, cc); } users.put(User.ANONYMOUS_USER, anonymous); } catch (ODKDatastoreException e) { e.printStackTrace(); throw new DatastoreFailureException(e); } return users; } static GrantedAuthorityName mapName(GrantedAuthority auth, Set<GrantedAuthority> badGrants) { GrantedAuthorityName name = null; try { name = GrantedAuthorityName.valueOf(auth.getAuthority()); } catch (Exception e) { badGrants.add(auth); } return name; } /** * During upgrades or other operations, we may change the set of granted * authorities (the valid set are identified by GrantedAuthorityNames). Remove * the bad grants wherever we find them... * * @param badGrants * @throws ODKDatastoreException */ static void removeBadGrantedAuthorities(Set<GrantedAuthority> badGrants, CallingContext cc) throws ODKDatastoreException { ArrayList<String> empty = new ArrayList<String>(); for (GrantedAuthority auth : badGrants) { UserGrantedAuthority.assertGrantedAuthorityMembers(auth, empty, cc); } } static void setAuthenticationLists(UserSecurityInfo userInfo, String uriUser, CallingContext cc) throws ODKDatastoreException { Datastore ds = cc.getDatastore(); User user = cc.getCurrentUser(); RoleHierarchy hierarchy = (RoleHierarchy) cc.getBean("hierarchicalRoleRelationships"); Set<GrantedAuthority> grants = UserGrantedAuthority.getGrantedAuthorities(uriUser, ds, user); Set<GrantedAuthority> badGrants = new TreeSet<GrantedAuthority>(); TreeSet<GrantedAuthorityName> groups = new TreeSet<GrantedAuthorityName>(); TreeSet<GrantedAuthorityName> authorities = new TreeSet<GrantedAuthorityName>(); for (GrantedAuthority grant : grants) { GrantedAuthorityName name = mapName(grant, badGrants); if (name != null) { if (GrantedAuthorityName.permissionsCanBeAssigned(grant.getAuthority())) { groups.add(name); } else { authorities.add(name); } } } Collection<? extends GrantedAuthority> auths = hierarchy.getReachableGrantedAuthorities(grants); for (GrantedAuthority auth : auths) { GrantedAuthorityName name = mapName(auth, badGrants); if (name != null && !GrantedAuthorityName.permissionsCanBeAssigned(auth.getAuthority())) { authorities.add(name); } } userInfo.setAssignedUserGroups(groups); userInfo.setGrantedAuthorities(authorities); removeBadGrantedAuthorities(badGrants, cc); } static void setAuthenticationListsForSpecialUser(UserSecurityInfo userInfo, GrantedAuthorityName specialGroup, CallingContext cc) throws DatastoreFailureException { RoleHierarchy hierarchy = (RoleHierarchy) cc.getBean("hierarchicalRoleRelationships"); Set<GrantedAuthority> badGrants = new TreeSet<GrantedAuthority>(); // The assigned groups are the specialGroup that this user defines // (i.e., anonymous or daemon) plus all directly-assigned assignable // permissions. TreeSet<GrantedAuthorityName> groups = new TreeSet<GrantedAuthorityName>(); TreeSet<GrantedAuthorityName> authorities = new TreeSet<GrantedAuthorityName>(); groups.add(specialGroup); GrantedAuthority specialAuth = new SimpleGrantedAuthority(specialGroup.name()); try { Set<GrantedAuthority> auths = GrantedAuthorityHierarchyTable .getSubordinateGrantedAuthorities(specialAuth, cc); for (GrantedAuthority auth : auths) { GrantedAuthorityName name = mapName(auth, badGrants); if (name != null) { groups.add(name); } } } catch (ODKDatastoreException e) { e.printStackTrace(); throw new DatastoreFailureException("Unable to retrieve granted authorities of " + specialGroup.name()); } Collection<? extends GrantedAuthority> auths = hierarchy .getReachableGrantedAuthorities(Collections.singletonList(specialAuth)); for (GrantedAuthority auth : auths) { GrantedAuthorityName name = mapName(auth, badGrants); if (name != null && !GrantedAuthorityName.permissionsCanBeAssigned(auth.getAuthority())) { authorities.add(name); } } userInfo.setAssignedUserGroups(groups); userInfo.setGrantedAuthorities(authorities); try { removeBadGrantedAuthorities(badGrants, cc); } catch (ODKDatastoreException e) { e.printStackTrace(); } } /** * Get the complete set of granted authorities (ROLE and RUN_AS grants) this user possesses. * * @param cc * @return * @throws ODKDatastoreException */ public static TreeSet<GrantedAuthorityName> getCurrentUserSecurityInfo(CallingContext cc) throws ODKDatastoreException { User user = cc.getCurrentUser(); TreeSet<GrantedAuthorityName> authorities = new TreeSet<GrantedAuthorityName>(); if (user.isAnonymous()) { RoleHierarchy hierarchy = (RoleHierarchy) cc.getBean("hierarchicalRoleRelationships"); Set<GrantedAuthority> badGrants = new TreeSet<GrantedAuthority>(); // The assigned groups are the specialGroup that this user defines // (i.e., anonymous or daemon) plus all directly-assigned assignable // permissions. GrantedAuthority specialAuth = new SimpleGrantedAuthority( GrantedAuthorityName.USER_IS_ANONYMOUS.name()); Collection<? extends GrantedAuthority> auths = hierarchy .getReachableGrantedAuthorities(Collections.singletonList(specialAuth)); for (GrantedAuthority auth : auths) { GrantedAuthorityName name = mapName(auth, badGrants); if (name != null && !GrantedAuthorityName.permissionsCanBeAssigned(auth.getAuthority())) { authorities.add(name); } } removeBadGrantedAuthorities(badGrants, cc); } else { RegisteredUsersTable t; t = RegisteredUsersTable.getUserByUri(user.getUriUser(), cc.getDatastore(), user); Datastore ds = cc.getDatastore(); RoleHierarchy hierarchy = (RoleHierarchy) cc.getBean("hierarchicalRoleRelationships"); Set<GrantedAuthority> grants = UserGrantedAuthority.getGrantedAuthorities(user.getUriUser(), ds, user); Set<GrantedAuthority> badGrants = new TreeSet<GrantedAuthority>(); TreeSet<GrantedAuthorityName> groups = new TreeSet<GrantedAuthorityName>(); for (GrantedAuthority grant : grants) { GrantedAuthorityName name = mapName(grant, badGrants); if (name != null) { if (GrantedAuthorityName.permissionsCanBeAssigned(grant.getAuthority())) { groups.add(name); } else { authorities.add(name); } } } Collection<? extends GrantedAuthority> auths = hierarchy.getReachableGrantedAuthorities(grants); for (GrantedAuthority auth : auths) { GrantedAuthorityName name = mapName(auth, badGrants); if (name != null && !GrantedAuthorityName.permissionsCanBeAssigned(auth.getAuthority())) { authorities.add(name); } } removeBadGrantedAuthorities(badGrants, cc); } return authorities; } public static final synchronized boolean isSpecialName(String authority) { if (SecurityServiceUtil.specialNames.isEmpty()) { for (GrantedAuthorityName n : GrantedAuthorityName.values()) { SecurityServiceUtil.specialNames.add(n.name()); } } return SecurityServiceUtil.specialNames.contains(authority) || authority.startsWith(GrantedAuthorityName.RUN_AS_PREFIX) || authority.startsWith(GrantedAuthorityName.ROLE_PREFIX); } /** * Construct and return the Email object for the superUser. * * @param cc * @return */ public static final EmailParser.Email getSuperUserEmail(CallingContext cc) { String suEmail = cc.getUserService().getSuperUserEmail(); if (suEmail == null) { return null; } return new EmailParser.Email( suEmail.substring(SecurityUtils.MAILTO_COLON.length(), suEmail.indexOf(SecurityUtils.AT_SIGN)), suEmail); } /** * Given a collection of users, ensure that each user is a registered user * (creating a registered user if one doesn't exist). </p> * <p> * The collection is assumed to be exhaustive. Users not in the list will be * deleted. * </p> * * @param users * @param cc * @return map of users to their Uri strings * @throws DatastoreFailureException * @throws AccessDeniedException */ private static Map<UserSecurityInfo, String> setUsers(ArrayList<UserSecurityInfo> users, CallingContext cc) throws DatastoreFailureException, AccessDeniedException { List<UserSecurityInfo> allUsersList = getAllUsers(false, cc); Set<UserSecurityInfo> removedUsers = new TreeSet<UserSecurityInfo>(); removedUsers.addAll(allUsersList); removedUsers.removeAll(users); Datastore ds = cc.getDatastore(); User user = cc.getCurrentUser(); Map<UserSecurityInfo, String> pkMap = new HashMap<UserSecurityInfo, String>(); try { // mark absent users as removed... for (UserSecurityInfo u : removedUsers) { if (u.getType() != UserType.REGISTERED) continue; RegisteredUsersTable t; if (u.getUsername() == null) { t = RegisteredUsersTable.getUniqueUserByEmail(u.getEmail(), ds, user); } else { t = RegisteredUsersTable.getUniqueUserByUsername(u.getUsername(), ds, user); } if (t != null) { t.setIsRemoved(true); ds.putEntity(t, user); } } // go through all other users. Assert that they exist. // This will update the fields to match those specified. for (UserSecurityInfo u : users) { if (u.getType() != UserType.REGISTERED) continue; RegisteredUsersTable t = RegisteredUsersTable.assertActiveUserByUserSecurityInfo(u, cc); pkMap.put(u, t.getUri()); } } catch (ODKDatastoreException e) { e.printStackTrace(); throw new DatastoreFailureException("Incomplete security update", e); } return pkMap; } /** * Given a collection of users, ensure that each user is a registered user * (creating a registered user if one doesn't exist) and assign those users to * the granted authority. * <p> * The collection is assumed to be exhaustive. If there are other e-mails * already assigned to the granted authority, they will be removed so that * exactly the passed-in set of users are assigned to the authority, no more, * no less. * </p> * * @param users * @param auth * @param cc * @throws DatastoreFailureException */ private static void setUsersOfGrantedAuthority(Map<UserSecurityInfo, String> pkMap, GrantedAuthority auth, CallingContext cc) throws DatastoreFailureException { Set<GrantedAuthority> badGrants = new TreeSet<GrantedAuthority>(); GrantedAuthorityName name = mapName(auth, badGrants); if (name != null) { // build the set of uriUsers for this granted authority... TreeSet<String> desiredMembers = new TreeSet<String>(); for (Map.Entry<UserSecurityInfo, String> u : pkMap.entrySet()) { UserSecurityInfo info = u.getKey(); String uriUser = u.getValue(); if (info.getAssignedUserGroups().contains(name)) { desiredMembers.add(uriUser); } } // assert that the authority has exactly this set of uriUsers (no more, no // less) try { UserGrantedAuthority.assertGrantedAuthorityMembers(auth, desiredMembers, cc); } catch (ODKDatastoreException e) { e.printStackTrace(); throw new DatastoreFailureException("Incomplete security update", e); } } else { try { removeBadGrantedAuthorities(badGrants, cc); } catch (ODKDatastoreException e) { e.printStackTrace(); throw new DatastoreFailureException("Incomplete security update", e); } } } /** * Method to enforce an access configuration constraining only registered * users, authenticated users and anonymous access. * * @param users * @param anonGrants * @param allGroups * @param cc * @throws DatastoreFailureException * @throws AccessDeniedException */ public static final void setStandardSiteAccessConfiguration(ArrayList<UserSecurityInfo> users, ArrayList<GrantedAuthorityName> allGroups, CallingContext cc) throws DatastoreFailureException, AccessDeniedException { List<String> anonGrantStrings = new ArrayList<String>(); for (UserSecurityInfo i : users) { if (i.getType() == UserType.ANONYMOUS) { for (GrantedAuthorityName a : i.getAssignedUserGroups()) { if (anonAuth.getAuthority().equals(a.name())) continue; // avoid circularity... anonGrantStrings.add(a.name()); } break; } } try { GrantedAuthorityHierarchyTable.assertGrantedAuthorityHierarchy(siteAuth, SecurityServiceUtil.siteAdministratorGrants, cc); GrantedAuthorityHierarchyTable.assertGrantedAuthorityHierarchy(administerTablesAuth, SecurityServiceUtil.administerTablesGrants, cc); GrantedAuthorityHierarchyTable.assertGrantedAuthorityHierarchy(synchronizeTablesAuth, SecurityServiceUtil.synchronizeTablesGrants, cc); GrantedAuthorityHierarchyTable.assertGrantedAuthorityHierarchy(dataOwnerAuth, SecurityServiceUtil.dataOwnerGrants, cc); GrantedAuthorityHierarchyTable.assertGrantedAuthorityHierarchy(dataViewerAuth, SecurityServiceUtil.dataViewerGrants, cc); GrantedAuthorityHierarchyTable.assertGrantedAuthorityHierarchy(dataCollectorAuth, SecurityServiceUtil.dataCollectorGrants, cc); GrantedAuthorityHierarchyTable.assertGrantedAuthorityHierarchy(anonAuth, anonGrantStrings, cc); TreeSet<String> authorities = GrantedAuthorityHierarchyTable .getAllPermissionsAssignableGrantedAuthorities(cc.getDatastore(), cc.getCurrentUser()); authorities.remove(siteAuth.getAuthority()); authorities.remove(administerTablesAuth.getAuthority()); authorities.remove(synchronizeTablesAuth.getAuthority()); authorities.remove(dataOwnerAuth.getAuthority()); authorities.remove(dataViewerAuth.getAuthority()); authorities.remove(dataCollectorAuth.getAuthority()); authorities.remove(anonAuth.getAuthority()); // remove anything else from database... List<String> empty = Collections.emptyList(); for (String s : authorities) { GrantedAuthorityHierarchyTable.assertGrantedAuthorityHierarchy(new SimpleGrantedAuthority(s), empty, cc); } Map<UserSecurityInfo, String> pkMap = setUsers(users, cc); setUsersOfGrantedAuthority(pkMap, siteAuth, cc); setUsersOfGrantedAuthority(pkMap, administerTablesAuth, cc); setUsersOfGrantedAuthority(pkMap, synchronizeTablesAuth, cc); setUsersOfGrantedAuthority(pkMap, dataOwnerAuth, cc); setUsersOfGrantedAuthority(pkMap, dataViewerAuth, cc); setUsersOfGrantedAuthority(pkMap, dataCollectorAuth, cc); } catch (ODKDatastoreException e) { e.printStackTrace(); throw new DatastoreFailureException("Incomplete update"); } finally { Datastore ds = cc.getDatastore(); User user = cc.getCurrentUser(); try { SecurityRevisionsTable.setLastRegisteredUsersRevisionDate(ds, user); } catch (ODKDatastoreException e) { // if it fails, use RELOAD_INTERVAL to force reload. e.printStackTrace(); } try { SecurityRevisionsTable.setLastRoleHierarchyRevisionDate(ds, user); } catch (ODKDatastoreException e) { // if it fails, use RELOAD_INTERVAL to force reload. e.printStackTrace(); } } } public static final void setUserCredentials(CredentialsInfo credential, CallingContext cc) throws AccessDeniedException, DatastoreFailureException { Datastore ds = cc.getDatastore(); User user = cc.getUserService().getCurrentUser(); RegisteredUsersTable userDefinition = null; try { userDefinition = RegisteredUsersTable.getUserByUsername(credential.getUsername(), cc.getUserService(), ds); if (userDefinition == null) { throw new AccessDeniedException("User is not a registered user."); } userDefinition.setDigestAuthPassword(credential.getDigestAuthHash()); userDefinition.setBasicAuthPassword(credential.getBasicAuthHash()); userDefinition.setBasicAuthSalt(credential.getBasicAuthSalt()); ds.putEntity(userDefinition, user); } catch (ODKDatastoreException e) { e.printStackTrace(); throw new DatastoreFailureException(e.getMessage()); } } /** * Configures the server to have the default role names and role hierarchy. * * @param cc * @throws DatastoreFailureException * @throws AccessDeniedException */ public static final void setDefaultRoleNamesAndHierarchy(CallingContext cc) throws DatastoreFailureException, AccessDeniedException { ArrayList<UserSecurityInfo> users = new ArrayList<UserSecurityInfo>(); ArrayList<GrantedAuthorityName> allGroups = new ArrayList<GrantedAuthorityName>(); // Grant the Anonymous user the ability to submit data to ODK Aggregate // Enables users to anonymously publish from ODK Collect into ODK Aggregate UserSecurityInfo anonymous = new UserSecurityInfo(User.ANONYMOUS_USER, User.ANONYMOUS_USER_NICKNAME, null, UserSecurityInfo.UserType.ANONYMOUS); TreeSet<GrantedAuthorityName> userGroups = new TreeSet<GrantedAuthorityName>(); userGroups.add(GrantedAuthorityName.GROUP_DATA_COLLECTORS); userGroups.add(GrantedAuthorityName.GROUP_FORM_MANAGERS); // issue 710 anonymous.setAssignedUserGroups(userGroups); users.add(anonymous); // NOTE: No users are defined at this point (including the superUser) see // superUserBootstrap below... setStandardSiteAccessConfiguration(users, allGroups, cc); } /** * Ensures that a (single) registered user record exists for the superUser, * adds that user to the list of site administrators, establishes that user as * the sole user with permanent access to the permissions management tab, and, * if the user is new, it sets a flag to force the user to visit the * permissions tab upon first access to the site (this is done inside * assertSuperUser). * * @param cc * @throws ODKDatastoreException */ public static final synchronized void superUserBootstrap(CallingContext cc) throws ODKDatastoreException { // assert that the superuser exists... MessageDigestPasswordEncoder mde = null; try { Object obj = cc.getBean(SecurityBeanDefs.BASIC_AUTH_PASSWORD_ENCODER); if (obj != null) { mde = (MessageDigestPasswordEncoder) obj; } } catch (Exception e) { mde = null; } List<RegisteredUsersTable> suList = RegisteredUsersTable.assertSuperUsers(mde, cc); Set<String> uriUsers; // add the superuser to the list of site administrators uriUsers = UserGrantedAuthority.getUriUsers(siteAuth, cc.getDatastore(), cc.getCurrentUser()); for (RegisteredUsersTable su : suList) { uriUsers.add(su.getUri()); } UserGrantedAuthority.assertGrantedAuthorityMembers(siteAuth, uriUsers, cc); // assert that the superuser is the only one with permanent access // administration rights... uriUsers.clear(); for (RegisteredUsersTable su : suList) { uriUsers.add(su.getUri()); } UserGrantedAuthority.assertGrantedAuthorityMembers( new SimpleGrantedAuthority(GrantedAuthorityName.ROLE_SITE_ACCESS_ADMIN.name()), uriUsers, cc); } public static void assignUserToForm(List<Long> ids, String formId, CallingContext cc) throws ODKDatastoreException { Datastore ds = cc.getDatastore(); User user = cc.getCurrentUser(); List<CommonFieldsBase> newEntries = new ArrayList<CommonFieldsBase>(); AclTable entryRelation = null; entryRelation = AclTable.assertRelation(ds, user); for (Long id : ids) { AclTable entryAccessRow = ds.createEntityUsingRelation(entryRelation, user); entryAccessRow.setStringField(AclTable.OBJECT_CLASS, AclTable.ProtectedClasses.FORM.getType()); entryAccessRow.setLongField(AclTable.OBJECT_IDENTITY, Long.valueOf(formId)); entryAccessRow.setLongField(AclTable.SID, id); entryAccessRow.setBooleanField(AclTable.GRANTED, true); newEntries.add(entryAccessRow); } ds.putEntities(newEntries, user); } public static ArrayList<UserSecurityInfo> getUsersForForm(String formId, CallingContext cc) throws ODKDatastoreException { Datastore ds = cc.getDatastore(); ArrayList<UserSecurityInfo> results = new ArrayList<UserSecurityInfo>(); List<Long> ids = AclTable.getUserIdsForForm(formId, cc); for (Long id : ids) { RegisteredUsersTable userEntry = RegisteredUsersTable.getUserById(id, cc.getUserService(), ds); logger.warn("We've found for id " + id.toString() + " user " + userEntry); if (userEntry != null) { UserSecurityInfo info = new UserSecurityInfo(userEntry.getUsername(), userEntry.getFullName(), userEntry.getEmail(), UserSecurityInfo.UserType.REGISTERED); results.add(info); } } return results; } public static void removeUsersFromForm(List<Long> ids, String formId, CallingContext cc) throws ODKDatastoreException { for (Long id : ids) { AclTable.deleteEntryForUser(id, Long.valueOf(formId), cc); } } }