package edu.harvard.iq.dataverse.authorization.groups.impl.shib; import edu.harvard.iq.dataverse.RoleAssigneeServiceBean; import edu.harvard.iq.dataverse.RoleAssignment; import edu.harvard.iq.dataverse.actionlogging.ActionLogRecord; import edu.harvard.iq.dataverse.actionlogging.ActionLogServiceBean; import edu.harvard.iq.dataverse.authorization.groups.GroupServiceBean; import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Logger; import javax.ejb.EJB; import javax.ejb.Stateless; import javax.inject.Named; import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.NonUniqueResultException; import javax.persistence.PersistenceContext; import javax.persistence.TypedQuery; /** * @todo Consider merging this bean into the newer and more generic * ShibServiceBean. */ @Named @Stateless public class ShibGroupServiceBean { private static final Logger logger = Logger.getLogger(ShibGroupServiceBean.class.getCanonicalName()); @PersistenceContext(unitName = "VDCNet-ejbPU") private EntityManager em; @EJB RoleAssigneeServiceBean roleAssigneeSvc; @EJB GroupServiceBean groupService; @EJB ActionLogServiceBean actionLogSvc; /** * @return A ShibGroup or null. */ public ShibGroup findById(Long id) { TypedQuery<ShibGroup> typedQuery = em.createQuery("SELECT OBJECT(o) FROM ShibGroup o WHERE o.id = :id", ShibGroup.class); typedQuery.setParameter("id", id); try { ShibGroup shibGroup = typedQuery.getSingleResult(); return shibGroup; } catch (NoResultException | NonUniqueResultException ex) { return null; } } public List<ShibGroup> findAll() { TypedQuery<ShibGroup> typedQuery = em.createQuery("SELECT OBJECT(o) FROM ShibGroup as o", ShibGroup.class); return typedQuery.getResultList(); } public ShibGroup save(String name, String shibIdpAttribute, String shibIdp) { ActionLogRecord alr = new ActionLogRecord(ActionLogRecord.ActionType.GlobalGroups, "shibCreate"); alr.setInfo( name + ": " + shibIdp + "/" + shibIdpAttribute ); ShibGroup institutionalGroup = new ShibGroup(name, shibIdpAttribute, shibIdp, groupService.getShibGroupProvider()); em.persist(institutionalGroup); em.flush(); ShibGroup merged = em.merge(institutionalGroup); actionLogSvc.log(alr); return merged; } public Set<ShibGroup> findFor(AuthenticatedUser authenticatedUser) { Set<ShibGroup> groupsForUser = new HashSet<>(); String shibIdp = authenticatedUser.getShibIdentityProvider(); logger.fine("IdP for user " + authenticatedUser.getIdentifier() + " is " + shibIdp); if (shibIdp != null) { /** * @todo Rather than a straight string equality match, we have a * requirement to support regular expressions: * https://docs.google.com/document/d/12Qru8Gjq4oDUiodI00oObHJog65S7QzFfFZuPU3n8aU/edit?usp=sharing */ TypedQuery<ShibGroup> typedQuery = em.createQuery("SELECT OBJECT(o) FROM ShibGroup as o WHERE o.pattern =:shibIdP", ShibGroup.class); typedQuery.setParameter("shibIdP", shibIdp); List<ShibGroup> matches = typedQuery.getResultList(); groupsForUser.addAll(matches); } /** * @todo In addition to supporting institution-wide Shibboleth groups * (Harvard, UNC, etc.), allow arbitrary Shibboleth attributes to be * matched (with a regex) such as "memberOf" etc. */ return groupsForUser; } public boolean delete(ShibGroup doomed) throws Exception { ActionLogRecord alr = new ActionLogRecord(ActionLogRecord.ActionType.GlobalGroups, "shibDelete"); alr.setInfo( doomed.getName() + ":" + doomed.getIdentifier() ); List<RoleAssignment> assignments = roleAssigneeSvc.getAssignmentsFor(doomed.getIdentifier()); if (assignments.isEmpty()) { em.remove(doomed); actionLogSvc.log( alr ); return true; } else { /** * @todo Delete role assignments that match this Shib group. */ List<String> assignmentIds = new ArrayList<>(); for (RoleAssignment assignment : assignments) { assignmentIds.add(assignment.getId().toString()); } String message = "Could not delete Shibboleth group id " + doomed.getId() + " due to existing role assignments: " + assignmentIds; logger.info(message); actionLogSvc.log( alr.setActionResult(ActionLogRecord.Result.BadRequest) .setInfo( alr.getInfo() + "// " + message ) ); throw new Exception(message); } } }