Example #1
0
def can_approve_request(session, request, owner, group_ids=None, owners_by_arg_by_perm=None):
    owner_arg_list = get_owner_arg_list(session, request.permission, request.argument,
            owners_by_arg_by_perm)
    if group_ids is None:
        group_ids = {g.id for g, _ in get_groups_by_user(session, owner)}

    return group_ids.intersection([o.id for o, arg in owner_arg_list])
Example #2
0
    def _build_form(self, data):
        # type: (Optional[int]) -> Tuple[PermissionRequestForm, Dict[str, List[str]]]
        """Build the permission request form given the request and POST data.

        Normally all fields of the form will be editable.  But if the URL
        locks down a specific value for the group, permission, or argument,
        then the specified fields will display those values and will be
        grayed out and not editable.

        """
        session = self.session
        current_user = self.current_user

        def pairs(seq):
            # type: (Iterable[str]) -> List[Tuple[str, str]]
            return [(item, item) for item in seq]

        form = PermissionRequestForm(data)

        group_names = {
            g.groupname
            for g, e in get_groups_by_user(session, current_user)
        }
        args_by_perm = get_grantable_permissions(
            session,
            settings().restricted_ownership_permissions)
        permission_names = {p for p in args_by_perm}

        group_param = self.get_argument("group", None)
        if group_param is not None:
            if group_param not in group_names:
                raise HTTPError(
                    status_code=404,
                    reason="the group name in the URL is not one you belong to"
                )
            form.group_name.choices = pairs([group_param])
            form.group_name.render_kw = {"readonly": "readonly"}
            form.group_name.data = group_param
        else:
            form.group_name.choices = pairs([""] + sorted(group_names))

        permission_param = self.get_argument("permission", None)
        if permission_param is not None:
            if permission_param not in permission_names:
                raise HTTPError(
                    status_code=404,
                    reason="an unrecognized permission is specified in the URL"
                )
            form.permission.choices = pairs([permission_param])
            form.permission.render_kw = {"readonly": "readonly"}
            form.permission.data = permission_param
        else:
            form.permission.choices = pairs(sorted(permission_names))

        argument_param = self.get_argument("argument", "")
        if argument_param:
            form.argument.render_kw = {"readonly": "readonly"}
            form.argument.data = argument_param

        return form, args_by_perm
Example #3
0
def can_approve_request(session, request, owner, group_ids=None, owners_by_arg_by_perm=None):
    owner_arg_list = get_owner_arg_list(session, request.permission, request.argument,
            owners_by_arg_by_perm)
    if group_ids is None:
        group_ids = {g.id for g, _ in get_groups_by_user(session, owner)}

    return group_ids.intersection([o.id for o, arg in owner_arg_list])
Example #4
0
def get_requests_by_owner(session, owner, status, limit, offset):
    """Load pending requests for a particular owner.

    Args:
        session(sqlalchemy.orm.session.Session): database session
        owner(models.User): model of user in question
        status(models.base.constants.REQUEST_STATUS_CHOICES): if not None,
                filter by particular status
        limit(int): how many results to return
        offset(int): the offset into the result set that should be applied

    Returns:
        2-tuple of (Requests, total) where total is total result size and
        Requests is the namedtuple with requests and associated
        comments/changes.
    """
    # get owners groups
    group_ids = {g.id for g, _ in get_groups_by_user(session, owner)}

    # get all requests
    all_requests = session.query(PermissionRequest)
    if status:
        all_requests = all_requests.filter(PermissionRequest.status == status)

    all_requests = all_requests.order_by(
        PermissionRequest.requested_at.desc()).all()

    owners_by_arg_by_perm = get_owners_by_grantable_permission(session)

    requests = []
    for request in all_requests:
        if can_approve_request(session,
                               request,
                               owner,
                               group_ids=group_ids,
                               owners_by_arg_by_perm=owners_by_arg_by_perm):
            requests.append(request)

    total = len(requests)
    requests = requests[offset:limit]

    status_change_by_request_id = defaultdict(list)
    if not requests:
        comment_by_status_change_id = {}
    else:
        status_changes = session.query(PermissionRequestStatusChange).filter(
            PermissionRequestStatusChange.request_id.in_(
                [r.id for r in requests]), ).all()
        for sc in status_changes:
            status_change_by_request_id[sc.request_id].append(sc)

        comments = session.query(Comment).filter(
            Comment.obj_type == OBJ_TYPES_IDX.index(
                "PermissionRequestStatusChange"),
            Comment.obj_pk.in_([s.id for s in status_changes]),
        ).all()
        comment_by_status_change_id = {c.obj_pk: c for c in comments}

    return Requests(requests, status_change_by_request_id,
                    comment_by_status_change_id), total
