/**
   * Apply the 'search by role' filter to the lucene query string.
   *
   * @param parametersMap
   * @param filters
   */
  protected void buildSearchByRoleQuery(Map<String, String> parametersMap, List<String> filters) {
    SearchableRole role =
        SearchableRole.valueOf(getSearchParam(parametersMap, REQUEST_PARAMETERS.role.toString()));
    String userid = getSearchParam(parametersMap, REQUEST_PARAMETERS.userid.toString());
    AuthorizableManager authorizableManager = null;
    Session adminSession = null;
    try {
      adminSession = repository.loginAdministrative();
      authorizableManager = adminSession.getAuthorizableManager();
      Authorizable au = authorizableManager.findAuthorizable(userid);
      List<Authorizable> groups = AuthorizableUtil.getUserFacingGroups(au, authorizableManager);
      groups.add(au);

      List<String> groupStrs = new ArrayList<String>(groups.size());
      for (Authorizable memberAuthz : groups) {
        groupStrs.add(ClientUtils.escapeQueryChars(memberAuthz.getId()));
      }

      filters.add(String.format(ROLE_TEMPLATE, role.toString(), JOINER_OR.join(groupStrs)));
      adminSession.logout();
    } catch (ClientPoolException e) {
      throw new RuntimeException(e);
    } catch (StorageClientException e) {
      throw new RuntimeException(e);
    } catch (AccessDeniedException e) {
      throw new RuntimeException(e);
    } finally {
      SparseUtils.logoutQuietly(adminSession);
    }
  }
  private AuthorizableManager getAuthorizableManager(
      HttpServletRequest request, HttpServletResponse response) throws StorageClientException {
    Session session = sessionTracker.get(request);
    if (session == null) {

      session =
          sessionTracker.register(authenticationService.authenticate(request, response), request);
    }
    return session.getAuthorizableManager();
  }
  /**
   * {@inheritDoc}
   *
   * @see
   *     org.sakaiproject.nakamura.api.solr.IndexingHandler#getDocuments(org.sakaiproject.nakamura.api.solr.RepositorySession,
   *     org.osgi.service.event.Event)
   */
  public Collection<SolrInputDocument> getDocuments(
      RepositorySession repositorySession, Event event) {
    String path = (String) event.getProperty(FIELD_PATH);

    logger.info("Indexing connections at path {}", path);
    List<SolrInputDocument> documents = Lists.newArrayList();
    if (!StringUtils.isBlank(path)) {
      try {
        Session session = repositorySession.adaptTo(Session.class);
        ContentManager cm = session.getContentManager();
        Content content = cm.get(path);

        int lastSlash = path.lastIndexOf('/');
        String contactName = path.substring(lastSlash + 1);
        AuthorizableManager am = session.getAuthorizableManager();
        Authorizable contactAuth = am.findAuthorizable(contactName);

        if (content != null && contactAuth != null) {
          SolrInputDocument doc = new SolrInputDocument();
          for (Entry<String, String> prop : WHITELISTED_PROPS.entrySet()) {
            String key = prop.getKey();
            Object value = content.getProperty(key);
            if (value != null) {
              doc.addField(WHITELISTED_PROPS.get(key), value);
            }
          }

          // flatten out the contact so we can search it
          Map<String, Object> contactProps = contactAuth.getSafeProperties();
          if (contactAuth != null) {
            for (String prop : FLATTENED_PROPS) {
              Object value = contactProps.get(prop);
              if (value != null) {
                doc.addField(prop, value);
              }
            }
          }

          doc.addField(_DOC_SOURCE_OBJECT, content);
          documents.add(doc);
        } else {
          logger.warn(
              "Did not index {}: Content == {}; Contact Auth == {}",
              new Object[] {path, content, contactAuth});
        }
      } catch (StorageClientException e) {
        logger.error(e.getMessage(), e);
      } catch (AccessDeniedException e) {
        logger.error(e.getMessage(), e);
      }
    }
    logger.debug("Got documents {} ", documents);
    return documents;
  }
 public CreateContentPoolServletTest()
     throws ClientPoolException, StorageClientException, AccessDeniedException,
         ClassNotFoundException {
   MockitoAnnotations.initMocks(this);
   BaseMemoryRepository baseMemoryRepository = new BaseMemoryRepository();
   repository = baseMemoryRepository.getRepository();
   Session session = repository.loginAdministrative();
   AuthorizableManager authorizableManager = session.getAuthorizableManager();
   authorizableManager.createUser("ieb", "Ian Boston", "test", ImmutableMap.of("x", (Object) "y"));
   org.sakaiproject.nakamura.api.lite.authorizable.Authorizable authorizable =
       authorizableManager.findAuthorizable("ieb");
   System.err.println("Got ieb as " + authorizable);
   session.logout();
 }
 /**
  * Same as writeResults logic, but counts number of results iterated over.
  *
  * @param request
  * @param write
  * @param iterator
  * @return Set containing all unique paths processed.
  * @throws JSONException
  */
 public Set<String> writeResultsInternal(
     SlingHttpServletRequest request, JSONWriter write, Iterator<Result> iterator)
     throws JSONException {
   final Set<String> uniquePaths = new HashSet<String>();
   final Integer iDepth = (Integer) request.getAttribute("depth");
   int depth = 0;
   if (iDepth != null) {
     depth = iDepth.intValue();
   }
   try {
     javax.jcr.Session jcrSession = request.getResourceResolver().adaptTo(javax.jcr.Session.class);
     final Session session = StorageClientUtils.adaptToSession(jcrSession);
     while (iterator.hasNext()) {
       final Result result = iterator.next();
       uniquePaths.add(result.getPath());
       try {
         if ("authorizable".equals(result.getFirstValue("resourceType"))) {
           AuthorizableManager authManager = session.getAuthorizableManager();
           Authorizable auth = authManager.findAuthorizable((String) result.getFirstValue("id"));
           if (auth != null) {
             write.object();
             ValueMap map = profileService.getProfileMap(auth, jcrSession);
             ExtendedJSONWriter.writeValueMapInternals(write, map);
             write.endObject();
           }
         } else {
           String contentPath = result.getPath();
           final Content content = session.getContentManager().get(contentPath);
           if (content != null) {
             handleContent(content, session, write, depth);
           } else {
             LOGGER.debug("Found null content item while writing results [{}]", contentPath);
           }
         }
       } catch (AccessDeniedException e) {
         // do nothing
       } catch (RepositoryException e) {
         throw new JSONException(e);
       }
     }
   } catch (StorageClientException e) {
     throw new JSONException(e);
   }
   return uniquePaths;
 }
  @Before
  public void setUp() throws Exception {
    provider = new MyRelatedGroupsPropertyProvider(searchServiceFactory);
    when(request.getRemoteUser()).thenReturn("user1");

    when(repo.loginAdministrative()).thenReturn(session);
    when(session.getAuthorizableManager()).thenReturn(authMgr);
    when(authMgr.findAuthorizable("user1")).thenReturn(auth1);

    Group group1 = mock(Group.class);
    when(group1.getId()).thenReturn("group1");
    when(group1.getProperty(GROUP_TITLE_PROPERTY)).thenReturn("Group 1 Test");
    when(group1.getProperty("sakai:tag-uuid")).thenReturn(new String[] {"123-456"});

    when(auth1.memberOf(authMgr)).thenReturn(Sets.newHashSet(group1).iterator());

    when(searchServiceFactory.getSearchResultSet(eq(request), any(Query.class))).thenReturn(rs);
  }
 private void writeCanManageProperty(
     SlingHttpServletRequest request, JSONWriter write, Session session, Content contentResult)
     throws StorageClientException, JSONException, AccessDeniedException {
   write.key("sakai:canmanage");
   Authorizable thisUser =
       session.getAuthorizableManager().findAuthorizable(request.getRemoteUser());
   Collection<String> principals = new ArrayList<String>();
   principals.addAll(Arrays.asList(thisUser.getPrincipals()));
   principals.add(request.getRemoteUser());
   boolean canManage = false;
   for (String principal : principals) {
     if (Arrays.asList(
             StorageClientUtils.nonNullStringArray(
                 (String[]) contentResult.getProperty("sakai:pooled-content-manager")))
         .contains(principal)) {
       canManage = true;
     }
   }
   write.value(canManage);
 }
  private String convertToEmail(String address, org.sakaiproject.nakamura.api.lite.Session session)
      throws StorageClientException, AccessDeniedException {
    if (address.indexOf('@') < 0) {
      String emailAddress = null;

      Authorizable user = session.getAuthorizableManager().findAuthorizable(address);
      if (user != null) {
        Content profile =
            session.getContentManager().get(LitePersonalUtils.getProfilePath(user.getId()));
        if (profile != null) {
          emailAddress = LitePersonalUtils.getProfilePath(user.getId());
        }
      }
      if (emailAddress != null && emailAddress.trim().length() > 0) {
        address = emailAddress;
      } else {
        address = address + "@" + smtpServer;
      }
    }
    return address;
  }
  /**
   * Process a query string to search using Solr.
   *
   * @param request
   * @param query
   * @param asAnon
   * @param rs
   * @return
   * @throws SolrSearchException
   */
  private SolrSearchResultSet processSolrQuery(
      SlingHttpServletRequest request, Query query, boolean asAnon)
      throws StorageClientException, AccessDeniedException, SolrServerException {
    String queryString = query.getQueryString();
    // apply readers restrictions.
    if (asAnon) {
      queryString = "(" + queryString + ")  AND readers:" + User.ANON_USER;
    } else {
      Session session =
          StorageClientUtils.adaptToSession(
              request.getResourceResolver().adaptTo(javax.jcr.Session.class));
      if (!User.ADMIN_USER.equals(session.getUserId())) {
        AuthorizableManager am = session.getAuthorizableManager();
        Authorizable user = am.findAuthorizable(session.getUserId());
        Set<String> readers = Sets.newHashSet();
        for (Iterator<Group> gi = user.memberOf(am); gi.hasNext(); ) {
          readers.add(gi.next().getId());
        }
        readers.add(session.getUserId());
        queryString =
            "(" + queryString + ") AND readers:(" + StringUtils.join(readers, " OR ") + ")";
      }
    }

    SolrQuery solrQuery = buildQuery(request, queryString, query.getOptions());

    SolrServer solrServer = solrSearchService.getServer();
    try {
      LOGGER.info("Performing Query {} ", URLDecoder.decode(solrQuery.toString(), "UTF-8"));
    } catch (UnsupportedEncodingException e) {
    }
    QueryResponse response = solrServer.query(solrQuery);
    SolrDocumentList resultList = response.getResults();
    LOGGER.info("Got {} hits in {} ms", resultList.size(), response.getElapsedTime());
    return new SolrSearchResultSetImpl(response);
  }
