Exemple #1
0
    def permission_grants_for_user(self, name):
        # type: (str) -> List[PermissionGrant]
        now = datetime.utcnow()
        user = User.get(self.session, name=name)
        if not user or user.role_user or user.is_service_account or not user.enabled:
            return []

        # Get the groups of which this user is a direct member.
        groups = (
            self.session.query(Group.id)
            .join(GroupEdge, Group.id == GroupEdge.group_id)
            .join(User, User.id == GroupEdge.member_pk)
            .filter(
                Group.enabled == True,
                User.id == user.id,
                GroupEdge.active == True,
                GroupEdge.member_type == OBJ_TYPES["User"],
                GroupEdge._role != GROUP_EDGE_ROLES.index("np-owner"),
                or_(GroupEdge.expiration > now, GroupEdge.expiration == None),
            )
            .distinct()
        )
        group_ids = [g.id for g in groups]

        # If the user was not a member of any group, we can return early.
        if not group_ids:
            return []

        # Now, get the parent groups of those groups and so forth until we run out of levels of the
        # tree.  Use a set of seen group_ids to avoid querying the same group twice if a user is a
        # member of it via multiple paths.
        seen_group_ids = set(group_ids)
        while group_ids:
            parent_groups = (
                self.session.query(Group.id)
                .join(GroupEdge, Group.id == GroupEdge.group_id)
                .filter(
                    GroupEdge.member_pk.in_(group_ids),
                    Group.enabled == True,
                    GroupEdge.active == True,
                    GroupEdge.member_type == OBJ_TYPES["Group"],
                    GroupEdge._role != GROUP_EDGE_ROLES.index("np-owner"),
                    or_(GroupEdge.expiration > now, GroupEdge.expiration == None),
                )
                .distinct()
            )
            group_ids = [g.id for g in parent_groups if g.id not in seen_group_ids]
            seen_group_ids.update(group_ids)

        # Return the permission grants.
        group_permission_grants = (
            self.session.query(Permission.name, PermissionMap.argument)
            .filter(
                Permission.id == PermissionMap.permission_id,
                PermissionMap.group_id.in_(seen_group_ids),
            )
            .all()
        )
        return [PermissionGrant(g.name, g.argument) for g in group_permission_grants]
Exemple #2
0
def test_group_edge_roles_order_unchanged():
    # The order of the GROUP_EDGE_ROLES tuple matters:  new roles must be
    # appended.  This test attempts exposes that information to help prevent
    # that from happening accidentally.
    assert GROUP_EDGE_ROLES.index("member") == 0
    assert GROUP_EDGE_ROLES.index("manager") == 1
    assert GROUP_EDGE_ROLES.index("owner") == 2
    assert GROUP_EDGE_ROLES.index("np-owner") == 3