Example #5
0
def get_user_view_template_vars(session, actor, user, graph):
    # type: (Session, User, User, GroupGraph) -> Dict[str, Any]
    # TODO(cbguder): get around circular dependencies
    from grouper.fe.handlers.user_disable import UserDisable
    from grouper.fe.handlers.user_enable import UserEnable

    ret = {}  # type: Dict[str, Any]
    if user.is_service_account:
        ret["can_control"] = can_manage_service_account(
            session, user.service_account, actor
        ) or user_is_user_admin(session, actor)
        ret["can_disable"] = ret["can_control"]
        ret["can_enable"] = user_is_user_admin(session, actor)
        ret["can_enable_preserving_membership"] = user_is_user_admin(session, actor)
        ret["account"] = user.service_account
    else:
        ret["can_control"] = user.name == actor.name or user_is_user_admin(session, actor)
        ret["can_disable"] = UserDisable.check_access(session, actor, user)
        ret["can_enable_preserving_membership"] = UserEnable.check_access(session, actor, user)
        ret["can_enable"] = UserEnable.check_access_without_membership(session, actor, user)

    if user.id == actor.id:
        ret["num_pending_group_requests"] = user_requests_aggregate(session, actor).count()
        _, ret["num_pending_perm_requests"] = get_requests(
            session, status="pending", limit=1, offset=0, owner=actor
        )
    else:
        ret["num_pending_group_requests"] = None
        ret["num_pending_perm_requests"] = None

    try:
        user_md = graph.get_user_details(user.name)
    except NoSuchUser:
        # Either user is probably very new, so they have no metadata yet, or
        # they're disabled, so we've excluded them from the in-memory graph.
        user_md = {}

    shell_metadata = get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY)
    ret["shell"] = shell_metadata.data_value if shell_metadata else "No shell configured"
    github_username = get_user_metadata_by_key(session, user.id, USER_METADATA_GITHUB_USERNAME_KEY)
    ret["github_username"] = github_username.data_value if github_username else "(Unset)"
    ret["open_audits"] = user_open_audits(session, user)
    group_edge_list = get_groups_by_user(session, user) if user.enabled else []
    ret["groups"] = [
        {"name": g.name, "type": "Group", "role": ge._role} for g, ge in group_edge_list
    ]
    ret["passwords"] = user_passwords(session, user)
    ret["public_keys"] = get_public_keys_of_user(session, user.id)
    ret["log_entries"] = get_log_entries_by_user(session, user)
    ret["user_tokens"] = user.tokens

    if user.is_service_account:
        service_account = user.service_account
        ret["permissions"] = service_account_permissions(session, service_account)
    else:
        ret["permissions"] = user_md.get("permissions", [])
        for permission in ret["permissions"]:
            permission["granted_on"] = datetime.fromtimestamp(permission["granted_on"])

    return ret
Example #6
0
    def _get_choices(self, group: Group, member_groups: Set[str],
                     user_is_member: bool) -> List[Tuple[str, str]]:
        choices = []

        if not user_is_member:
            choice = "User: {}".format(self.current_user.name)
            choices.append((choice, choice))

        for _group, group_edge in get_groups_by_user(self.session,
                                                     self.current_user):
            if group.name == _group.name:  # Don't add self.
                continue
            if group_edge._role not in APPROVER_ROLE_INDICES:  # manager, owner, and np-owner only.
                continue
            if _group.name in member_groups:
                continue

            choice = "Group: {}".format(_group.name)
            choices.append((choice, choice))

        # If there are some choices but the user is already a member or has a pending request, add
        # a blank option as the first choice to avoid the user requesting membership on behalf of a
        # group by mistake.
        if choices and user_is_member:
            choices.insert(0, ("", ""))

        return choices
