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")); } } }
/* * (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); } }