protected void updateGroupMembership(
      SlingHttpServletRequest request,
      Session session,
      Authorizable authorizable,
      String paramName,
      List<Modification> changes,
      Map<String, Object> toSave)
      throws AccessDeniedException, StorageClientException {
    if (authorizable instanceof Group) {
      Group group = ((Group) authorizable);
      String groupPath =
          LiteAuthorizableResourceProvider.SYSTEM_USER_MANAGER_GROUP_PREFIX + group.getId();

      boolean changed = false;

      AuthorizableManager authorizableManager = session.getAuthorizableManager();

      // first remove any members posted as ":member@Delete"
      String[] membersToDelete =
          request.getParameterValues(paramName + SlingPostConstants.SUFFIX_DELETE);
      if (membersToDelete != null) {
        toSave.put(group.getId(), group);
        LOGGER.info("Members to delete {} ", membersToDelete);
        for (String member : membersToDelete) {
          String memberId = getAuthIdFromParameter(member);
          group.removeMember(memberId);
          changed = true;
        }
      }

      Joinable groupJoin = getJoinable(group);

      // second add any members posted as ":member"
      String[] membersToAdd = request.getParameterValues(paramName);
      if (membersToAdd != null) {
        LOGGER.info("Members to add {} ", membersToAdd);
        Group peerGroup = getPeerGroupOf(group, authorizableManager, toSave);
        List<Authorizable> membersToRemoveFromPeer = new ArrayList<Authorizable>();
        for (String member : membersToAdd) {
          String memberId = getAuthIdFromParameter(member);
          Authorizable memberAuthorizable = (Authorizable) toSave.get(memberId);
          if (memberAuthorizable == null) {
            memberAuthorizable = authorizableManager.findAuthorizable(memberId);
          }
          if (memberAuthorizable != null) {
            if (!User.ADMIN_USER.equals(session.getUserId())
                && !UserConstants.ANON_USERID.equals(session.getUserId())
                && Joinable.yes.equals(groupJoin)
                && memberAuthorizable.getId().equals(session.getUserId())) {
              LOGGER.debug("Is Joinable {} {} ", groupJoin, session.getUserId());
              // we can grab admin session since group allows all users to join
              Session adminSession = getSession();
              try {
                AuthorizableManager adminAuthorizableManager =
                    adminSession.getAuthorizableManager();
                Group adminAuthGroup =
                    (Group) adminAuthorizableManager.findAuthorizable(group.getId());
                if (adminAuthGroup != null) {
                  adminAuthGroup.addMember(memberAuthorizable.getId());
                  adminAuthorizableManager.updateAuthorizable(adminAuthGroup);
                  changed = true;
                }
              } finally {
                ungetSession(adminSession);
              }
            } else {
              LOGGER.info(
                  "Group {} is not Joinable: User {} adding {}  ",
                  new Object[] {
                    group.getId(), session.getUserId(), memberAuthorizable.getId(),
                  });
              // group is restricted, so use the current user's authorization
              // to add the member to the group:

              group.addMember(memberAuthorizable.getId());
              if (LOGGER.isInfoEnabled()) {
                LOGGER.info(
                    "{} Membership now {} {} {}",
                    new Object[] {
                      group.getId(),
                      Arrays.toString(group.getMembers()),
                      Arrays.toString(group.getMembersAdded()),
                      Arrays.toString(group.getMembersRemoved())
                    });
              }
              toSave.put(group.getId(), group);
              Group gt = (Group) toSave.get(group.getId());
              if (LOGGER.isInfoEnabled()) {
                LOGGER.info(
                    "{} Membership now {} {} {}",
                    new Object[] {
                      group.getId(),
                      Arrays.toString(gt.getMembers()),
                      Arrays.toString(gt.getMembersAdded()),
                      Arrays.toString(gt.getMembersRemoved())
                    });
              }
              changed = true;
            }
            if (peerGroup != null && peerGroup.getId() != group.getId()) {
              Set<String> members = ImmutableSet.of(peerGroup.getMembers());
              if (members.contains(memberAuthorizable.getId())) {
                membersToRemoveFromPeer.add(memberAuthorizable);
              }
            }
          } else {
            LOGGER.warn("member not found {} ", memberId);
          }
        }
        if ((peerGroup != null) && (membersToRemoveFromPeer.size() > 0)) {
          for (Authorizable member : membersToRemoveFromPeer) {
            if (LOGGER.isInfoEnabled()) {
              LOGGER.info("Removing Member {} from {} ", member.getId(), peerGroup.getId());
            }
            peerGroup.removeMember(member.getId());
          }
          toSave.put(peerGroup.getId(), peerGroup);
          if (LOGGER.isInfoEnabled()) {
            LOGGER.info(
                "{} Just Updated Peer Group Membership now {} {} {}",
                new Object[] {
                  peerGroup.getId(),
                  Arrays.toString(peerGroup.getMembers()),
                  Arrays.toString(peerGroup.getMembersAdded()),
                  Arrays.toString(peerGroup.getMembersRemoved())
                });
          }
        }
      }

      if (changed) {
        // add an entry to the changes list to record the membership
        // change
        changes.add(Modification.onModified(groupPath + "/members"));
      }
    }
  }