Example #7
0
def can_approve_request(
    session: Session,
    request: PermissionRequest,
    owner: User,
    group_ids: Optional[Set[int]] = None,
    owners_by_arg_by_perm: Optional[Dict[object, Dict[str,
                                                      List[Group]]]] = None,
) -> bool:
    """Determine whether the given owner can approve a permission request.

    Args:
        session: Database session
        request: Pending permission request
        owner: User who may or may not be able to approve the request
        group_ids: If given, the IDs of the groups of which the user is a member (solely so that we
            can avoid another database query if this information is already available)
        owners_by_arg_by_perm: List of permission granters by permission and argument (solely so
            that we can avoid another database query if this information is already available)
    """
    owner_arg_list = get_owner_arg_list(session, request.permission,
                                        request.argument,
                                        owners_by_arg_by_perm)
    if group_ids is None:
        group_ids = {g.id for g, _ in get_groups_by_user(session, owner)}

    return bool(group_ids.intersection([o.id for o, arg in owner_arg_list]))
def get_user_view_template_vars(session, actor, user, graph):
    # TODO(cbguder): get around circular dependencies
    from grouper.fe.handlers.user_disable import UserDisable
    from grouper.fe.handlers.user_enable import UserEnable

    ret = {}
    if user.is_service_account:
        ret["can_control"] = (
            can_manage_service_account(session, user.service_account, actor) or
            user_is_user_admin(session, actor)
        )
        ret["can_disable"] = ret["can_control"]
        ret["can_enable"] = user_is_user_admin(session, actor)
        ret["account"] = user.service_account
    else:
        ret["can_control"] = (user.name == actor.name or user_is_user_admin(session, actor))
        ret["can_disable"] = UserDisable.check_access(session, actor, user)
        ret["can_enable"] = UserEnable.check_access(session, actor, user)

    if user.id == actor.id:
        ret["num_pending_group_requests"] = user_requests_aggregate(session, actor).count()
        _, ret["num_pending_perm_requests"] = get_requests_by_owner(session, actor,
            status='pending', limit=1, offset=0)
    else:
        ret["num_pending_group_requests"] = None
        ret["num_pending_perm_requests"] = None

    try:
        user_md = graph.get_user_details(user.name)
    except NoSuchUser:
        # Either user is probably very new, so they have no metadata yet, or
        # they're disabled, so we've excluded them from the in-memory graph.
        user_md = {}

    shell = (get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY).data_value
        if get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY)
        else "No shell configured")
    ret["shell"] = shell
    ret["open_audits"] = user_open_audits(session, user)
    group_edge_list = get_groups_by_user(session, user) if user.enabled else []
    ret["groups"] = [{'name': g.name, 'type': 'Group', 'role': ge._role}
        for g, ge in group_edge_list]
    ret["passwords"] = user_passwords(session, user)
    ret["public_keys"] = get_public_keys_of_user(session, user.id)
    for key in ret["public_keys"]:
        key.tags = get_public_key_tags(session, key)
        key.pretty_permissions = ["{} ({})".format(perm.name,
            perm.argument if perm.argument else "unargumented")
            for perm in get_public_key_permissions(session, key)]
    ret["log_entries"] = get_log_entries_by_user(session, user)
    ret["user_tokens"] = user.tokens

    if user.is_service_account:
        service_account = user.service_account
        ret["permissions"] = service_account_permissions(session, service_account)
    else:
        ret["permissions"] = user_md.get('permissions', [])

    return ret