Ejemplo n.º 10
0
  private SolrInputDocument handleMessageIndexing(Map<String, Object> props) throws Exception {
    String messagePath = "a:user1/messagePath";

    Content content = new Content(messagePath, props);
    Authorizable sender = mock(Authorizable.class);

    when(sender.getId()).thenReturn("sender");
    when(sender.isGroup()).thenReturn(Boolean.FALSE);
    when(sender.getProperty(eq("firstName"))).thenReturn("test");
    when(sender.getProperty(eq("lastName"))).thenReturn("user");

    Authorizable user1 = mock(Authorizable.class);
    when(user1.getId()).thenReturn("user1");
    when(user1.isGroup()).thenReturn(Boolean.FALSE);
    when(user1.getProperty(eq("firstName"))).thenReturn("user");
    when(user1.getProperty(eq("lastName"))).thenReturn("one");

    when(authorizableManager.findAuthorizable(anyString())).thenReturn(sender);
    when(repositorySession.adaptTo(Session.class)).thenReturn(session);
    when(session.getAuthorizableManager()).thenReturn(authorizableManager);
    when(session.getContentManager()).thenReturn(contentManager);
    when(contentManager.get(messagePath)).thenReturn(content);

    MessageIndexingHandler handler = new MessageIndexingHandler();
    handler.dateParser = this.dateParser;
    Event event = new Event("topic", buildEventProperties(messagePath));

    Collection<SolrInputDocument> documents = handler.getDocuments(repositorySession, event);

    assertNotNull(documents);
    assertTrue(!documents.isEmpty());

    Iterator<SolrInputDocument> docIt = documents.iterator();

    SolrInputDocument doc = docIt.next();

    // test basic message properties
    assertEquals("test-messagestore", doc.getField("messagestore").getValue());
    assertEquals("test-messagebox", doc.getField("messagebox").getValue());
    assertEquals("test-type", doc.getField("type").getValue());
    assertEquals("test-category", doc.getField("category").getValue());
    assertEquals("test-from", doc.getField("from").getValue());
    assertEquals("test-to", doc.getField("to").getValue());
    assertEquals("test-read", doc.getField("read").getValue());
    assertEquals("test-marker", doc.getField("marker").getValue());
    assertEquals("test-sendstate", doc.getField("sendstate").getValue());
    assertEquals("test-initialpost", doc.getField("initialpost").getValue());
    assertEquals("test-title", doc.getField("title").getValue());
    assertEquals("test-content", doc.getField("content").getValue());

    // ensure unexpected value is skipped
    assertNull(doc.getField("notindexed"));

    // test sender name is set
    assertEquals("test", doc.getField("firstName").getValue());
    assertEquals("user", doc.getField("lastName").getValue());

    // an additional doc should have been added for authorizable searching:
    assertTrue(docIt.hasNext());
    SolrInputDocument authDoc = docIt.next();

    // test values set for user/group searching
    assertEquals("test-title", authDoc.getField("title").getValue());
    assertEquals("test-content", authDoc.getField("content").getValue());
    assertEquals("u", authDoc.getField("type").getValue());
    assertEquals(content, authDoc.getField(IndexingHandler._DOC_SOURCE_OBJECT).getValue());
    assertEquals("user1", authDoc.getField(IndexingHandler.FIELD_PATH).getValue());
    assertEquals(messagePath + "-auth", authDoc.getField(IndexingHandler.FIELD_ID).getValue());
    assertEquals("user1", authDoc.getField("returnpath").getValue());

    assertTrue(!docIt.hasNext());
    return doc;
  }
  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"));
      }
    }
  }
  @SuppressWarnings("unchecked")
  public void onMessage(Message message) {
    log.debug("Receiving a message on {} : {}", SyncJMSMessageProducer.QUEUE_NAME, message);
    try {

      String topic = message.getJMSType();
      String groupId = (String) message.getStringProperty("path");

      String operation = "UNKNOWN";

      // A group was DELETED
      if ("org/sakaiproject/nakamura/lite/authorizables/DELETE".equals(topic)
          && config.getDeletesEnabled()) {
        Map<String, Object> attributes =
            (Map<String, Object>) message.getObjectProperty(StoreListener.BEFORE_EVENT_PROPERTY);
        grouperManager.deleteGroup(groupId, attributes);
        operation = "DELETED";
      }

      // A new group was ADDED or an existing group was UPDATED
      if ("org/sakaiproject/nakamura/lite/authorizables/ADDED".equals(topic)
          || "org/sakaiproject/nakamura/lite/authorizables/UPDATED".equals(topic)) {
        // These events should be under org/sakaiproject/nakamura/lite/authorizables/UPDATED
        // http://jira.sakaiproject.org/browse/KERN-1795
        String membersAdded =
            (String) message.getStringProperty(GrouperEventUtils.MEMBERS_ADDED_PROP);
        if (membersAdded != null) {
          // membership adds can be attached to the same event for the group add.
          grouperManager.createGroup(groupId, config.getGroupTypes());
          grouperManager.addMemberships(
              groupId, Arrays.asList(StringUtils.split(membersAdded, ",")));
          operation = "ADD_MEMBERS";
        }

        String membersRemoved =
            (String) message.getStringProperty(GrouperEventUtils.MEMBERS_REMOVED_PROP);
        if (membersRemoved != null) {
          grouperManager.removeMemberships(
              groupId, Arrays.asList(StringUtils.split(membersRemoved, ",")));
          operation = "REMOVE_MEMBERS";
        }

        if (membersAdded == null && membersRemoved == null) {
          org.sakaiproject.nakamura.api.lite.Session repositorySession =
              repository.loginAdministrative();
          AuthorizableManager am = repositorySession.getAuthorizableManager();
          Group group = (Group) am.findAuthorizable(groupId);
          repositorySession.logout();

          if (groupId.startsWith(ContactsGrouperNameProviderImpl.CONTACTS_GROUPID_PREFIX)) {
            // TODO Why are we not getting added and removed properties on the Message
            grouperManager.createGroup(groupId, null);
            grouperManager.addMemberships(groupId, Arrays.asList(group.getMembers()));
            operation = "UPDATE CONTACTS";
          } else {
            grouperManager.createGroup(groupId, config.getGroupTypes());
            grouperManager.addMemberships(groupId, Arrays.asList(group.getMembers()));
            operation = "CREATE";
          }
        }
      }

      // The message was processed successfully. No exceptions were thrown.
      // We acknowledge the message and its removed from the queue
      message.acknowledge();

      // We got a message that we didn't know what to do with.
      if (operation.equals("UNKNOWN")) {
        log.error(
            "I don't know what to do with this topic: {}. Turn on debug logs to see the message.",
            topic);
        log.debug(message.toString());
      } else {
        log.info("Successfully processed and acknowledged. {}, {}", operation, groupId);
        log.debug(message.toString());
      }

    } catch (JMSException jmse) {
      log.error("JMSException while processing message.", jmse);
    } catch (Exception e) {
      log.error("Exception while processing message.", e);
    }
  }
  /**
   * Manipulate the member list for this file.
   *
   * <p>{@inheritDoc}
   *
   * @see
   *     org.apache.sling.api.servlets.SlingAllMethodsServlet#doPost(org.apache.sling.api.SlingHttpServletRequest,
   *     org.apache.sling.api.SlingHttpServletResponse)
   */
  @SuppressWarnings("unchecked")
  @Override
  protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response)
      throws ServletException, IOException {
    // fail if anonymous
    String remoteUser = request.getRemoteUser();
    if (User.ANON_USER.equals(remoteUser)) {
      response.sendError(SC_FORBIDDEN, "Anonymous users cannot update content members.");
      return;
    }
    Session session = null;
    boolean releaseSession = false;
    try {
      Resource resource = request.getResource();
      session = resource.adaptTo(Session.class);
      Content pooledContent = resource.adaptTo(Content.class);
      AccessControlManager accessControlManager = session.getAccessControlManager();
      AuthorizableManager authorizableManager = session.getAuthorizableManager();
      User thisUser = authorizableManager.getUser();
      if (!accessControlManager.can(
          thisUser, Security.ZONE_CONTENT, pooledContent.getPath(), Permissions.CAN_READ)) {
        response.sendError(SC_FORBIDDEN, "Insufficient permission to read this content.");
      }

      Map<String, Object> properties = pooledContent.getProperties();
      String[] managers =
          StorageClientUtils.nonNullStringArray(
              (String[]) properties.get(POOLED_CONTENT_USER_MANAGER));
      String[] editors =
          StorageClientUtils.nonNullStringArray(
              (String[]) properties.get(POOLED_CONTENT_USER_EDITOR));
      String[] viewers =
          StorageClientUtils.nonNullStringArray(
              (String[]) properties.get(POOLED_CONTENT_USER_VIEWER));

      Set<String> managerSet = Sets.newHashSet(managers);
      Set<String> editorSet = Sets.newHashSet(editors);
      Set<String> viewerSet = Sets.newHashSet(viewers);

      List<String> removeViewers =
          Arrays.asList(
              StorageClientUtils.nonNullStringArray(request.getParameterValues(":viewer@Delete")));
      List<String> removeManagers =
          Arrays.asList(
              StorageClientUtils.nonNullStringArray(request.getParameterValues(":manager@Delete")));
      List<String> removeEditors =
          Arrays.asList(
              StorageClientUtils.nonNullStringArray(request.getParameterValues(":editor@Delete")));
      List<String> addViewers =
          Arrays.asList(
              StorageClientUtils.nonNullStringArray(request.getParameterValues(":viewer")));
      List<String> addManagers =
          Arrays.asList(
              StorageClientUtils.nonNullStringArray(request.getParameterValues(":manager")));
      List<String> addEditors =
          Arrays.asList(
              StorageClientUtils.nonNullStringArray(request.getParameterValues(":editor")));

      if (!accessControlManager.can(
          thisUser, Security.ZONE_CONTENT, pooledContent.getPath(), Permissions.CAN_WRITE)) {
        if (!addManagers.isEmpty()) {
          response.sendError(SC_FORBIDDEN, "Non-managers may not add managers to content.");
          return;
        }

        for (String name : removeManagers) {
          // asking to remove managers who don't exist is harmless
          if (managerSet.contains(name)) {
            response.sendError(SC_FORBIDDEN, "Non-managers may not remove managers from content.");
            return;
          }
        }

        if (addViewers.contains(User.ANON_USER) || addViewers.contains(Group.EVERYONE)) {
          response.sendError(
              SC_FORBIDDEN, "Non-managers may not add 'anonymous' or 'everyone' as viewers.");
          return;
        }

        if (addEditors.contains(User.ANON_USER) || addEditors.contains(Group.EVERYONE)) {
          response.sendError(
              SC_FORBIDDEN, "Non-managers may not add 'anonymous' or 'everyone' as editors.");
          return;
        }

        for (String name : removeViewers) {
          if (!thisUser.getId().equals(name)) {
            Authorizable viewer = authorizableManager.findAuthorizable(name);
            if (viewer != null
                && !accessControlManager.can(
                    thisUser, Security.ZONE_AUTHORIZABLES, name, Permissions.CAN_WRITE)) {
              response.sendError(
                  SC_FORBIDDEN,
                  "Non-managers may not remove any viewer other than themselves or a group which they manage.");
            }
          }
        }

        // the request has passed all the rules that govern non-manager users
        // so we'll grant an administrative session
        session = session.getRepository().loginAdministrative();
        releaseSession = true;
      }
      List<AclModification> aclModifications = Lists.newArrayList();

      for (String addManager : addManagers) {
        if ((addManager.length() > 0) && !managerSet.contains(addManager)) {
          managerSet.add(addManager);
          AclModification.addAcl(true, Permissions.CAN_MANAGE, addManager, aclModifications);
        }
      }

      for (String removeManager : removeManagers) {
        if ((removeManager.length() > 0) && managerSet.contains(removeManager)) {
          managerSet.remove(removeManager);
          AclModification.removeAcl(true, Permissions.CAN_MANAGE, removeManager, aclModifications);
        }
      }

      for (String addEditor : addEditors) {
        if ((addEditor.length() > 0) && !editorSet.contains(addEditor)) {
          editorSet.add(addEditor);
          AclModification.addAcl(true, PERMISSION_EDITOR, addEditor, aclModifications);
        }
      }

      for (String removeEditor : removeEditors) {
        if ((removeEditor.length() > 0) && editorSet.contains(removeEditor)) {
          editorSet.remove(removeEditor);
          AclModification.removeAcl(true, PERMISSION_EDITOR, removeEditor, aclModifications);
        }
      }

      for (String addViewer : addViewers) {
        if ((addViewer.length() > 0) && !viewerSet.contains(addViewer)) {
          viewerSet.add(addViewer);
          AclModification.addAcl(true, Permissions.CAN_READ, addViewer, aclModifications);
        }
      }

      for (String removeViewer : removeViewers) {
        removeViewer = removeViewer.trim();
        if ((removeViewer.length() > 0) && viewerSet.contains(removeViewer)) {
          viewerSet.remove(removeViewer);
          if (!managerSet.contains(removeViewer)) {
            AclModification.removeAcl(true, Permissions.CAN_READ, removeViewer, aclModifications);
          }
        }
      }

      updateContentMembers(session, pooledContent, viewerSet, managerSet, editorSet);
      updateContentAccess(session, pooledContent, aclModifications);

      this.authorizableCountChanger.notify(
          UserConstants.CONTENT_ITEMS_PROP,
          addViewers,
          addEditors,
          addManagers,
          removeViewers,
          removeEditors,
          removeManagers);

      response.setStatus(SC_OK);

    } catch (StorageClientException e) {
      LOGGER.error(e.getMessage());
      response.sendError(
          SC_INTERNAL_SERVER_ERROR, "StorageClientException: " + e.getLocalizedMessage());
    } catch (AccessDeniedException e) {
      response.sendError(
          SC_FORBIDDEN,
          "Insufficient permission to update content members at " + request.getRequestURI());
    } finally {
      if (session != null && releaseSession) {
        try {
          session.logout();
        } catch (ClientPoolException e) {
          LOGGER.error(e.getMessage());
        }
      }
    }
  }
  /**
   * Retrieves the list of members.
   *
   * <p>{@inheritDoc}
   *
   * @see
   *     org.apache.sling.api.servlets.SlingSafeMethodsServlet#doGet(org.apache.sling.api.SlingHttpServletRequest,
   *     org.apache.sling.api.SlingHttpServletResponse)
   */
  @Override
  protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
      throws ServletException, IOException {
    try {
      // Get hold of the actual file.
      Resource resource = request.getResource();
      javax.jcr.Session jcrSession = request.getResourceResolver().adaptTo(javax.jcr.Session.class);
      Session session = resource.adaptTo(Session.class);

      AuthorizableManager am = session.getAuthorizableManager();
      AccessControlManager acm = session.getAccessControlManager();
      Content node = resource.adaptTo(Content.class);
      Authorizable thisUser = am.findAuthorizable(session.getUserId());

      if (!acm.can(thisUser, Security.ZONE_CONTENT, resource.getPath(), Permissions.CAN_READ)) {
        response.sendError(HttpServletResponse.SC_NOT_FOUND);
        return;
      }

      Map<String, Object> properties = node.getProperties();
      String[] managers = (String[]) properties.get(POOLED_CONTENT_USER_MANAGER);
      String[] editors = (String[]) properties.get(POOLED_CONTENT_USER_EDITOR);
      String[] viewers = (String[]) properties.get(POOLED_CONTENT_USER_VIEWER);

      boolean detailed = false;
      boolean tidy = false;
      for (String selector : request.getRequestPathInfo().getSelectors()) {
        if ("detailed".equals(selector)) {
          detailed = true;
        } else if ("tidy".equals(selector)) {
          tidy = true;
        }
      }

      // Loop over the sets and output it.
      ExtendedJSONWriter writer = new ExtendedJSONWriter(response.getWriter());
      writer.setTidy(tidy);
      writer.object();
      writer.key("managers");
      writer.array();
      for (String manager : StorageClientUtils.nonNullStringArray(managers)) {
        try {
          writeProfileMap(jcrSession, am, writer, manager, detailed);
        } catch (AccessDeniedException e) {
          LOGGER.debug("Skipping private manager [{}]", manager);
        }
      }
      writer.endArray();
      writer.key("editors");
      writer.array();
      for (String editor : StorageClientUtils.nonNullStringArray(editors)) {
        try {
          writeProfileMap(jcrSession, am, writer, editor, detailed);
        } catch (AccessDeniedException e) {
          LOGGER.debug("Skipping private editor [{}]", editor);
        }
      }
      writer.endArray();
      writer.key("viewers");
      writer.array();
      for (String viewer : StorageClientUtils.nonNullStringArray(viewers)) {
        try {
          writeProfileMap(jcrSession, am, writer, viewer, detailed);
        } catch (AccessDeniedException e) {
          LOGGER.debug("Skipping private viewer [{}]", viewer);
        }
      }
      writer.endArray();
      writer.endObject();
    } catch (JSONException e) {
      response.sendError(SC_INTERNAL_SERVER_ERROR, "Failed to generate proper JSON.");
      LOGGER.error(e.getMessage(), e);
    } catch (StorageClientException e) {
      response.sendError(SC_INTERNAL_SERVER_ERROR, "Failed to generate proper JSON.");
      LOGGER.error(e.getMessage(), e);
    } catch (AccessDeniedException e) {
      response.sendError(SC_INTERNAL_SERVER_ERROR, "Failed to generate proper JSON.");
      LOGGER.error(e.getMessage(), e);
    } catch (RepositoryException e) {
      response.sendError(SC_INTERNAL_SERVER_ERROR, "Failed to generate proper JSON.");
      LOGGER.error(e.getMessage(), e);
    }
  }