package edu.harvard.iq.dataverse;
import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean;
import edu.harvard.iq.dataverse.authorization.DataverseRole;
import edu.harvard.iq.dataverse.authorization.RoleAssignee;
import edu.harvard.iq.dataverse.authorization.groups.Group;
import edu.harvard.iq.dataverse.authorization.groups.GroupServiceBean;
import edu.harvard.iq.dataverse.authorization.groups.impl.builtin.AllUsers;
import edu.harvard.iq.dataverse.authorization.groups.impl.builtin.AuthenticatedUsers;
import edu.harvard.iq.dataverse.authorization.groups.impl.explicit.ExplicitGroup;
import edu.harvard.iq.dataverse.authorization.groups.impl.explicit.ExplicitGroupServiceBean;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.authorization.users.GuestUser;
import edu.harvard.iq.dataverse.engine.command.DataverseRequest;
import edu.harvard.iq.dataverse.mydata.MyDataFilterParams;
import edu.harvard.iq.dataverse.privateurl.PrivateUrlUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.commons.lang.StringUtils;
/**
* The place to obtain {@link RoleAssignee}s, based on their identifiers.
*
* @author michael
*/
@Stateless
@Named
public class RoleAssigneeServiceBean {
private static final Logger logger = Logger.getLogger(RoleAssigneeServiceBean.class.getName());
@PersistenceContext(unitName = "VDCNet-ejbPU")
private EntityManager em;
@EJB
AuthenticationServiceBean authSvc;
@EJB
GroupServiceBean groupSvc;
@EJB
ExplicitGroupServiceBean explicitGroupSvc;
@EJB
DataverseRoleServiceBean dataverseRoleService;
protected Map<String, RoleAssignee> predefinedRoleAssignees = new TreeMap<>();
@PostConstruct
protected void setup() {
GuestUser gu = GuestUser.get();
predefinedRoleAssignees.put(gu.getIdentifier(), gu);
predefinedRoleAssignees.put(AuthenticatedUsers.get().getIdentifier(), AuthenticatedUsers.get());
predefinedRoleAssignees.put(AllUsers.get().getIdentifier(), AllUsers.get());
}
/**
* @param identifier An identifier beginning with ":" (builtin), "@"
* ({@link AuthenticatedUser}), "&" ({@link Group}), or "#"
* ({@link PrivateUrlUser}).
*
* @return A RoleAssignee (User or Group) or null.
*
* @throws IllegalArgumentException if you pass null, empty string, or an
* identifier that doesn't start with one of the supported characters.
*/
public RoleAssignee getRoleAssignee(String identifier) {
if (identifier == null || identifier.isEmpty()) {
throw new IllegalArgumentException("Identifier cannot be null or empty string.");
}
switch (identifier.charAt(0)) {
case ':':
return predefinedRoleAssignees.get(identifier);
case '@':
return authSvc.getAuthenticatedUser(identifier.substring(1));
case '&':
return groupSvc.getGroup(identifier.substring(1));
case '#':
return PrivateUrlUtil.identifier2roleAssignee(identifier);
default:
throw new IllegalArgumentException("Unsupported assignee identifier '" + identifier + "'");
}
}
public List<RoleAssignment> getAssignmentsFor(String roleAssigneeIdentifier) {
return em.createNamedQuery("RoleAssignment.listByAssigneeIdentifier", RoleAssignment.class)
.setParameter("assigneeIdentifier", roleAssigneeIdentifier)
.getResultList();
}
public List<AuthenticatedUser> getExplicitUsers(RoleAssignee ra) {
List<AuthenticatedUser> explicitUsers = new ArrayList();
if (ra instanceof AuthenticatedUser) {
explicitUsers.add((AuthenticatedUser) ra);
} else if (ra instanceof ExplicitGroup) {
ExplicitGroup group = (ExplicitGroup) ra;
for (String raIdentifier : group.getContainedRoleAssgineeIdentifiers()) {
explicitUsers.addAll(getExplicitUsers(getRoleAssignee(raIdentifier)));
}
}
return explicitUsers;
}
private String getRoleIdListClause(List<Long> roleIdList) {
if (roleIdList == null) {
return "";
}
List<String> outputList = new ArrayList<>();
for (Long r : roleIdList) {
if (r != null) {
outputList.add(r.toString());
}
}
if (outputList.isEmpty()) {
return "";
}
return " AND r.role_id IN (" + StringUtils.join(outputList, ",") + ")";
}
public List<DataverseRole> getAssigneeDataverseRoleFor(DataverseRequest dataverseRequest) {
if (dataverseRequest == null){
throw new NullPointerException("dataverseRequest cannot be null!");
}
AuthenticatedUser au = dataverseRequest.getAuthenticatedUser();
if (au.getUserIdentifier() == null){
return null;
}
String roleAssigneeIdentifier = "@" + au.getUserIdentifier();
List<DataverseRole> retList = new ArrayList();
roleAssigneeIdentifier = roleAssigneeIdentifier.replaceAll("\\s", ""); // remove spaces from string
List<String> userGroups = getUserExplicitGroups(au);
List<String> userRunTimeGroups = getUserRuntimeGroups(dataverseRequest);
String identifierClause = " WHERE r.assigneeIdentifier= '" + roleAssigneeIdentifier + "'";
if (userGroups != null || userRunTimeGroups != null) {
identifierClause = getGroupIdentifierClause(roleAssigneeIdentifier, userGroups, userRunTimeGroups);
}
String qstr = "SELECT distinct r.role_id";
qstr += " FROM RoleAssignment r";
qstr += identifierClause;
qstr += ";";
msg("qstr: " + qstr);
for (Object o : em.createNativeQuery(qstr).getResultList()) {
retList.add(dataverseRoleService.find((Long) o));
}
return retList;
}
public List<Object[]> getAssigneeAndRoleIdListFor(MyDataFilterParams filterParams) {
if (filterParams == null){
throw new NullPointerException("Cannot be null! filterParams must be an instance of MyDataFilterParams");
}
AuthenticatedUser au = filterParams.getAuthenticatedUser();
List<Long> roleIdList = filterParams.getRoleIds();
//filterParams.getAuthenticatedUser()
// , this.filterParams.getRoleIds());
if (au.getUserIdentifier() == null) {
return null;
}
String roleAssigneeIdentifier = "@" + au.getUserIdentifier();
roleAssigneeIdentifier = roleAssigneeIdentifier.replaceAll("\\s", ""); // remove spaces from string
List<String> userExplicitGroups = getUserExplicitGroups(au);
List<String> userRunTimeGroups = getUserRuntimeGroups(filterParams.getDataverseRequest());
String identifierClause = " WHERE r.assigneeIdentifier= '" + roleAssigneeIdentifier + "'";
if (userExplicitGroups != null || userRunTimeGroups != null) {
identifierClause = getGroupIdentifierClause(roleAssigneeIdentifier, userExplicitGroups, userRunTimeGroups);
}
String qstr = "SELECT r.definitionpoint_id, r.role_id";
qstr += " FROM RoleAssignment r";
qstr += identifierClause;
qstr += getRoleIdListClause(roleIdList);
qstr += ";";
msg("qstr: " + qstr);
return em.createNativeQuery(qstr)
.getResultList();
}
public List<Long> getRoleIdListForGivenAssigneeDvObject(DataverseRequest dataverseRequest, List<Long> roleIdList, Long defPointId) {
if (dataverseRequest == null){
throw new NullPointerException("dataverseRequest cannot be null!");
}
AuthenticatedUser au = dataverseRequest.getAuthenticatedUser();
if (au.getUserIdentifier() == null){
return null;
}
String roleAssigneeIdentifier = "@" + au.getUserIdentifier();
roleAssigneeIdentifier = roleAssigneeIdentifier.replaceAll("\\s", ""); // remove spaces from string
List<String> userGroups = getUserExplicitGroups(au);
List<String> userRunTimeGroups = getUserRuntimeGroups(dataverseRequest);
String identifierClause = " WHERE r.assigneeIdentifier= '" + roleAssigneeIdentifier + "'";
if (userGroups != null || userRunTimeGroups != null) {
identifierClause = getGroupIdentifierClause(roleAssigneeIdentifier, userGroups, userRunTimeGroups);
}
String qstr = "SELECT r.role_id";
qstr += " FROM RoleAssignment r";
qstr += identifierClause;
qstr += getRoleIdListClause(roleIdList);
qstr += " and r.definitionpoint_id = " + defPointId;
qstr += ";";
msg("qstr: " + qstr);
return em.createNativeQuery(qstr)
.getResultList();
}
private String getGroupIdentifierClause(String roleAssigneeIdentifier, List<String> userExplicitGroups, List<String> userRunTimeGroups) {
if (userExplicitGroups == null && userRunTimeGroups == null) {
return "";
}
List<String> outputExplicitList = new ArrayList<>();
String explicitString = "";
if (userExplicitGroups != null) {
for (String r : userExplicitGroups) {
if (r != null) {
outputExplicitList.add(r);
}
}
if (!outputExplicitList.isEmpty()) {
explicitString = ",'&explicit/" + StringUtils.join(outputExplicitList, "','&explicit/") + "'";
}
}
List<String> outputRuntimeList = new ArrayList<>();
String runTimeString = "";
if (userRunTimeGroups != null) {
for (String r : userRunTimeGroups) {
if (r != null) {
outputRuntimeList.add(r);
}
}
if (!outputRuntimeList.isEmpty()) {
runTimeString = ",'" + StringUtils.join(outputRuntimeList, "','") + "'";
}
}
return " WHERE r.assigneeIdentifier in ( '" + roleAssigneeIdentifier + "'" + explicitString + runTimeString + ")";
}
public List<Object[]> getRoleIdsFor(DataverseRequest dataverseRequest, List<Long> dvObjectIdList) {
if (dataverseRequest == null){
throw new NullPointerException("dataverseRequest cannot be null!");
}
AuthenticatedUser au = dataverseRequest.getAuthenticatedUser();
if (au.getUserIdentifier() == null){
return null;
}
String roleAssigneeIdentifier = "@" + au.getUserIdentifier();
roleAssigneeIdentifier = roleAssigneeIdentifier.replaceAll("\\s", ""); // remove spaces from string
List<String> userGroups = getUserExplicitGroups(au);
List<String> userRunTimeGroups = getUserRuntimeGroups(dataverseRequest);
String identifierClause = " WHERE r.assigneeIdentifier= '" + roleAssigneeIdentifier + "'";
if (userGroups != null || userRunTimeGroups != null) {
identifierClause = getGroupIdentifierClause(roleAssigneeIdentifier, userGroups, userRunTimeGroups);
}
String qstr = "SELECT r.definitionpoint_id, r.role_id";
qstr += " FROM RoleAssignment r";
qstr += identifierClause;
qstr += getDvObjectIdListClause(dvObjectIdList);
qstr += ";";
//msg("qstr: " + qstr);
return em.createNativeQuery(qstr)
.getResultList();
}
private String getDvObjectIdListClause(List<Long> dvObjectIdList) {
if (dvObjectIdList == null) {
return "";
}
List<String> outputList = new ArrayList<>();
for (Long r : dvObjectIdList) {
if (r != null) {
outputList.add(r.toString());
}
}
if (outputList.isEmpty()) {
return "";
}
return " AND r.definitionpoint_id IN (" + StringUtils.join(outputList, ",") + ")";
}
/**
* @param ra
* @todo Support groups within groups: https://github.com/IQSS/dataverse/issues/3056
* @return List of aliases of all explicit groups {@code ra} is in.
*/
public List<String> getUserExplicitGroups(RoleAssignee ra) {
return explicitGroupSvc.findGroups(ra).stream()
.map( g -> g.getAlias())
.collect(Collectors.toList());
}
private List<String> getUserRuntimeGroups(DataverseRequest dataverseRequest) {
List<String> retVal = new ArrayList();
//Set<Group> groups = groupSvc.groupsFor(dataverseRequest, null);
Set<Group> groups = groupSvc.collectAncestors(groupSvc.groupsFor(dataverseRequest));
for (Group group : groups) {
logger.fine("found group " + group.getIdentifier() + " with alias " + group.getAlias());
// if (group.getGroupProvider().getGroupProviderAlias().equals("shib") || group.getGroupProvider().getGroupProviderAlias().equals("ip")) {
String groupAlias = group.getAlias();
if (groupAlias != null && !groupAlias.isEmpty()) {
if( group instanceof ExplicitGroup){
retVal.add("&explicit/" + groupAlias);
} else{
retVal.add('&' + groupAlias);
}
}
//}
}
logger.fine("retVal: " + retVal);
return retVal;
}
public List<RoleAssignee> filterRoleAssignees(String query, DvObject dvObject, List<RoleAssignee> roleAssignSelectedRoleAssignees) {
List<RoleAssignee> roleAssigneeList = new ArrayList<>();
// we get the users through a query that does the filtering through the db,
// so that we don't have to instantiate all of the RoleAssignee objects
em.createNamedQuery("AuthenticatedUser.filter", AuthenticatedUser.class)
.setParameter("query", "%" + query + "%")
.getResultList().stream()
.filter(ra -> roleAssignSelectedRoleAssignees == null || !roleAssignSelectedRoleAssignees.contains(ra))
.forEach((ra) -> {
roleAssigneeList.add(ra);
});
// now we add groups to the list, both global and explicit
Set<Group> groups = groupSvc.findGlobalGroups();
groups.addAll(explicitGroupSvc.findAvailableFor(dvObject));
groups.stream()
.filter(ra -> StringUtils.containsIgnoreCase(ra.getDisplayInfo().getTitle(), query)
|| StringUtils.containsIgnoreCase(ra.getIdentifier(), query))
.filter(ra -> roleAssignSelectedRoleAssignees == null || !roleAssignSelectedRoleAssignees.contains(ra))
.forEach((ra) -> {
roleAssigneeList.add(ra);
});
return roleAssigneeList;
}
private void msg(String s) {
//System.out.println(s);
}
private void msgt(String s) {
msg("-------------------------------");
msg(s);
msg("-------------------------------");
}
}