Example #9
0
def get_requests_by_owner(session, owner, status, limit, offset):
    """Load pending requests for a particular owner.

    Args:
        session(sqlalchemy.orm.session.Session): database session
        owner(models.User): model of user in question
        status(models.base.constants.REQUEST_STATUS_CHOICES): if not None,
                filter by particular status
        limit(int): how many results to return
        offset(int): the offset into the result set that should be applied

    Returns:
        2-tuple of (Requests, total) where total is total result size and
        Requests is the namedtuple with requests and associated
        comments/changes.
    """
    # get owners groups
    group_ids = {g.id for g, _ in get_groups_by_user(session, owner)}

    # get all requests
    all_requests = session.query(PermissionRequest)
    if status:
        all_requests = all_requests.filter(PermissionRequest.status == status)

    all_requests = all_requests.order_by(PermissionRequest.requested_at.desc()).all()

    owners_by_arg_by_perm = get_owners_by_grantable_permission(session)

    requests = []
    for request in all_requests:
        owner_arg_list = get_owner_arg_list(session, request.permission, request.argument,
                owners_by_arg_by_perm)
        if group_ids.intersection([o.id for o, arg in owner_arg_list]):
            requests.append(request)

    total = len(requests)
    requests = requests[offset:limit]

    status_change_by_request_id = defaultdict(list)
    if not requests:
        comment_by_status_change_id = {}
    else:
        status_changes = session.query(PermissionRequestStatusChange).filter(
                    PermissionRequestStatusChange.request_id.in_([r.id for r in requests]),
                    ).all()
        for sc in status_changes:
            status_change_by_request_id[sc.request_id].append(sc)

        comments = session.query(Comment).filter(
                Comment.obj_type == OBJ_TYPES_IDX.index("PermissionRequestStatusChange"),
                Comment.obj_pk.in_([s.id for s in status_changes]),
                ).all()
        comment_by_status_change_id = {c.obj_pk: c for c in comments}

    return Requests(requests, status_change_by_request_id, comment_by_status_change_id), total
Example #10
0
    def _build_form(self, data):
        # type: (Optional[int]) -> Tuple[PermissionRequestForm, Dict[Permission, List[str]]]
        """Build the permission request form given the request and POST data.

        Normally all fields of the form will be editable.  But if the URL
        locks down a specific value for the group, permission, or argument,
        then the specified fields will display those values and will be
        grayed out and not editable.

        """
        session = self.session
        current_user = self.current_user

        def pairs(seq):
            # type: (Iterable[str]) -> List[Tuple[str, str]]
            return [(item, item) for item in seq]

        form = PermissionRequestForm(data)

        group_names = {g.groupname for g, e in get_groups_by_user(session, current_user)}
        args_by_perm = get_grantable_permissions(
            session, settings().restricted_ownership_permissions
        )
        permission_names = {p for p in args_by_perm}

        group_param = self.get_argument("group", None)
        if group_param is not None:
            if group_param not in group_names:
                raise HTTPError(
                    status_code=404, reason="the group name in the URL is not one you belong to"
                )
            form.group_name.choices = pairs([group_param])
            form.group_name.render_kw = {"readonly": "readonly"}
        else:
            form.group_name.choices = pairs([""] + sorted(group_names))

        permission_param = self.get_argument("permission", None)
        if permission_param is not None:
            if permission_param not in permission_names:
                raise HTTPError(
                    status_code=404, reason="an unrecognized permission is specified in the URL"
                )
            form.permission_name.choices = pairs([permission_param])
            form.permission_name.render_kw = {"readonly": "readonly"}
        else:
            form.permission_name.choices = pairs([""] + sorted(permission_names))

        argument_param = self.get_argument("argument", "")
        if argument_param:
            form.argument.render_kw = {"readonly": "readonly"}
            form.argument.data = argument_param

        return form, args_by_perm