Exemple #3
0
def user_role_index(user, members):
    if user_is_group_admin(user.session, user):
        return GROUP_EDGE_ROLES.index("owner")
    member = members.get(("User", user.name))
    if not member:
        return None
    return member.role
    def permission_grants_for_user(self, name):
        # type: (str) -> List[GroupPermissionGrant]
        """Return all permission grants a user has from whatever source.

        TODO(rra): Currently does not expand permission aliases, and therefore doesn't match the
        graph behavior.  Use with caution until that is fixed.
        """
        now = datetime.utcnow()
        user = User.get(self.session, name=name)
        if not user or user.role_user or user.is_service_account or not user.enabled:
            return []

        # Get the groups of which this user is a direct member.
        groups = (self.session.query(Group.id).join(
            GroupEdge, Group.id == GroupEdge.group_id).join(
                User, User.id == GroupEdge.member_pk).filter(
                    Group.enabled == True,
                    User.id == user.id,
                    GroupEdge.active == True,
                    GroupEdge.member_type == OBJ_TYPES["User"],
                    GroupEdge._role != GROUP_EDGE_ROLES.index("np-owner"),
                    or_(GroupEdge.expiration > now,
                        GroupEdge.expiration == None),
                ).distinct())
        group_ids = [g.id for g in groups]

        # If the user was not a member of any group, we can return early.
        if not group_ids:
            return []

        # Now, return all the permission grants for those groups.
        return self._permission_grants_for_group_ids(group_ids)
    def _permission_grants_for_group_ids(self, group_ids):
        # type: (Iterable[int]) -> List[GroupPermissionGrant]
        """Given a set of group IDs, return all direct or inherited permission grants.

        Used to build the full list of permission grants for a set of groups, taking inheritance
        into account.  Shared code between permission_grants_for_user and
        permission_grants_for_group.

        TODO(rra): Currently does not expand permission aliases, and therefore doesn't match the
        graph behavior.
        """
        # Get the parent groups of the initial groups, repeating until we run out of levels of the
        # tree.  Use a set of seen group_ids to avoid querying the same group twice if a user is a
        # member of it via multiple paths.
        now = datetime.utcnow()
        seen_group_ids = set(group_ids)
        while group_ids:
            parent_groups = (self.session.query(Group.id).join(
                GroupEdge, Group.id == GroupEdge.group_id).filter(
                    GroupEdge.member_pk.in_(group_ids),
                    Group.enabled == True,
                    GroupEdge.active == True,
                    GroupEdge.member_type == OBJ_TYPES["Group"],
                    GroupEdge._role != GROUP_EDGE_ROLES.index("np-owner"),
                    or_(GroupEdge.expiration > now,
                        GroupEdge.expiration == None),
                ).distinct())
            group_ids = [
                g.id for g in parent_groups if g.id not in seen_group_ids
            ]
            seen_group_ids.update(group_ids)

        # Return the permission grants.
        group_permission_grants = (self.session.query(
            Group.groupname,
            Permission.name,
            PermissionMap.argument,
            PermissionMap.granted_on,
            PermissionMap.id,
        ).filter(
            Permission.id == PermissionMap.permission_id,
            PermissionMap.group_id.in_(seen_group_ids),
            Group.id == PermissionMap.group_id,
        ).all())
        return [
            GroupPermissionGrant(
                group=g.groupname,
                permission=g.name,
                argument=g.argument,
                granted_on=g.granted_on,
                is_alias=False,
                grant_id=g.id,
            ) for g in group_permission_grants
        ]
Exemple #6
0
def _create_edge(session, group, member, role):
    # type: (Session, Group, Union[User, Group], str) -> GroupEdge
    edge, new = GroupEdge.get_or_create(session,
                                        group_id=group.id,
                                        member_type=member.member_type,
                                        member_pk=member.id)

    if new:
        # TODO(herb): this means all requests by this user to this group will
        # have the same role. we should probably record the role specifically
        # on the request and use that as the source on the UI
        edge._role = GROUP_EDGE_ROLES.index(role)

    session.flush()

    return edge
Exemple #7
0
 def add_group_to_group(self, member, group):
     # type: (str, str) -> None
     self.create_group(member)
     self.create_group(group)
     member_obj = Group.get(self.session, name=member)
     assert member_obj
     group_obj = Group.get(self.session, name=group)
     assert group_obj
     edge = GroupEdge(
         group_id=group_obj.id,
         member_type=OBJ_TYPES["Group"],
         member_pk=member_obj.id,
         active=True,
         _role=GROUP_EDGE_ROLES.index("member"),
     )
     edge.add(self.session)
Exemple #8
0
 def add_user_to_group(self, user, group, role="member"):
     # type: (str, str, str) -> None
     self.create_user(user)
     self.create_group(group)
     user_obj = User.get(self.session, name=user)
     assert user_obj
     group_obj = Group.get(self.session, name=group)
     assert group_obj
     edge = GroupEdge(
         group_id=group_obj.id,
         member_type=OBJ_TYPES["User"],
         member_pk=user_obj.id,
         active=True,
         _role=GROUP_EDGE_ROLES.index(role),
     )
     edge.add(self.session)
