PrincipalsUtil.getPrincipal(ctx, groupId, function(err, updatedGroup) { if (err) { return callback(err); } // Asynchronously update all member library indexes so that the group appears higher due to it being more recently // interacted with AuthzAPI.getAuthzMembers(groupId, null, 10000, function(err, memberRoles) { if (err) { log().error({'err': err, 'group': updatedGroup}, 'An error occurred while fetching group members to update library indexes after group update'); } var memberIds = _.pluck(memberRoles, 'id'); _updateMembershipsLibraries(memberIds, updatedGroup, oldStorageGroup.lastModified, function(err) { if (err) { log().error({ 'err': err, 'oldGroup': oldStorageGroup, 'newGroup': updatedStorageGroup, 'memberIds': memberIds }, 'An error occurred while updating the library index for group members after group update'); } }); }); // Emit the fact that we have updated this group PrincipalsEmitter.emit(PrincipalsConstants.events.UPDATED_GROUP, ctx, updatedStorageGroup, oldStorageGroup); // Return the full group profile for the caller return getFullGroupProfile(ctx, groupId, callback); });
'pageResources': function(libraryId, start, limit, callback) { AuthzAPI.getAuthzMembers(libraryId, start, limit, function(err, memberEntries) { if (err) { return callback(err); } PrincipalsDAO.getPrincipals(_.pluck(memberEntries, 'id'), ['principalId', 'tenantAlias', 'visibility', 'smallPictureUri'], function(err, members) { if (err) { return callback(err); } var resources = _.map(memberEntries, function(memberEntry) { var member = members[memberEntry.id]; var role = memberEntry.role; return { 'rank': _getMembersLibraryRank(libraryId, member, role), 'resource': member, 'value': role }; }); return callback(null, resources); }); }); }
it('verify non-numeric limit error', function(callback) { AuthzAPI.getAuthzMembers('g:cam:mrvisser', undefined, 'not a number', function(err) { assert.ok(err); assert.equal(err.code, 400); callback(); }); });
getMeeting(ctx, meetingId, function(err, meeting) { if (err) { return callback(err); } // Get the meeting members AuthzAPI.getAuthzMembers(meetingId, start, limit, function(err, memberRoles, nextToken) { if (err) { return callback(err); } // Get the basic profiles for all of these principals var memberIds = _.pluck(memberRoles, 'id'); PrincipalsUtil.getPrincipals(ctx, memberIds, function(err, memberProfiles) { if (err) { return callback(err); } // Merge the member profiles and roles into a single object var memberList = _.map(memberRoles, function(memberRole) { return { 'profile': memberProfiles[memberRole.id], 'role': memberRole.role }; }); return callback(null, memberList, nextToken); }); }); });
var _aggregateMembersDocuments = function(principalIds, callback, memberDocs) { memberDocs = memberDocs || []; if (principalIds.length === 0) { return callback(null, memberDocs); } var memberUpdate = principalIds.shift(); var resourceId = memberUpdate.id; var members = memberUpdate.members; if (members) { memberDocs.push(_createMembersDocument(resourceId, _.keys(members))); return _aggregateMembersDocuments(principalIds, callback, memberDocs); } else if (AuthzUtil.isUserId(resourceId)) { // If the resource whose members to reindex is a user, then the index is the user followers list FollowingDAO.getFollowers(resourceId, null, 10000, function(err, followerUserIds) { if (err) { return callback(err); } memberDocs.push(_createMembersDocument(resourceId, followerUserIds)); return _aggregateMembersDocuments(principalIds, callback, memberDocs); }); } else { // If the resource whose members to reindex is not a user, we get their members list AuthzAPI.getAuthzMembers(resourceId, null, 10000, function(err, members) { if (err) { return callback(err); } members = _.map(members, function(member) { return member.id; }); memberDocs.push(_createMembersDocument(resourceId, members)); return _aggregateMembersDocuments(principalIds, callback, memberDocs); }); } };
canViewMembers(ctx, group, function(err, canViewMembers) { if (err) { return callback(err); } else if (!canViewMembers) { return callback({'code': 401, 'msg': 'Insufficient privilege to view this group\'s members list.'}); } // Finally get the members and their basic profiles AuthzAPI.getAuthzMembers(groupId, start, limit, function(err, members, nextToken) { if (err) { return callback(err); } var memberIds = _.map(members, function(member) { return member.id; }); PrincipalsUtil.getPrincipals(ctx, memberIds, function(err, memberProfiles) { if (err) { return callback(err); } var memberList = []; for (var m = 0; m < members.length; m++) { var member = members[m].id; if (memberProfiles[member]) { memberList.push({ 'profile': memberProfiles[member], 'role': members[m].role }); } } return callback(null, memberList, nextToken); }); }); });
var _checkNewGroupMembers = function(ctx, group, members, callback) { // Check that we don't remove all members. AuthzAPI.getAuthzMembers(group.id, null, 10000, function(err, oldMembers) { if (err) { return callback(err); } // Get the managers that aren't removed by this update. var remainingManagers = _.filter(oldMembers, function(member) { var isManager = member.role === Constants.roles.MANAGER; var isRemoved = members[member.id] === false; var hasRoleChange = (members[member.id] && members[member.id] !== Constants.roles.MANAGER); return (isManager && !isRemoved && !hasRoleChange); }); // Get the extra set of managers. var newManagers = _.filter(members, function(role, id) { return role === Constants.roles.MANAGER; }); // Combine them and count them. If the total is 0 that means an attempt has been made to remove all direct managers. var managers = remainingManagers.concat(newManagers); if (managers.length === 0) { return callback({'code': 400, 'msg': 'At least one principal should be a manager.'}); } else { callback(); } }); };
getFolder(ctx, folderId, function(err, folder) { if (err) { return callback(err); } // Get the discussion members AuthzAPI.getAuthzMembers(folder.groupId, start, limit, function(err, memberRoles, nextToken) { if (err) { return callback(err); } // Get the basic profiles for all of these principals PrincipalsUtil.getPrincipals(ctx, _.pluck(memberRoles, 'id'), function(err, memberProfiles) { if (err) { return callback(err); } // Merge the member profiles and roles into a single object var memberList = _.map(memberRoles, function(memberRole) { return { 'profile': memberProfiles[memberRole.id], 'role': memberRole.role }; }); return callback(null, memberList, nextToken); }); }); });
it('verify invalid group id error', function(callback) { AuthzAPI.getAuthzMembers('not a valid id', undefined, undefined, function(err) { assert.ok(err); assert.equal(err.code, 400); callback(); }); });
it('verify non-group group id error', function(callback) { AuthzAPI.getAuthzMembers('u:cam:mrvisser', undefined, undefined, function(err) { assert.ok(err); assert.equal(err.code, 400); callback(); }); });
var _getAllAuthzMembers = function(groupIds, callback, aggregatedMembers) { aggregatedMembers = aggregatedMembers || {}; if (groupIds.length === 0) { return callback(null, _.keys(aggregatedMembers)); } var groupId = groupIds.shift(); AuthzAPI.getAuthzMembers(groupId, null, 10000, function(err, members) { if (err) { return callback(err); } // Aggregate the memberIds for (var i = 0; i < members.length; i++) { var memberId = members[i].id; if (!aggregatedMembers[memberId] && AuthzUtil.isGroupId(memberId) && !_.contains(groupIds, memberId)) { // If this is a group and we have not aggregated it yet, add it to the groupIds groupIds.push(memberId); } // Aggregate the member's id aggregatedMembers[memberId] = true; } return _getAllAuthzMembers(groupIds, callback, aggregatedMembers); }); };
verifyBidirectionalGroupMembership(groupId, memberId, 'manager', function() { // also ensure that the number of members in the group is still 1 AuthzAPI.getAuthzMembers(groupId, undefined, undefined, function(err, members) { assert.ok(!err); assert.equal(members.length, 1); callback(); }); });
AuthzAPI.updateRoles(groupId, makeMembershipChange(memberId, 'member'), function(err) { assert.ok(!err); AuthzAPI.getAuthzMembers(groupId, undefined, undefined, function(err, members) { assert.ok(!err); assert.ok(members); assert.equal(members.length, 1); assert.equal(members[0].id, memberId); callback(); }); });
AuthzAPI.getAuthzMembers(groupId, undefined, 10, function(err, members) { assert.ok(!err); assert.equal(members.length, 10); AuthzAPI.getAuthzMembers(groupId, members[9].id, 10, function(err, members) { assert.ok(!err); assert.equal(members.length, 1); callback(); }); });
AuthzAPI.hasAnyRole(memberId, groupId, function(err, hasRole) { assert.ok(!err); assert.ok(!hasRole); AuthzAPI.getAuthzMembers(groupId, undefined, undefined, function(err, members) { assert.ok(!err); assert.ok(members); assert.ok(!_.find(members, function(member){ if (member.id === memberId) { return member.role; }})); callback(); }); });
AuthzAPI.hasRole(memberId, groupId, 'member', function(err, hasRole) { assert.ok(!err); assert.ok(hasRole); // verify membership exists VIA groups api (top-to-bottom association) AuthzAPI.getAuthzMembers(groupId, undefined, undefined, function(err, members) { assert.ok(!err); assert.equal(members.length, 1); callback(); }); });
const _getMemberIds = function(resource, callback) { if (resource.memberIds) { return callback(null, resource.memberIds); } AuthzAPI.getAuthzMembers(resource.id, null, 10000, (err, memberIdRoles) => { if (err) { return callback(err); } return callback(null, _.pluck(memberIdRoles, 'id')); }); };
AuthzAPI.updateRoles(groupId, changes, function(err) { assert.ok(!err); AuthzAPI.getAuthzMembers(groupId, undefined, 10, function(err, members, nextToken) { assert.ok(!err); assert.equal(members.length, 10); assert.equal(nextToken, members[9].id); AuthzAPI.getAuthzMembers(groupId, members[9].id, 10, function(err, members, nextToken) { assert.ok(!err); assert.equal(members.length, 1); assert.ok(!nextToken); callback(); }); }); });
AuthzAPI.hasRole(memberId, groupId, role, function(err, hasRole) { assert.ok(!err); assert.ok(hasRole); // also verify from the group membership AuthzAPI.getAuthzMembers(groupId, undefined, undefined, function(err, members) { assert.ok(!err); assert.ok(members); assert.ok(_.find(members, function(member) { if (member.id === memberId) { return member.role; } })); callback(); }); });
'pageResources': function(libraryId, start, limit, callback) { AuthzAPI.getAuthzMembers(libraryId, start, limit, function(err, memberInfos, nextToken) { if (err) { return callback(err); } var ids = _.pluck(memberInfos, 'id'); PrincipalsDAO.getPrincipals(ids, ['principalId', 'tenantAlias', 'visibility'], function(err, memberProfiles) { if (err) { return callback(err); } var resources = _.map(memberProfiles, function(memberProfile) { return {'resource': memberProfile}; }); return callback(null, resources, nextToken); }); }); }
var getAllAuthzMembersByRole = module.exports.getAllAuthzMembersByRole = function(resourceId, callback) { AuthzAPI.getAuthzMembers(resourceId, null, 10000, function(err, members) { if (err) { return callback(err); } var membersByRole = {}; var groupMembersByRole = {}; // Gather the direct membersByRole and aggregate the groupMembersByRole so we can get their descendants for (var i = 0; i < members.length; i++) { var member = members[i]; var id = member.id; var role = member.role; membersByRole[role] = membersByRole[role] || []; membersByRole[role].push(id); if (AuthzUtil.isGroupId(id)) { groupMembersByRole[role] = groupMembersByRole[role] || []; groupMembersByRole[role].push(id); } } // Merge the descendants by role of all the group members descendants _getAllAuthzGroupMembersByRole(groupMembersByRole, function(err, indirectMembersByRole) { if (err) { return callback(err); } var roles = _.keys(indirectMembersByRole); for (var i = 0; i < roles.length; i++) { var role = roles[i]; membersByRole[role] = _.uniq(_.union(membersByRole[role], indirectMembersByRole[role])); } // At this point membersByRole holds a hash of all direct and indirect members of the content, keyed by their role return callback(null, membersByRole); }); }); };
PrincipalsDAO.updatePrincipal(groupId, profileFields, function(err) { if (err) { return callback(err); } var updatedGroup = _.extend({}, oldGroup, profileFields); /*! * A callback method that, when invoked, will signal the successful completion of this method. Used for * convenience so that when operations occur afterward that are not tied to the success of this method are * invoked they can easily return without returning an error code */ var _callback = function() { PrincipalsEmitter.emit(PrincipalsConstants.events.UPDATED_GROUP, ctx, updatedGroup, oldGroup); return callback(null, updatedGroup); }; AuthzAPI.getAuthzMembers(groupId, null, 10000, function(err, memberRoles) { if (err) { log().error({'err': err, 'group': updatedGroup}, 'An error occurred while fetching group members to update library indexes after group update'); return _callback(); } var memberIds = _.pluck(memberRoles, 'id'); _updateMembershipsLibraries(memberIds, updatedGroup, oldGroup.lastModified, function(err) { if (err) { log().error({ 'err': err, 'oldGroup': oldGroup, 'newGroup': newGroup, 'memberIds': memberIds }, 'An error occurred while updating the library index for group members after group update'); } return _callback(); }); }); });
FoldersAPI.on(FoldersConstants.events.UPDATED_FOLDER, function(ctx, folder, updatedFolder) { // Keep track of the async operation purgeCounter.incr(); // Update the folder libraries of the principals that are members of this folder AuthzAPI.getAuthzMembers(folder.groupId, null, 10000, function(err, memberRoles, nextToken) { if (err) { log().error({'err': err, 'folder': folder}, 'Could not retrieve the members for a folder, their folder library will NOT be updated'); return; } var principalIds = _.pluck(memberRoles, 'id'); FoldersFoldersLibrary.update(principalIds, updatedFolder, folder.lastModified, function(err) { if (err) { log().error({'err': err, 'folder': folder}, 'Could not update the folder libraries for a set of users'); return; } // At this point the async operation is over purgeCounter.decr(); }); }); });
const getAllAuthzMembersByRole = function(resourceId, callback) { AuthzAPI.getAuthzMembers(resourceId, null, 10000, (err, members) => { if (err) { return callback(err); } const membersByRole = {}; const groupMembersByRole = {}; // Gather the direct membersByRole and aggregate the groupMembersByRole so we can get their descendants _.each(members, member => { const { id } = member; const { role } = member; membersByRole[role] = membersByRole[role] || []; membersByRole[role].push(id); if (AuthzUtil.isGroupId(id)) { groupMembersByRole[role] = groupMembersByRole[role] || []; groupMembersByRole[role].push(id); } }); // Merge the descendants by role of all the group members descendants _getAllAuthzGroupMembersByRole(groupMembersByRole, (err, indirectMembersByRole) => { if (err) { return callback(err); } // Aggregate each set of indirect members into its associated group of roles _.each(indirectMembersByRole, (indirectMembers, role) => { membersByRole[role] = _.union(membersByRole[role], indirectMembers); }); // At this point membersByRole holds a hash of all direct and indirect members of the content, keyed by their role return callback(null, membersByRole); }); }); };
var _getAllGroupChildren = function(principalIds, excludePrincipals, callback, _groupsToExplode, _allChildren) { _allChildren = _allChildren || []; _groupsToExplode = _groupsToExplode || _.filter(principalIds, AuthzUtil.isGroupId); // If there are no groups left to explode, we can remove the group from all the affected // member libraries if (_.isEmpty(_groupsToExplode)) { return callback(null, _allChildren); } // Get the next group to explode var groupId = _groupsToExplode.shift(); // Get all of the members of the group, so they can be invalidated AuthzAPI.getAuthzMembers(groupId, null, 10000, function(err, members) { if (err) { return callback(err); } _.each(members, function(member) { // Groups need to be further exploded. In order to do this, we need to check whether or not the list // of groups that have already been invalidated and the list of groups that are queued up to be invalidated // don't contain this group, otherwise we'll invalidate the group twice. if (AuthzUtil.isGroupId(member.id) && !_.contains(_allChildren, member.id) && !_.contains(_groupsToExplode, member.id) && !_.contains(excludePrincipals, member.id)) { _groupsToExplode.push(member.id); } // The members can be invalidated if (!_.contains(_allChildren, member.id) && !_.contains(excludePrincipals, member.id)) { _allChildren.push(member.id); } }); _getAllGroupChildren(principalIds, excludePrincipals, callback, _groupsToExplode, _allChildren); }); };
var _aggregateMembersDocuments = function(principalIds, callback, memberDocs) { memberDocs = memberDocs || []; if (principalIds.length === 0) { return callback(null, memberDocs); } var memberUpdate = principalIds.shift(); var resourceId = memberUpdate.id; var members = memberUpdate.members; if (members) { memberDocs.push(_createMembersDocument(resourceId, _.keys(members))); return _aggregateMembersDocuments(principalIds, callback, memberDocs); } else { AuthzAPI.getAuthzMembers(resourceId, null, 10000, function(err, members) { if (err) { return callback(err); } members = _.map(members, function(member) { return member.id; }); memberDocs.push(_createMembersDocument(resourceId, members)); return _aggregateMembersDocuments(principalIds, callback, memberDocs); }); } };
}); /*! * Register a library indexer that can provide resources to reindex the content members library */ LibraryAPI.Index.registerLibraryIndex(ContentConstants.library.MEMBERS_LIBRARY_INDEX_NAME, { pageResources(libraryId, start, limit, callback) { AuthzAPI.getAuthzMembers(libraryId, start, limit, (err, memberInfos, nextToken) => { if (err) { return callback(err); } const ids = _.pluck(memberInfos, 'id'); PrincipalsDAO.getPrincipals(ids, ['principalId', 'tenantAlias', 'visibility'], (err, memberProfiles) => { if (err) { return callback(err); } const resources = _.map(memberProfiles, memberProfile => { return { resource: memberProfile }; }); return callback(null, resources, nextToken); }); }); } }); /*! * Configure the content library search endpoint */ LibraryAPI.Search.registerLibrarySearch('content-library', ['content']);
var getAllContentMembers = module.exports.getAllContentMembers = function(contentId, callback) { AuthzAPI.getAuthzMembers(contentId, null, 10000, callback); };
LibraryAPI.Index.registerLibraryIndex(PrincipalsConstants.library.MEMBERS_INDEX_NAME, { pageResources(libraryId, start, limit, callback) { AuthzAPI.getAuthzMembers(libraryId, start, limit, (err, memberEntries) => { if (err) { return callback(err); } PrincipalsDAO.getPrincipals( _.pluck(memberEntries, 'id'), ['principalId', 'tenantAlias', 'visibility', 'smallPictureUri'], (err, members) => { if (err) { return callback(err); } const resources = _.map(memberEntries, memberEntry => { const member = members[memberEntry.id]; const { role } = memberEntry; return { rank: _getMembersLibraryRank(libraryId, member, role), resource: member, value: role }; }); return callback(null, resources); } ); }); } });