Example #11
0
def get_user_view_template_vars(session, actor, user, graph):
    ret = {}
    ret["can_control"] = (user.name == actor.name
                          or user_is_user_admin(session, actor))
    ret["can_disable"] = UserDisable.check_access(session, actor, user)
    ret["can_enable"] = UserEnable.check_access(session, actor, user)

    if user.id == actor.id:
        ret["num_pending_group_requests"] = user_requests_aggregate(
            session, actor).count()
        _, ret["num_pending_perm_requests"] = get_requests_by_owner(
            session, actor, status='pending', limit=1, offset=0)
    else:
        ret["num_pending_group_requests"] = None
        ret["num_pending_perm_requests"] = None

    try:
        user_md = graph.get_user_details(user.name)
    except NoSuchUser:
        # Either user is probably very new, so they have no metadata yet, or
        # they're disabled, so we've excluded them from the in-memory graph.
        user_md = {}

    shell = (get_user_metadata_by_key(session, user.id,
                                      USER_METADATA_SHELL_KEY).data_value
             if get_user_metadata_by_key(session, user.id,
                                         USER_METADATA_SHELL_KEY) else
             "No shell configured")
    ret["shell"] = shell
    ret["open_audits"] = user_open_audits(session, user)
    group_edge_list = get_groups_by_user(session, user) if user.enabled else []
    ret["groups"] = [{
        'name': g.name,
        'type': 'Group',
        'role': ge._role
    } for g, ge in group_edge_list]
    ret["passwords"] = user_passwords(session, user)
    ret["public_keys"] = get_public_keys_of_user(session, user.id)
    for key in ret["public_keys"]:
        key.tags = get_public_key_tags(session, key)
        key.pretty_permissions = [
            "{} ({})".format(
                perm.name, perm.argument if perm.argument else "unargumented")
            for perm in get_public_key_permissions(session, key)
        ]
    ret["permissions"] = user_md.get('permissions', [])
    ret["log_entries"] = get_log_entries_by_user(session, user)
    ret["user_tokens"] = user.tokens

    return ret
Example #12
0
    def _get_choices(self, group):
        choices = []

        members = group.my_members()

        if ("User", self.current_user.name) not in members:
            choices.append(("User: {}".format(self.current_user.name),) * 2)

        for _group, group_edge in get_groups_by_user(self.session, self.current_user):
            if group.name == _group.name:  # Don't add self.
                continue
            if group_edge._role not in APPROVER_ROLE_INDICES:  # manager, owner, and np-owner only.
                continue
            if ("Group", _group.name) in members:
                continue

            choices.append(("Group: {}".format(_group.name),) * 2)

        return choices
Example #13
0
    def _get_choices(self, group):
        choices = []

        members = group.my_members()

        if ("User", self.current_user.name) not in members:
            choices.append(("User: {}".format(self.current_user.name),) * 2)

        for _group, group_edge in get_groups_by_user(self.session, self.current_user):
            if group.name == _group.name:  # Don't add self.
                continue
            if group_edge._role not in APPROVER_ROLE_INDICIES:  # manager, owner, and np-owner only.
                continue
            if ("Group", _group.name) in members:
                continue

            choices.append(("Group: {}".format(_group.name),) * 2)

        return choices
Example #14
0
def enable_user(session, user, requester, preserve_membership):
    """Enable a disabled user.

    Args:
        preserve_membership(bool): whether to remove user from any groups it may be a member of
    Returns:
        None
    """
    if not preserve_membership:
        for group, group_edge in get_groups_by_user(session, user):
            group_obj = session.query(Group).filter_by(
                groupname=group.name
            ).scalar()
            if group_obj:
                group_obj.revoke_member(
                    requester, user, "group membership stripped as part of re-enabling account."
                )

    user.enabled = True
    Counter.incr(session, "updates")
Example #15
0
def enable_user(session, user, requester, preserve_membership):
    """Enable a disabled user.

    Args:
        preserve_membership(bool): whether to remove user from any groups it may be a member of
    Returns:
        None
    """
    if not preserve_membership:
        for group, group_edge in get_groups_by_user(session, user):
            group_obj = session.query(Group).filter_by(
                groupname=group.name).scalar()
            if group_obj:
                group_obj.revoke_member(
                    requester, user,
                    "group membership stripped as part of re-enabling account."
                )

    user.enabled = True
    Counter.incr(session, "updates")