Exemple #9
0
 def add_user_to_group(self, user, group, role="member", expiration=None):
     # type: (str, str, str, Optional[datetime]) -> None
     self.create_user(user)
     self.create_group(group)
     user_obj = User.get(self.session, name=user)
     assert user_obj
     group_obj = Group.get(self.session, name=group)
     assert group_obj
     edge = GroupEdge(
         group_id=group_obj.id,
         member_type=OBJ_TYPES["User"],
         member_pk=user_obj.id,
         expiration=expiration,
         active=True,
         _role=GROUP_EDGE_ROLES.index(role),
     )
     edge.add(self.session)
Exemple #10
0
 def groups_of_user(self, username):
     # type: (str) -> List[str]
     now = datetime.utcnow()
     user = User.get(self.session, name=username)
     if not user or user.role_user or user.is_service_account or not user.enabled:
         return []
     groups = (self.session.query(Group.groupname).join(
         GroupEdge, Group.id == GroupEdge.group_id).join(
             User, User.id == GroupEdge.member_pk).filter(
                 Group.enabled == True,
                 User.id == user.id,
                 GroupEdge.active == True,
                 GroupEdge.member_type == OBJ_TYPES["User"],
                 GroupEdge._role != GROUP_EDGE_ROLES.index("np-owner"),
                 or_(GroupEdge.expiration > now,
                     GroupEdge.expiration == None),
             ).distinct())
     return [g.groupname for g in groups]
    def will_update_group_membership(self, session, group, member, **updates):
        if member.member_type != OBJ_TYPES["User"]:
            return

        check_permanent_owners = False

        if "role" in updates:
            role_idx = GROUP_EDGE_ROLES.index(updates["role"])
            if role_idx not in OWNER_ROLE_INDICES:
                check_permanent_owners = True

        if updates.get("expiration"):
            check_permanent_owners = True

        if "active" in updates and not updates["active"]:
            check_permanent_owners = True

        if check_permanent_owners and _is_last_permanent_owner(session, group, member):
            raise PluginRejectedGroupMembershipUpdate(EXCEPTION_MESSAGE)
Exemple #12
0
    def role(self, role):
        # type: (str) -> None
        prev_role = self._role
        self._role = GROUP_EDGE_ROLES.index(role)

        # Groups should always "member".
        if not (OBJ_TYPES_IDX[self.member_type] == "User"):
            return

        # If ownership status is unchanged, no notices need to be adjusted.
        if (self._role in OWNER_ROLE_INDICES) == (prev_role
                                                  in OWNER_ROLE_INDICES):
            return

        user = User.get(self.session, pk=self.member_pk)
        assert user
        recipient = user.username
        expiring_supergroups = self.group.my_expiring_groups()
        member_name = self.group.name

        if role in ["owner", "np-owner"]:
            # We're creating a new owner, who should find out when this group
            # they now own loses its membership in larger groups.
            for supergroup_name, expiration in expiring_supergroups:
                add_expiration(
                    self.session,
                    expiration,
                    group_name=supergroup_name,
                    member_name=member_name,
                    recipients=[recipient],
                    member_is_user=False,
                )
        else:
            # We're removing an owner, who should no longer find out when this
            # group they no longer own loses its membership in larger groups.
            for supergroup_name, _ in expiring_supergroups:
                cancel_expiration(
                    self.session,
                    group_name=supergroup_name,
                    member_name=member_name,
                    recipients=[recipient],
                )
Exemple #13
0
    def will_update_group_membership(self, session, group, member, **updates):
        if member.member_type != OBJ_TYPES["User"]:
            return

        check_permanent_owners = False

        if "role" in updates:
            role_idx = GROUP_EDGE_ROLES.index(updates["role"])
            if role_idx not in OWNER_ROLE_INDICES:
                check_permanent_owners = True

        if updates.get("expiration"):
            check_permanent_owners = True

        if "active" in updates and not updates["active"]:
            check_permanent_owners = True

        if check_permanent_owners and _is_last_permanent_owner(
                session, group, member):
            raise PluginRejectedGroupMembershipUpdate(EXCEPTION_MESSAGE)