Ejemplo n.º 2
0
  /*
   * (non-Javadoc)
   * @see
   * org.apache.sling.jackrabbit.usermanager.post.AbstractAuthorizablePostServlet
   * #handleOperation(org.apache.sling.api.SlingHttpServletRequest,
   * org.apache.sling.api.servlets.HtmlResponse, java.util.List)
   */
  @Override
  protected void handleOperation(
      SlingHttpServletRequest request, HtmlResponse response, List<Modification> changes)
      throws RepositoryException {
    // make sure user self-registration is enabled
    if (!selfRegistrationEnabled) {
      throw new RepositoryException(
          "Sorry, registration of new users is not currently enabled.  Please try again later.");
    }

    Session session = request.getResourceResolver().adaptTo(Session.class);
    if (session == null) {
      throw new RepositoryException("JCR Session not found");
    }

    // check that the submitted parameter values have valid values.
    String principalName = request.getParameter(SlingPostConstants.RP_NODE_NAME);
    if (principalName == null) {
      throw new RepositoryException("User name was not submitted");
    }
    String pwd = request.getParameter("pwd");
    if (pwd == null) {
      throw new RepositoryException("Password was not submitted");
    }
    String pwdConfirm = request.getParameter("pwdConfirm");
    if (!pwd.equals(pwdConfirm)) {
      throw new RepositoryException("Password value does not match the confirmation password");
    }

    Session selfRegSession = null;
    try {
      selfRegSession = getSession();

      UserManager userManager = AccessControlUtil.getUserManager(selfRegSession);
      Authorizable authorizable = userManager.getAuthorizable(principalName);

      if (authorizable != null) {
        // user already exists!
        throw new RepositoryException(
            "A principal already exists with the requested name: " + principalName);
      } else {
        Map<String, RequestProperty> reqProperties = collectContent(request, response);

        User user = userManager.createUser(principalName, digestPassword(pwd));
        String userPath =
            AuthorizableResourceProvider.SYSTEM_USER_MANAGER_USER_PREFIX + user.getID();

        response.setPath(userPath);
        response.setLocation(externalizePath(request, userPath));
        response.setParentLocation(
            externalizePath(request, AuthorizableResourceProvider.SYSTEM_USER_MANAGER_USER_PATH));
        changes.add(Modification.onCreated(userPath));

        // write content from form
        writeContent(selfRegSession, user, reqProperties, changes);

        if (selfRegSession.hasPendingChanges()) {
          selfRegSession.save();
        }
      }
    } finally {
      ungetSession(selfRegSession);
    }
  }
  /**
   * {@inheritDoc} This post processor is only interested in posts to messages, so it should iterate
   * rapidly through all messages.
   *
   * @see
   *     org.apache.sling.servlets.post.SlingPostProcessor#process(org.apache.sling.api.SlingHttpServletRequest,
   *     java.util.List)
   */
  public void process(SlingHttpServletRequest request, List<Modification> changes)
      throws Exception {

    Resource resource = request.getResource();
    ResourceResolver resourceResolver = request.getResourceResolver();
    if (SparseContentResource.SPARSE_CONTENT_RT.equals(resource.getResourceSuperType())) {
      Session session = resource.adaptTo(Session.class);
      ContentManager contentManager = session.getContentManager();
      Map<Content, String> messageMap = new HashMap<Content, String>();
      for (Modification m : changes) {
        try {
          switch (m.getType()) {
            case CREATE:
            case MODIFY:
              String path = m.getSource();
              if (path.lastIndexOf("@") > 0) {
                path = path.substring(0, path.lastIndexOf("@"));
              }
              if (path.endsWith("/" + MessageConstants.PROP_SAKAI_MESSAGEBOX)) {
                path =
                    path.substring(
                        0, path.length() - MessageConstants.PROP_SAKAI_MESSAGEBOX.length() - 1);
              }

              // The Modification Source is the Resource path, and so we
              // need to translate that into a Content path.
              // TODO This is not a cheap operation. We might be better off
              // if we start including the Content path in our Modification objects.
              Resource modifiedResource = resourceResolver.getResource(path);
              if (modifiedResource == null) {
                return;
              }
              Content content = modifiedResource.adaptTo(Content.class);
              String contentPath = content.getPath();

              if (contentManager.exists(contentPath)) {
                content = contentManager.get(contentPath);
                if (content.hasProperty(SLING_RESOURCE_TYPE_PROPERTY)
                    && content.hasProperty(PROP_SAKAI_MESSAGEBOX)) {
                  if (SAKAI_MESSAGE_RT.equals(content.getProperty(SLING_RESOURCE_TYPE_PROPERTY))
                      && BOX_OUTBOX.equals(content.getProperty(PROP_SAKAI_MESSAGEBOX))) {
                    String sendstate;
                    if (content.hasProperty(PROP_SAKAI_SENDSTATE)) {
                      sendstate = (String) content.getProperty(PROP_SAKAI_SENDSTATE);
                    } else {
                      sendstate = STATE_NONE;
                    }
                    messageMap.put(content, sendstate);
                  }
                }
              }
              break;
          }
        } catch (StorageClientException ex) {
          LOGGER.warn("Failed to process on create for {} ", m.getSource(), ex);
        } catch (AccessDeniedException ex) {
          LOGGER.warn("Failed to process on create for {} ", m.getSource(), ex);
        }
      }

      List<String> handledNodes = new ArrayList<String>();
      // Check if we have any nodes that have a pending state and launch an OSGi
      // event
      for (Entry<Content, String> mm : messageMap.entrySet()) {
        Content content = mm.getKey();
        String path = content.getPath();
        String state = mm.getValue();
        if (!handledNodes.contains(path)) {
          if (STATE_NONE.equals(state) || STATE_PENDING.equals(state)) {

            content.setProperty(PROP_SAKAI_SENDSTATE, STATE_NOTIFIED);
            contentManager.update(content);

            Dictionary<String, Object> messageDict = new Hashtable<String, Object>();
            // WARNING
            // We can't pass in the node, because the session might expire before the event gets
            // handled
            // This does mean that the listener will have to get the node each time, and probably
            // create a new session for each message
            // This might be heavy on performance.
            messageDict.put(EVENT_LOCATION, path);
            messageDict.put(UserConstants.EVENT_PROP_USERID, request.getRemoteUser());
            LOGGER.debug("Launched event for message: {} ", path);
            Event pendingMessageEvent = new Event(PENDINGMESSAGE_EVENT, messageDict);
            // KERN-790: Initiate a synchronous event.
            try {
              eventAdmin.postEvent(pendingMessageEvent);
              handledNodes.add(path);
            } catch (Exception e) {
              LOGGER.warn("Failed to post message dispatch event, cause {} ", e.getMessage(), e);
            }
          }
        }
      }
    }
  }
  /*
   * (non-Javadoc)
   *
   * @seeorg.apache.sling.jackrabbit.usermanager.post.AbstractAuthorizablePostServlet#
   * handleOperation(org.apache.sling.api.SlingHttpServletRequest,
   * org.apache.sling.api.servlets.HtmlResponse, java.util.List)
   */
  @Override
  @edu.umd.cs.findbugs.annotations.SuppressWarnings(
      justification = "If there is an exception, the user is certainly not admin",
      value = {"REC_CATCH_EXCEPTION"})
  protected void handleOperation(
      SlingHttpServletRequest request, HtmlResponse response, List<Modification> changes)
      throws RepositoryException {

    // KERN-432 dont allow anon users to access create group.
    if (SecurityConstants.ANONYMOUS_ID.equals(request.getRemoteUser())) {
      response.setStatus(403, "AccessDenied");
    }

    // check that the submitted parameter values have valid values.
    final String principalName = request.getParameter(SlingPostConstants.RP_NODE_NAME);
    if (principalName == null) {
      throw new RepositoryException("Group name was not submitted");
    }

    NameSanitizer san = new NameSanitizer(principalName, false);
    san.validate();

    // check for allow create Group
    boolean allowCreateGroup = false;
    User currentUser = null;

    try {
      Session currentSession = request.getResourceResolver().adaptTo(Session.class);
      UserManager um = AccessControlUtil.getUserManager(currentSession);
      currentUser = (User) um.getAuthorizable(currentSession.getUserID());
      if (currentUser.isAdmin()) {
        LOGGER.debug("User is an admin ");
        allowCreateGroup = true;
      } else {
        LOGGER.debug("Checking for membership of one of {} ", Arrays.toString(authorizedGroups));
        PrincipalManager principalManager = AccessControlUtil.getPrincipalManager(currentSession);
        PrincipalIterator pi =
            principalManager.getGroupMembership(
                principalManager.getPrincipal(currentSession.getUserID()));
        Set<String> groups = new HashSet<String>();
        for (; pi.hasNext(); ) {
          groups.add(pi.nextPrincipal().getName());
        }

        for (String groupName : authorizedGroups) {
          if (groups.contains(groupName)) {
            allowCreateGroup = true;
            break;
          }

          // TODO: move this nasty hack into the PrincipalManager dynamic groups need to
          // be in the principal manager for this to work.
          if ("authenticated".equals(groupName)
              && !SecurityConstants.ADMIN_ID.equals(currentUser.getID())) {
            allowCreateGroup = true;
            break;
          }

          // just check via the user manager for dynamic resolution.
          Group group = (Group) um.getAuthorizable(groupName);
          LOGGER.debug("Checking for group  {} {} ", groupName, group);
          if (group != null && group.isMember(currentUser)) {
            allowCreateGroup = true;
            LOGGER.debug("User is a member  of {} {} ", groupName, group);
            break;
          }
        }
      }
    } catch (Exception ex) {
      LOGGER.warn(
          "Failed to determin if the user is an admin, assuming not. Cause: " + ex.getMessage());
      allowCreateGroup = false;
    }

    if (!allowCreateGroup) {
      LOGGER.debug("User is not allowed to create groups ");
      response.setStatus(HttpServletResponse.SC_FORBIDDEN, "User is not allowed to create groups");
      return;
    }

    Session session = getSession();

    try {
      UserManager userManager = AccessControlUtil.getUserManager(session);
      Authorizable authorizable = userManager.getAuthorizable(principalName);

      if (authorizable != null) {
        // principal already exists!
        throw new RepositoryException(
            "A principal already exists with the requested name: " + principalName);
      } else {

        Group group =
            userManager.createGroup(
                new Principal() {
                  public String getName() {
                    return principalName;
                  }
                });
        String groupPath =
            AuthorizableResourceProvider.SYSTEM_USER_MANAGER_GROUP_PREFIX + group.getID();
        Map<String, RequestProperty> reqProperties = collectContent(request, response, groupPath);

        response.setPath(groupPath);
        response.setLocation(externalizePath(request, groupPath));
        response.setParentLocation(
            externalizePath(request, AuthorizableResourceProvider.SYSTEM_USER_MANAGER_GROUP_PATH));
        changes.add(Modification.onCreated(groupPath));

        // It is not allowed to touch the rep:group-managers property directly.
        String key = SYSTEM_USER_MANAGER_GROUP_PREFIX + principalName + "/";
        reqProperties.remove(key + PROP_GROUP_MANAGERS);
        reqProperties.remove(key + PROP_GROUP_VIEWERS);

        // write content from form
        writeContent(session, group, reqProperties, changes);

        // update the group memberships, although this uses session from the request, it
        // only
        // does so for finding authorizables, so its ok that we are using an admin session
        // here.
        updateGroupMembership(request, group, changes);
        updateOwnership(request, group, new String[] {currentUser.getID()}, changes);

        sakaiAuthorizableService.postprocess(group, session);

        // Launch an OSGi event for creating a group.
        try {
          Dictionary<String, String> properties = new Hashtable<String, String>();
          properties.put(UserConstants.EVENT_PROP_USERID, principalName);
          EventUtils.sendOsgiEvent(properties, UserConstants.TOPIC_GROUP_CREATED, eventAdmin);
        } catch (Exception e) {
          // Trap all exception so we don't disrupt the normal behaviour.
          LOGGER.error("Failed to launch an OSGi event for creating a user.", e);
        }
      }
    } catch (RepositoryException re) {
      throw new RepositoryException("Failed to create new group.", re);
    } finally {
      ungetSession(session);
    }
  }