Example #16
0
    def _get_choices(self, group):
        # type: (Group) -> List[Tuple[str, ...]]
        # This returns List[Tuple[str, str]], but mypy is confused by the * 2 syntax.
        choices = []

        members = group.my_members()

        if ("User", self.current_user.name) not in members:
            choices.append(("User: {}".format(self.current_user.name),) * 2)

        for _group, group_edge in get_groups_by_user(self.session, self.current_user):
            if group.name == _group.name:  # Don't add self.
                continue
            if group_edge._role not in APPROVER_ROLE_INDICES:  # manager, owner, and np-owner only.
                continue
            if ("Group", _group.name) in members:
                continue

            choices.append(("Group: {}".format(_group.name),) * 2)

        return choices
Example #17
0
    def _get_choices(self, group):
        # type: (Group) -> List[Tuple[str, ...]]
        # This returns List[Tuple[str, str]], but mypy is confused by the * 2 syntax.
        choices = []

        members = group.my_members()

        if ("User", self.current_user.name) not in members:
            choices.append(("User: {}".format(self.current_user.name), ) * 2)

        for _group, group_edge in get_groups_by_user(self.session,
                                                     self.current_user):
            if group.name == _group.name:  # Don't add self.
                continue
            if group_edge._role not in APPROVER_ROLE_INDICES:  # manager, owner, and np-owner only.
                continue
            if ("Group", _group.name) in members:
                continue

            choices.append(("Group: {}".format(_group.name), ) * 2)

        return choices
def get_user_view_template_vars(session, actor, user, graph):
    # TODO(cbguder): get around circular dependencies
    from grouper.fe.handlers.user_disable import UserDisable
    from grouper.fe.handlers.user_enable import UserEnable

    ret = {}
    if user.is_service_account:
        ret["can_control"] = can_manage_service_account(
            session, user.service_account, actor
        ) or user_is_user_admin(session, actor)
        ret["can_disable"] = ret["can_control"]
        ret["can_enable"] = user_is_user_admin(session, actor)
        ret["can_enable_preserving_membership"] = user_is_user_admin(session, actor)
        ret["account"] = user.service_account
    else:
        ret["can_control"] = user.name == actor.name or user_is_user_admin(session, actor)
        ret["can_disable"] = UserDisable.check_access(session, actor, user)
        ret["can_enable_preserving_membership"] = UserEnable.check_access(session, actor, user)
        ret["can_enable"] = UserEnable.check_access_without_membership(session, actor, user)

    if user.id == actor.id:
        ret["num_pending_group_requests"] = user_requests_aggregate(session, actor).count()
        _, ret["num_pending_perm_requests"] = get_requests(
            session, status="pending", limit=1, offset=0, owner=actor
        )
    else:
        ret["num_pending_group_requests"] = None
        ret["num_pending_perm_requests"] = None

    try:
        user_md = graph.get_user_details(user.name)
    except NoSuchUser:
        # Either user is probably very new, so they have no metadata yet, or
        # they're disabled, so we've excluded them from the in-memory graph.
        user_md = {}

    shell = (
        get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY).data_value
        if get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY)
        else "No shell configured"
    )
    ret["shell"] = shell
    ret["open_audits"] = user_open_audits(session, user)
    group_edge_list = get_groups_by_user(session, user) if user.enabled else []
    ret["groups"] = [
        {"name": g.name, "type": "Group", "role": ge._role} for g, ge in group_edge_list
    ]
    ret["passwords"] = user_passwords(session, user)
    ret["public_keys"] = get_public_keys_of_user(session, user.id)
    for key in ret["public_keys"]:
        key.tags = get_public_key_tags(session, key)
        key.pretty_permissions = [
            "{} ({})".format(perm.name, perm.argument if perm.argument else "unargumented")
            for perm in get_public_key_permissions(session, key)
        ]
    ret["log_entries"] = get_log_entries_by_user(session, user)
    ret["user_tokens"] = user.tokens

    if user.is_service_account:
        service_account = user.service_account
        ret["permissions"] = service_account_permissions(session, service_account)
    else:
        ret["permissions"] = user_md.get("permissions", [])

    return ret