Exemple #14
0
    def role(self, role):
        # type: (str) -> None
        prev_role = self._role
        self._role = GROUP_EDGE_ROLES.index(role)

        # Groups should always "member".
        if not (OBJ_TYPES_IDX[self.member_type] == "User"):
            return

        # If ownership status is unchanged, no notices need to be adjusted.
        if (self._role in OWNER_ROLE_INDICES) == (prev_role in OWNER_ROLE_INDICES):
            return

        user = User.get(self.session, pk=self.member_pk)
        assert user
        recipient = user.username
        expiring_supergroups = self.group.my_expiring_groups()
        member_name = self.group.name

        if role in ["owner", "np-owner"]:
            # We're creating a new owner, who should find out when this group
            # they now own loses its membership in larger groups.
            for supergroup_name, expiration in expiring_supergroups:
                add_expiration(
                    self.session,
                    expiration,
                    group_name=supergroup_name,
                    member_name=member_name,
                    recipients=[recipient],
                    member_is_user=False,
                )
        else:
            # We're removing an owner, who should no longer find out when this
            # group they no longer own loses its membership in larger groups.
            for supergroup_name, _ in expiring_supergroups:
                cancel_expiration(
                    self.session,
                    group_name=supergroup_name,
                    member_name=member_name,
                    recipients=[recipient],
                )
Exemple #15
0
 def groups_of_user(self, username):
     # type: (str) -> List[str]
     now = datetime.utcnow()
     user = User.get(self.session, name=username)
     if not user or user.role_user or user.is_service_account or not user.enabled:
         return []
     groups = (
         self.session.query(Group.groupname)
         .join(GroupEdge, Group.id == GroupEdge.group_id)
         .join(User, User.id == GroupEdge.member_pk)
         .filter(
             Group.enabled == True,
             User.id == user.id,
             GroupEdge.active == True,
             GroupEdge.member_type == OBJ_TYPES["User"],
             GroupEdge._role != GROUP_EDGE_ROLES.index("np-owner"),
             or_(GroupEdge.expiration > now, GroupEdge.expiration == None),
         )
         .distinct()
     )
     return [g.groupname for g in groups]
Exemple #16
0
    def permission_grants_for_user(self, name):
        # type: (str) -> List[GroupPermissionGrant]
        """Return all permission grants a user has from whatever source.

        TODO(rra): Currently does not expand permission aliases, and therefore doesn't match the
        graph behavior.  Use with caution until that is fixed.
        """
        now = datetime.utcnow()
        user = User.get(self.session, name=name)
        if not user or user.role_user or user.is_service_account or not user.enabled:
            return []

        # Get the groups of which this user is a direct member.
        groups = (
            self.session.query(Group.id)
            .join(GroupEdge, Group.id == GroupEdge.group_id)
            .join(User, User.id == GroupEdge.member_pk)
            .filter(
                Group.enabled == True,
                User.id == user.id,
                GroupEdge.active == True,
                GroupEdge.member_type == OBJ_TYPES["User"],
                GroupEdge._role != GROUP_EDGE_ROLES.index("np-owner"),
                or_(GroupEdge.expiration > now, GroupEdge.expiration == None),
            )
            .distinct()
        )
        group_ids = [g.id for g in groups]

        # If the user was not a member of any group, we can return early.
        if not group_ids:
            return []

        # Now, get the parent groups of those groups and so forth until we run out of levels of the
        # tree.  Use a set of seen group_ids to avoid querying the same group twice if a user is a
        # member of it via multiple paths.
        seen_group_ids = set(group_ids)
        while group_ids:
            parent_groups = (
                self.session.query(Group.id)
                .join(GroupEdge, Group.id == GroupEdge.group_id)
                .filter(
                    GroupEdge.member_pk.in_(group_ids),
                    Group.enabled == True,
                    GroupEdge.active == True,
                    GroupEdge.member_type == OBJ_TYPES["Group"],
                    GroupEdge._role != GROUP_EDGE_ROLES.index("np-owner"),
                    or_(GroupEdge.expiration > now, GroupEdge.expiration == None),
                )
                .distinct()
            )
            group_ids = [g.id for g in parent_groups if g.id not in seen_group_ids]
            seen_group_ids.update(group_ids)

        # Return the permission grants.
        group_permission_grants = (
            self.session.query(
                Group.groupname,
                Permission.name,
                PermissionMap.argument,
                PermissionMap.granted_on,
                PermissionMap.id,
            )
            .filter(
                Permission.id == PermissionMap.permission_id,
                PermissionMap.group_id.in_(seen_group_ids),
                Group.id == PermissionMap.group_id,
            )
            .all()
        )
        return [
            GroupPermissionGrant(
                group=g.groupname,
                permission=g.name,
                argument=g.argument,
                granted_on=g.granted_on,
                is_alias=False,
                grant_id=g.id,
            )
            for g in group_permission_grants
        ]