Example #19
0
def get_requests(
    session: Session,
    status: str,
    limit: int,
    offset: int,
    owner: Optional[User] = None,
    requester: Optional[User] = None,
    owners_by_arg_by_perm: Optional[Dict[object, Dict[str,
                                                      List[Group]]]] = None,
) -> Tuple[Requests, int]:
    """Load requests using the given filters.

    Args:
        session: Database session
        status: If not None, filter by particular status
        limit: how many results to return
        offset: the offset into the result set that should be applied
        owner: If not None, filter by requests that the owner can action
        requester: If not None, filter by requests that the requester made
        owners_by_arg_by_perm: List of groups that can grant a given permission, argument pair in
            the format of
            {perm_name: {argument: [group1, group2, ...], ...}, ...}
            This is for convenience/caching if the value has already been fetched.

    Returns:
        2-tuple of (Requests, total) where total is total result size and Requests is the
        data transfer object with requests and associated comments/changes.
    """
    # get all requests
    all_requests = session.query(PermissionRequest)
    if status:
        all_requests = all_requests.filter(PermissionRequest.status == status)
    if requester:
        all_requests = all_requests.filter(
            PermissionRequest.requester_id == requester.id)

    all_requests = all_requests.order_by(
        PermissionRequest.requested_at.desc()).all()

    if owners_by_arg_by_perm is None:
        owners_by_arg_by_perm = get_owners_by_grantable_permission(session)

    if owner:
        group_ids = {g.id for g, _ in get_groups_by_user(session, owner)}
        requests = [
            request for request in all_requests if can_approve_request(
                session,
                request,
                owner,
                group_ids=group_ids,
                owners_by_arg_by_perm=owners_by_arg_by_perm,
            )
        ]
    else:
        requests = all_requests

    total = len(requests)
    requests = requests[offset:limit]

    status_change_by_request_id: Dict[
        int, List[PermissionRequestStatusChange]] = defaultdict(list)
    if not requests:
        comment_by_status_change_id: Dict[int, Comment] = {}
    else:
        status_changes = (session.query(PermissionRequestStatusChange).filter(
            PermissionRequestStatusChange.request_id.in_(
                [r.id for r in requests])).all())
        for sc in status_changes:
            status_change_by_request_id[sc.request_id].append(sc)

        comments = (session.query(Comment).filter(
            Comment.obj_type == OBJ_TYPES_IDX.index(
                "PermissionRequestStatusChange"),
            Comment.obj_pk.in_([s.id for s in status_changes]),
        ).all())
        comment_by_status_change_id = {c.obj_pk: c for c in comments}

    return (Requests(requests, status_change_by_request_id,
                     comment_by_status_change_id), total)
Example #20
0
def get_user_view_template_vars(session, actor, user, graph):
    # type: (Session, User, User, GroupGraph) -> Dict[str, Any]
    # TODO(cbguder): get around circular dependencies
    from grouper.fe.handlers.user_disable import UserDisable
    from grouper.fe.handlers.user_enable import UserEnable

    ret = {}  # type: Dict[str, Any]
    if user.is_service_account:
        ret["can_control"] = can_manage_service_account(
            session, user.service_account, actor
        ) or user_is_user_admin(session, actor)
        ret["can_disable"] = ret["can_control"]
        ret["can_enable"] = user_is_user_admin(session, actor)
        ret["can_enable_preserving_membership"] = user_is_user_admin(session, actor)
        ret["account"] = user.service_account
    else:
        ret["can_control"] = user.name == actor.name or user_is_user_admin(session, actor)
        ret["can_disable"] = UserDisable.check_access(session, actor, user)
        ret["can_enable_preserving_membership"] = UserEnable.check_access(session, actor, user)
        ret["can_enable"] = UserEnable.check_access_without_membership(session, actor, user)

    if user.id == actor.id:
        ret["num_pending_group_requests"] = user_requests_aggregate(session, actor).count()
        _, ret["num_pending_perm_requests"] = get_requests(
            session, status="pending", limit=1, offset=0, owner=actor
        )
    else:
        ret["num_pending_group_requests"] = None
        ret["num_pending_perm_requests"] = None

    try:
        user_md = graph.get_user_details(user.name)
    except NoSuchUser:
        # Either user is probably very new, so they have no metadata yet, or
        # they're disabled, so we've excluded them from the in-memory graph.
        user_md = {}

    shell = (
        get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY).data_value
        if get_user_metadata_by_key(session, user.id, USER_METADATA_SHELL_KEY)
        else "No shell configured"
    )
    ret["shell"] = shell
    github_username = get_user_metadata_by_key(session, user.id, USER_METADATA_GITHUB_USERNAME_KEY)
    ret["github_username"] = github_username.data_value if github_username else "(Unset)"
    ret["open_audits"] = user_open_audits(session, user)
    group_edge_list = get_groups_by_user(session, user) if user.enabled else []
    ret["groups"] = [
        {"name": g.name, "type": "Group", "role": ge._role} for g, ge in group_edge_list
    ]
    ret["passwords"] = user_passwords(session, user)
    ret["public_keys"] = get_public_keys_of_user(session, user.id)
    ret["log_entries"] = get_log_entries_by_user(session, user)
    ret["user_tokens"] = user.tokens

    if user.is_service_account:
        service_account = user.service_account
        ret["permissions"] = service_account_permissions(session, service_account)
    else:
        ret["permissions"] = user_md.get("permissions", [])
        for permission in ret["permissions"]:
            permission["granted_on"] = datetime.fromtimestamp(permission["granted_on"])

    return ret
Example #21
0
def get_requests(
    session, status, limit, offset, owner=None, requester=None, owners_by_arg_by_perm=None
):
    """Load requests using the given filters.

    Args:
        session(sqlalchemy.orm.session.Session): database session
        status(models.base.constants.REQUEST_STATUS_CHOICES): if not None,
                filter by particular status
        limit(int): how many results to return
        offset(int): the offset into the result set that should be applied
        owner(models.User): if not None, filter by requests that the owner
            can action
        requester(models.User): if not None, filter by requests that the
            requester made
        owners_by_arg_by_perm(Dict): list of groups that can grant a given
            permission, argument pair in the format of
            {perm_name: {argument: [group1, group2, ...], ...}, ...}
            This is for convenience/caching if the value has already been fetched.

    Returns:
        2-tuple of (Requests, total) where total is total result size and
        Requests is the namedtuple with requests and associated
        comments/changes.
    """
    # get all requests
    all_requests = session.query(PermissionRequest)
    if status:
        all_requests = all_requests.filter(PermissionRequest.status == status)
    if requester:
        all_requests = all_requests.filter(PermissionRequest.requester_id == requester.id)

    all_requests = all_requests.order_by(PermissionRequest.requested_at.desc()).all()

    if owners_by_arg_by_perm is None:
        owners_by_arg_by_perm = get_owners_by_grantable_permission(session)

    if owner:
        group_ids = {g.id for g, _ in get_groups_by_user(session, owner)}
        requests = [
            request
            for request in all_requests
            if can_approve_request(
                session,
                request,
                owner,
                group_ids=group_ids,
                owners_by_arg_by_perm=owners_by_arg_by_perm,
            )
        ]
    else:
        requests = all_requests

    total = len(requests)
    requests = requests[offset:limit]

    status_change_by_request_id = defaultdict(list)
    if not requests:
        comment_by_status_change_id = {}
    else:
        status_changes = (
            session.query(PermissionRequestStatusChange)
            .filter(PermissionRequestStatusChange.request_id.in_([r.id for r in requests]))
            .all()
        )
        for sc in status_changes:
            status_change_by_request_id[sc.request_id].append(sc)

        comments = (
            session.query(Comment)
            .filter(
                Comment.obj_type == OBJ_TYPES_IDX.index("PermissionRequestStatusChange"),
                Comment.obj_pk.in_([s.id for s in status_changes]),
            )
            .all()
        )
        comment_by_status_change_id = {c.obj_pk: c for c in comments}

    return (Requests(requests, status_change_by_request_id, comment_by_status_change_id), total)