Exemple #17
0
    def permission_grants_for_user(self, name):
        # type: (str) -> List[GroupPermissionGrant]
        """Return all permission grants a user has from whatever source.

        TODO(rra): Currently does not expand permission aliases, and therefore doesn't match the
        graph behavior.  Use with caution until that is fixed.
        """
        now = datetime.utcnow()
        user = User.get(self.session, name=name)
        if not user or user.role_user or user.is_service_account or not user.enabled:
            return []

        # Get the groups of which this user is a direct member.
        groups = (self.session.query(Group.id).join(
            GroupEdge, Group.id == GroupEdge.group_id).join(
                User, User.id == GroupEdge.member_pk).filter(
                    Group.enabled == True,
                    User.id == user.id,
                    GroupEdge.active == True,
                    GroupEdge.member_type == OBJ_TYPES["User"],
                    GroupEdge._role != GROUP_EDGE_ROLES.index("np-owner"),
                    or_(GroupEdge.expiration > now,
                        GroupEdge.expiration == None),
                ).distinct())
        group_ids = [g.id for g in groups]

        # If the user was not a member of any group, we can return early.
        if not group_ids:
            return []

        # Now, get the parent groups of those groups and so forth until we run out of levels of the
        # tree.  Use a set of seen group_ids to avoid querying the same group twice if a user is a
        # member of it via multiple paths.
        seen_group_ids = set(group_ids)
        while group_ids:
            parent_groups = (self.session.query(Group.id).join(
                GroupEdge, Group.id == GroupEdge.group_id).filter(
                    GroupEdge.member_pk.in_(group_ids),
                    Group.enabled == True,
                    GroupEdge.active == True,
                    GroupEdge.member_type == OBJ_TYPES["Group"],
                    GroupEdge._role != GROUP_EDGE_ROLES.index("np-owner"),
                    or_(GroupEdge.expiration > now,
                        GroupEdge.expiration == None),
                ).distinct())
            group_ids = [
                g.id for g in parent_groups if g.id not in seen_group_ids
            ]
            seen_group_ids.update(group_ids)

        # Return the permission grants.
        group_permission_grants = (self.session.query(
            Group.groupname,
            Permission.name,
            PermissionMap.argument,
            PermissionMap.granted_on,
            PermissionMap.id,
        ).filter(
            Permission.id == PermissionMap.permission_id,
            PermissionMap.group_id.in_(seen_group_ids),
            Group.id == PermissionMap.group_id,
        ).all())
        return [
            GroupPermissionGrant(
                group=g.groupname,
                permission=g.name,
                argument=g.argument,
                granted_on=g.granted_on,
                is_alias=False,
                grant_id=g.id,
            ) for g in group_permission_grants
        ]