コード例 #1
0
ファイル: test_grouper_ctl.py プロジェクト: Acidity/grouper
def test_oneoff(mock_make_session, mock_annex, mock_load_plugins, session):
    mock_make_session.return_value = session
    username = '******'
    other_username = '******'
    groupname = 'fake_group'

    class FakeOneOff(object):
        def configure(self, service_name):
            pass

        def run(self, session, **kwargs):
            if kwargs.get('group'):
                Group.get_or_create(session, groupname=groupname)
                session.commit()
            elif kwargs.get('key') == 'valuewith=':
                User.get_or_create(session, username=other_username)
                session.commit()
            else:
                User.get_or_create(session, username=username)
                session.commit()

    mock_annex.return_value = [FakeOneOff()]

    # dry_run
    call_main('oneoff', 'run', 'FakeOneOff')
    assert User.get(session,
                    name=username) is None, 'default dry_run means no writes'
    assert User.get(session,
                    name=other_username) is None, '"valuewith= not in arg'
    assert Group.get(
        session,
        name=groupname) is None, '"group" not in arg so no group created'

    # not dry_run, create a user
    call_main('oneoff', 'run', '--no-dry_run', 'FakeOneOff')
    assert User.get(session,
                    name=username) is not None, 'dry_run off means writes'
    assert User.get(session,
                    name=other_username) is None, '"valuewith= not in arg'
    assert Group.get(
        session,
        name=groupname) is None, '"group" not in arg so no group created'

    # not dry_run, use kwarg to create a group
    call_main('oneoff', 'run', '--no-dry_run', 'FakeOneOff', 'group=1')
    assert User.get(session,
                    name=username) is not None, 'dry_run off means writes'
    assert User.get(session,
                    name=other_username) is None, '"valuewith= not in arg'
    assert Group.get(
        session, name=groupname) is not None, '"group" in arg so group created'

    # invalid format for argument should result in premature system exit
    with pytest.raises(SystemExit):
        call_main('oneoff', 'run', '--no-dry_run', 'FakeOneOff', 'bad_arg')

    call_main('oneoff', 'run', '--no-dry_run', 'FakeOneOff', 'key=valuewith=')
    assert User.get(
        session,
        name=other_username) is not None, '"valuewith= in arg, create user2'
コード例 #2
0
ファイル: test_fe_handlers.py プロジェクト: Acidity/grouper
def test_add_service_account(session, users, http_client, base_url):
    user = users['*****@*****.**']

    # Add account
    fe_url = url(base_url, '/service/create')
    resp = yield http_client.fetch(fe_url, method="POST",
            body=urlencode({'name': '*****@*****.**', "description": "Hi", "canjoin": "canjoin"}),
            headers={'X-Grouper-User': user.username})
    assert resp.code == 200

    assert User.get(session, name="*****@*****.**") is None
    assert Group.get(session, name="*****@*****.**") is None

    # Add account
    fe_url = url(base_url, '/service/create')
    resp = yield http_client.fetch(fe_url, method="POST",
            body=urlencode({'name': '*****@*****.**', "description": "Hi", "canjoin": "canjoin"}),
            headers={'X-Grouper-User': user.username})
    assert resp.code == 200

    u = User.get(session, name="*****@*****.**")
    g = Group.get(session, name="*****@*****.**")

    assert u is not None
    assert g is not None
    assert is_service_account(session, user=u)
    assert is_service_account(session, group=g)
    assert get_service_account(session, user=u).group.id == g.id
    assert get_service_account(session, group=g).user.id == u.id
    assert not is_service_account(session, user=user)
    assert not is_service_account(session, group=Group.get(session, name="team-sre"))
コード例 #3
0
ファイル: test_fe_handlers.py プロジェクト: schedutron/merou
def test_add_service_account(session, users, http_client, base_url):
    user = users['*****@*****.**']

    # Add account
    fe_url = url(base_url, '/service/create')
    resp = yield http_client.fetch(fe_url, method="POST",
            body=urlencode({'name': '*****@*****.**', "description": "Hi", "canjoin": "canjoin"}),
            headers={'X-Grouper-User': user.username})
    assert resp.code == 200

    assert User.get(session, name="*****@*****.**") is None
    assert Group.get(session, name="*****@*****.**") is None

    # Add account
    fe_url = url(base_url, '/service/create')
    resp = yield http_client.fetch(fe_url, method="POST",
            body=urlencode({'name': '*****@*****.**', "description": "Hi", "canjoin": "canjoin"}),
            headers={'X-Grouper-User': user.username})
    assert resp.code == 200

    u = User.get(session, name="*****@*****.**")
    g = Group.get(session, name="*****@*****.**")

    assert u is not None
    assert g is not None
    assert is_service_account(session, user=u)
    assert is_service_account(session, group=g)
    assert get_service_account(session, user=u).group.id == g.id
    assert get_service_account(session, group=g).user.id == u.id
    assert not is_service_account(session, user=user)
    assert not is_service_account(session, group=Group.get(session, name="team-sre"))
コード例 #4
0
ファイル: test_models.py プロジェクト: Acidity/grouper
def test_permission_exclude_inactive(session, standard_graph):
    """Ensure disabled groups are excluded from permission data."""
    group = Group.get(session, name="team-sre")
    permission = Permission.get(session, name="ssh")
    assert "team-sre" in [g[0] for g in get_groups_by_permission(session, permission)]
    group.disable()
    assert "team-sre" not in [g[0] for g in get_groups_by_permission(session, permission)]
コード例 #5
0
    def get(self, request_id, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        members = group.my_members()
        my_role = user_role(self.current_user, members)
        if my_role not in ("manager", "owner", "np-owner"):
            return self.forbidden()

        request = self.session.query(Request).filter_by(id=request_id).scalar()
        if not request:
            return self.notfound()

        form = GroupRequestModifyForm(self.request.arguments)
        form.status.choices = self._get_choices(request.status)

        updates = request.my_status_updates()

        self.render("group-request-update.html",
                    group=group,
                    request=request,
                    members=members,
                    form=form,
                    statuses=REQUEST_STATUS_CHOICES,
                    updates=updates)
コード例 #6
0
ファイル: group_enable.py プロジェクト: graham/grouper
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        members = group.my_members()
        if not user_role(self.current_user, members) in ("owner", "np-owner"):
            return self.forbidden()

        # Enabling and disabling service accounts via the group endpoints is forbidden
        # because we need the preserve_membership data that is only available via the
        # UserEnable form.
        if is_service_account(self.session, group=group):
            return self.forbidden()

        group.enable()

        self.session.commit()

        AuditLog.log(self.session,
                     self.current_user.id,
                     'enable_group',
                     'Enabled group.',
                     on_group_id=group.id)

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
コード例 #7
0
ファイル: service_account.py プロジェクト: graham/grouper
def get_service_account(session, user=None, group=None):
    # type: (Session, User, Group) -> ServiceAccount
    """
    Takes in a User or a Group and returns a dictionary that contains
    all of the service account components for the service account that
    the user/group is part of.

    Args:
        session: the database session
        user: a User object to check
        group: a Group object to check

    Throws:
        ServiceAccountNotFound: if the user or group is not part of a
            service account

    Returns:
        a dictionary with all components of the service account of the
            user or group passed in
    """
    if not is_service_account(session, user, group):
        raise ServiceAccountNotFound()

    name = user.name if user else group.name
    return ServiceAccount(User.get(session, name=name),
                          Group.get(session, name=name))
コード例 #8
0
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if not self.current_user.can_manage(group):
            return self.forbidden()

        form = GroupRemoveForm(self.request.arguments)
        if not form.validate():
            return self.send_error(status_code=400)

        member_type, member_name = form.data["member_type"], form.data["member"]

        members = group.my_members()
        if not members.get((member_type.capitalize(), member_name), None):
            return self.notfound()

        removed_member = get_user_or_group(self.session, member_name, user_or_group=member_type)

        if self.current_user == removed_member:
            return self.send_error(
                status_code=400,
                reason="Can't remove yourself. Leave group instead."
            )

        group.revoke_member(self.current_user, removed_member, "Removed by owner/np-owner/manager")
        AuditLog.log(self.session, self.current_user.id, 'remove_from_group',
                     '{} was removed from the group.'.format(removed_member.name),
                     on_group_id=group.id, on_user_id=removed_member.id)
        return self.redirect("/groups/{}?refresh=yes".format(group.name))
コード例 #9
0
ファイル: group_requests.py プロジェクト: graham/grouper
    def get(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        status = self.get_argument("status", None)
        offset = int(self.get_argument("offset", 0))
        limit = int(self.get_argument("limit", 100))
        if limit > 9000:
            limit = 9000

        requests = group.my_requests(status).order_by(
            Request.requested_at.desc()
        )
        members = group.my_members()

        total = requests.count()
        requests = requests.offset(offset).limit(limit)

        current_user_role = {
            'is_owner': user_role_index(self.current_user, members) in OWNER_ROLE_INDICES,
            'is_approver': user_role_index(self.current_user, members) in APPROVER_ROLE_INDICIES,
            'is_manager': user_role(self.current_user, members) == "manager",
            'role': user_role(self.current_user, members),
             }

        self.render(
            "group-requests.html", group=group, requests=requests,
            members=members, status=status, statuses=REQUEST_STATUS_CHOICES,
            offset=offset, limit=limit, total=total, current_user_role=current_user_role,
        )
コード例 #10
0
ファイル: service_account.py プロジェクト: Acidity/grouper
def get_service_account(session, user=None, group=None):
    # type: (Session, User, Group) -> ServiceAccount
    """
    Takes in a User or a Group and returns a dictionary that contains
    all of the service account components for the service account that
    the user/group is part of.

    Args:
        session: the database session
        user: a User object to check
        group: a Group object to check

    Throws:
        ServiceAccountNotFound: if the user or group is not part of a
            service account

    Returns:
        a dictionary with all components of the service account of the
            user or group passed in
    """
    if not is_service_account(session, user, group):
        raise ServiceAccountNotFound()

    name = user.name if user else group.name
    return ServiceAccount(User.get(session, name=name), Group.get(session, name=name))
コード例 #11
0
ファイル: test_grouper_ctl.py プロジェクト: rra/grouper
def test_oneoff(mock_make_session, mock_annex, session):
    mock_make_session.return_value = session
    username = '******'
    other_username = '******'
    groupname = 'fake_group'

    class FakeOneOff(object):
        def configure(self, service_name):
            pass

        def run(self, session, **kwargs):
            if kwargs.get('group'):
                Group.get_or_create(session, groupname=groupname)
                session.commit()
            elif kwargs.get('key') == 'valuewith=':
                User.get_or_create(session, username=other_username)
                session.commit()
            else:
                User.get_or_create(session, username=username)
                session.commit()

    mock_annex.return_value = [FakeOneOff()]

    # dry_run
    call_main('oneoff', 'run', 'FakeOneOff')
    assert User.get(session, name=username) is None, 'default dry_run means no writes'
    assert User.get(session, name=other_username) is None, '"valuewith= not in arg'
    assert Group.get(session, name=groupname) is None, '"group" not in arg so no group created'

    # not dry_run, create a user
    call_main('oneoff', 'run', '--no-dry_run', 'FakeOneOff')
    assert User.get(session, name=username) is not None, 'dry_run off means writes'
    assert User.get(session, name=other_username) is None, '"valuewith= not in arg'
    assert Group.get(session, name=groupname) is None, '"group" not in arg so no group created'

    # not dry_run, use kwarg to create a group
    call_main('oneoff', 'run', '--no-dry_run', 'FakeOneOff', 'group=1')
    assert User.get(session, name=username) is not None, 'dry_run off means writes'
    assert User.get(session, name=other_username) is None, '"valuewith= not in arg'
    assert Group.get(session, name=groupname) is not None, '"group" in arg so group created'

    # invalid format for argument should result in premature system exit
    with pytest.raises(SystemExit):
        call_main('oneoff', 'run', '--no-dry_run', 'FakeOneOff', 'bad_arg')

    call_main('oneoff', 'run', '--no-dry_run', 'FakeOneOff', 'key=valuewith=')
    assert User.get(session, name=other_username) is not None, '"valuewith= in arg, create user2'
コード例 #12
0
def test_grant_and_revoke(session, standard_graph, graph, groups, permissions,
        http_client, base_url):
    """Test that permission grant and revokes are reflected correctly."""
    group_name = "team-sre"
    permission_name = "sudo"
    user_name = "*****@*****.**"

    def _check_graph_for_perm(graph):
        return any(map(lambda x: x.permission == permission_name,
                graph.permission_metadata[group_name]))

    # make some permission admins
    perm_admin, _ = Permission.get_or_create(session, name=PERMISSION_ADMIN, description="")
    session.commit()
    grant_permission(groups["security-team"], perm_admin)

    # grant attempt by non-permission admin
    fe_url = url(base_url, "/permissions/grant/{}".format(group_name))
    with pytest.raises(HTTPError):
        yield http_client.fetch(fe_url, method="POST",
                body=urlencode({"permission": permission_name, "argument": "specific_arg"}),
                headers={'X-Grouper-User': "******"})

    graph.update_from_db(session)
    assert not _check_graph_for_perm(graph), "no permissions granted"

    # grant by permission admin
    resp = yield http_client.fetch(fe_url, method="POST",
            body=urlencode({"permission": permission_name, "argument": "specific_arg"}),
            headers={'X-Grouper-User': user_name})
    assert resp.code == 200

    graph.update_from_db(session)
    assert _check_graph_for_perm(graph), "permissions granted, successfully"

    # figure out mapping_id of grant
    permission_id = Permission.get(session, name=permission_name).id
    group_id = Group.get(session, name=group_name).id
    mapping = session.query(PermissionMap).filter(
            PermissionMap.permission_id == permission_id,
            PermissionMap.group_id == group_id).first()

    # revoke permission by non-admin
    fe_url = url(base_url, "/permissions/{}/revoke/{}".format(permission_name, mapping.id))
    with pytest.raises(HTTPError):
        yield http_client.fetch(fe_url, method="POST", body=urlencode({}),
                headers={'X-Grouper-User': "******"})

    graph.update_from_db(session)
    assert _check_graph_for_perm(graph), "permissions not revoked"

    # revoke permission for realz
    resp = yield http_client.fetch(fe_url, method="POST", body=urlencode({}),
            headers={'X-Grouper-User': user_name})
    assert resp.code == 200

    graph.update_from_db(session)
    assert not _check_graph_for_perm(graph), "permissions revoked successfully"
コード例 #13
0
ファイル: group_join.py プロジェクト: rra/grouper
    def get(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        group_md = self.graph.get_group_details(group.name)

        form = GroupJoinForm()
        form.member.choices = self._get_choices(group)
        return self.render("group-join.html", form=form, group=group, audited=group_md["audited"])
コード例 #14
0
    def get(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        members = group.my_members()
        if not user_role(self.current_user, members):
            return self.forbidden()

        return self.render("group-leave.html", group=group)
コード例 #15
0
ファイル: group_edit.py プロジェクト: schedutron/merou
    def get(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if not user_can_manage_group(self.session, group, self.current_user):
            return self.forbidden()

        form = GroupEditForm(obj=group)

        self.render("group-edit.html", group=group, form=form)
コード例 #16
0
ファイル: test_grouper_ctl.py プロジェクト: rra/grouper
def test_sync_db_default_group(make_session, session, users, groups):
    make_session.return_value = session

    call_main('sync_db')
    admin_group = Group.get(session, name="grouper-administrators")
    assert admin_group, "Group should have been autocreated"

    admin_group_permission_names = [perm[1] for perm in admin_group.my_permissions()]
    for permission in (GROUP_ADMIN, PERMISSION_ADMIN, USER_ADMIN):
        assert permission in admin_group_permission_names, \
                "Expected permission missing: %s" % permission
コード例 #17
0
ファイル: group_edit.py プロジェクト: nathanielherman/grouper
    def get(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if not self.current_user.can_manage(group):
            return self.forbidden()

        form = GroupEditForm(obj=group)

        self.render("group-edit.html", group=group, form=form)
コード例 #18
0
def test_permission_exclude_inactive(session, standard_graph):
    """Ensure disabled groups are excluded from permission data."""
    group = Group.get(session, name="team-sre")
    permission = Permission.get(session, name="ssh")
    assert "team-sre" in [
        g[0] for g in get_groups_by_permission(session, permission)
    ]
    group.disable()
    assert "team-sre" not in [
        g[0] for g in get_groups_by_permission(session, permission)
    ]
コード例 #19
0
    def get(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        members = group.my_members()
        if not self.current_user.my_role(members):
            return self.forbidden()

        return self.render(
            "group-leave.html", group=group
        )
コード例 #20
0
ファイル: group_add.py プロジェクト: nathanielherman/grouper
    def get(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if not self.current_user.can_manage(group):
            return self.forbidden()

        members = group.my_members()
        my_role = self.current_user.my_role(members)
        return self.render(
            "group-add.html", form=self.get_form(role=my_role), group=group
        )
コード例 #21
0
ファイル: group_view.py プロジェクト: Acidity/grouper
    def get(self, group_id=None, name=None):
        self.handle_refresh()
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if is_service_account(self.session, group=group):
            return self.redirect("/service/{}".format(group.groupname))

        self.render(
            "group.html", group=group,
            **get_group_view_template_vars(self.session, self.current_user, group, self.graph)
        )
コード例 #22
0
ファイル: test_grouper_ctl.py プロジェクト: Acidity/grouper
def test_sync_db_default_group(make_session, session, users, groups):
    make_session.return_value = session

    call_main('sync_db')
    admin_group = Group.get(session, name="grouper-administrators")
    assert admin_group, "Group should have been autocreated"

    admin_group_permission_names = [
        perm[1] for perm in admin_group.my_permissions()
    ]
    for permission in (GROUP_ADMIN, PERMISSION_ADMIN, USER_ADMIN):
        assert permission in admin_group_permission_names, \
                "Expected permission missing: %s" % permission
コード例 #23
0
    def get(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        args_by_perm = get_grantable_permissions(self.session,
                settings.restricted_ownership_permissions)
        dropdown_form, text_form = GroupPermissionRequest._get_forms(args_by_perm, None)

        self.render("group-permission-request.html", dropdown_form=dropdown_form,
                text_form=text_form, group=group, args_by_perm_json=json.dumps(args_by_perm),
                dropdown_help=settings.permission_request_dropdown_help,
                text_help=settings.permission_request_text_help)
コード例 #24
0
ファイル: group_add.py プロジェクト: graham/grouper
    def get(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if not user_can_manage_group(self.session, group, self.current_user):
            return self.forbidden()

        members = group.my_members()
        my_role = user_role(self.current_user, members)
        return self.render(
            "group-add.html", form=self.get_form(role=my_role), group=group
        )
コード例 #25
0
    def get(self, group_id=None, name=None):
        self.handle_refresh()
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if is_service_account(self.session, group=group):
            return self.redirect("/service/{}".format(group.groupname))

        self.render("group.html",
                    group=group,
                    **get_group_view_template_vars(self.session,
                                                   self.current_user, group,
                                                   self.graph))
コード例 #26
0
ファイル: group_edit.py プロジェクト: schedutron/merou
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if not user_can_manage_group(self.session, group, self.current_user):
            return self.forbidden()

        form = GroupEditForm(self.request.arguments, obj=group)
        if not form.validate():
            return self.render("group-edit.html",
                               group=group,
                               form=form,
                               alerts=self.get_form_alerts(form.errors))

        if (group.groupname != form.data["groupname"]
                and is_service_account(self.session, group=group)):
            form.groupname.errors.append(
                "You cannot change the name of service account groups")
            return self.render("group-edit.html",
                               group=group,
                               form=form,
                               alerts=self.get_form_alerts(form.errors))

        group.groupname = form.data["groupname"]
        group.email_address = form.data["email_address"]
        group.description = form.data["description"]
        group.canjoin = form.data["canjoin"]
        group.auto_expire = form.data["auto_expire"]
        Counter.incr(self.session, "updates")

        try:
            self.session.commit()
        except IntegrityError:
            self.session.rollback()
            form.groupname.errors.append("{} already exists".format(
                form.data["groupname"]))
            return self.render("group-edit.html",
                               group=group,
                               form=form,
                               alerts=self.get_form_alerts(form.errors))

        AuditLog.log(self.session,
                     self.current_user.id,
                     'edit_group',
                     'Edited group.',
                     on_group_id=group.id)

        return self.redirect("/groups/{}".format(group.name))
コード例 #27
0
ファイル: group_view.py プロジェクト: nathanielherman/grouper
    def get(self, group_id=None, name=None):
        self.handle_refresh()
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        grantable = self.current_user.my_grantable_permissions()

        try:
            group_md = self.graph.get_group_details(group.name)
        except NoSuchGroup:
            # Very new group with no metadata yet, or it has been disabled and
            # excluded from in-memory cache.
            group_md = {}

        members = group.my_members()
        groups = group.my_groups()
        permissions = group_md.get('permissions', [])
        permission_requests_pending = get_pending_request_by_group(self.session, group)
        audited = group_md.get('audited', False)
        log_entries = group.my_log_entries()
        num_pending = group.my_requests("pending").count()
        current_user_role = {
                'is_owner': self.current_user.my_role_index(members) in OWNER_ROLE_INDICES,
                'is_approver': self.current_user.my_role_index(members) in APPROVER_ROLE_INDICIES,
                'is_manager': self.current_user.my_role(members) == "manager",
                }

        # Add mapping_id to permissions structure
        my_permissions = group.my_permissions()
        for perm_up in permissions:
            for perm_direct in my_permissions:
                if (perm_up['permission'] == perm_direct.name and
                        perm_up['argument'] == perm_direct.argument):
                    perm_up['mapping_id'] = perm_direct.mapping_id
                    break

        alerts = []
        self_pending = group.my_requests("pending", user=self.current_user).count()
        if self_pending:
            alerts.append(Alert('info', 'You have a pending request to join this group.', None))

        self.render(
            "group.html", group=group, members=members, groups=groups,
            num_pending=num_pending, alerts=alerts, permissions=permissions,
            log_entries=log_entries, grantable=grantable, audited=audited,
            statuses=AUDIT_STATUS_CHOICES, current_user_role=current_user_role,
            permission_requests_pending=permission_requests_pending
        )
コード例 #28
0
    def get(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        group_md = self.graph.get_group_details(group.name)

        form = GroupJoinForm()
        form.member.choices = self._get_choices(group)
        return self.render(
            "group-join.html",
            form=form,
            group=group,
            audited=group_md["audited"],
        )
コード例 #29
0
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        members = group.my_members()
        if not self.current_user.my_role(members):
            return self.forbidden()

        group.revoke_member(self.current_user, self.current_user, "User self-revoked.")

        AuditLog.log(self.session, self.current_user.id, 'leave_group',
                     '{} left the group.'.format(self.current_user.name),
                     on_group_id=group.id)

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
コード例 #30
0
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        members = group.my_members()
        if not self.current_user.my_role(members) in ("owner", "np-owner"):
            return self.forbidden()

        group.enable()
        self.session.commit()

        AuditLog.log(self.session, self.current_user.id, 'enable_group',
                     'Enabled group.', on_group_id=group.id)

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
コード例 #31
0
    def get(self, user_id=None, name=None):
        self.handle_refresh()
        user = User.get(self.session, user_id, name)

        if not user or not user.role_user:
            return self.notfound()

        group = Group.get(self.session, name=name)
        actor = self.current_user
        graph = self.graph
        session = self.session
        self.render("service.html",
                    user=user,
                    group=group,
                    **get_service_account_view_template_vars(session, actor, user, group, graph)
                    )
コード例 #32
0
ファイル: sync_db.py プロジェクト: rra/grouper
def sync_db_command(args):
    # Models not implicitly or explictly imported above are explicitly imported
    # here:
    from grouper.models.perf_profile import PerfProfile  # noqa

    db_engine = get_db_engine(get_database_url(settings))
    Model.metadata.create_all(db_engine)

    # Add some basic database structures we know we will need if they don't exist.
    session = make_session()

    for name, description in SYSTEM_PERMISSIONS:
        test = Permission.get(session, name)
        if test:
            continue
        permission = Permission(name=name, description=description)
        try:
            permission.add(session)
            session.flush()
        except IntegrityError:
            session.rollback()
            raise Exception('Failed to create permission: %s' % (name, ))
        session.commit()

    # This group is needed to bootstrap a Grouper installation.
    admin_group = Group.get(session, name="grouper-administrators")
    if not admin_group:
        admin_group = Group(
                groupname="grouper-administrators",
                description="Administrators of the Grouper system.",
                canjoin="nobody",
        )

        try:
            admin_group.add(session)
            session.flush()
        except IntegrityError:
            session.rollback()
            raise Exception('Failed to create group: grouper-administrators')

        for permission_name in (GROUP_ADMIN, PERMISSION_ADMIN, USER_ADMIN):
            permission = Permission.get(session, permission_name)
            assert permission, "Permission should have been created earlier!"
            grant_permission(session, admin_group.id, permission.id)

        session.commit()
コード例 #33
0
ファイル: sync_db.py プロジェクト: graham/grouper
def sync_db_command(args):
    # Models not implicitly or explictly imported above are explicitly imported
    # here:
    from grouper.models.perf_profile import PerfProfile  # noqa

    db_engine = get_db_engine(get_database_url(settings))
    Model.metadata.create_all(db_engine)

    # Add some basic database structures we know we will need if they don't exist.
    session = make_session()

    for name, description in SYSTEM_PERMISSIONS:
        test = Permission.get(session, name)
        if test:
            continue
        permission = Permission(name=name, description=description)
        try:
            permission.add(session)
            session.flush()
        except IntegrityError:
            session.rollback()
            raise Exception('Failed to create permission: %s' % (name, ))
        session.commit()

    # This group is needed to bootstrap a Grouper installation.
    admin_group = Group.get(session, name="grouper-administrators")
    if not admin_group:
        admin_group = Group(
            groupname="grouper-administrators",
            description="Administrators of the Grouper system.",
            canjoin="nobody",
        )

        try:
            admin_group.add(session)
            session.flush()
        except IntegrityError:
            session.rollback()
            raise Exception('Failed to create group: grouper-administrators')

        for permission_name in (GROUP_ADMIN, PERMISSION_ADMIN, USER_ADMIN):
            permission = Permission.get(session, permission_name)
            assert permission, "Permission should have been created earlier!"
            grant_permission(session, admin_group.id, permission.id)

        session.commit()
コード例 #34
0
ファイル: group_edit.py プロジェクト: Acidity/grouper
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if not user_can_manage_group(self.session, group, self.current_user):
            return self.forbidden()

        form = GroupEditForm(self.request.arguments, obj=group)
        if not form.validate():
            return self.render(
                "group-edit.html", group=group, form=form,
                alerts=self.get_form_alerts(form.errors)
            )

        if (group.groupname != form.data["groupname"] and
                is_service_account(self.session, group=group)):
            form.groupname.errors.append("You cannot change the name of service account groups")
            return self.render(
                "group-edit.html", group=group, form=form,
                alerts=self.get_form_alerts(form.errors)
            )

        group.groupname = form.data["groupname"]
        group.description = form.data["description"]
        group.canjoin = form.data["canjoin"]
        group.auto_expire = form.data["auto_expire"]
        Counter.incr(self.session, "updates")

        try:
            self.session.commit()
        except IntegrityError:
            self.session.rollback()
            form.groupname.errors.append(
                "{} already exists".format(form.data["groupname"])
            )
            return self.render(
                "group-edit.html", group=group, form=form,
                alerts=self.get_form_alerts(form.errors)
            )

        AuditLog.log(self.session, self.current_user.id, 'edit_group',
                     'Edited group.', on_group_id=group.id)

        return self.redirect("/groups/{}".format(group.name))
コード例 #35
0
    def get(self, name=None):
        grantable = self.current_user.my_grantable_permissions()
        if not grantable:
            return self.forbidden()

        group = Group.get(self.session, None, name)
        if not group:
            return self.notfound()

        form = PermissionGrantForm()
        form.permission.choices = [["", "(select one)"]]
        for perm in grantable:
            grantable = "{} ({})".format(perm[0].name, perm[1])
            form.permission.choices.append([perm[0].name, grantable])

        return self.render(
            "permission-grant.html", form=form, group=group,
        )
コード例 #36
0
ファイル: group_edit_member.py プロジェクト: graham/grouper
    def get(self, group_id=None, name=None, name2=None, member_type=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if self.current_user.name == name2:
            return self.forbidden()

        members = group.my_members()
        my_role = user_role(self.current_user, members)
        if my_role not in ("manager", "owner", "np-owner"):
            return self.forbidden()

        member = members.get((member_type.capitalize(), name2), None)
        if not member:
            return self.notfound()

        edge = GroupEdge.get(
            self.session,
            group_id=group.id,
            member_type=OBJ_TYPES[member.type],
            member_pk=member.id,
        )
        if not edge:
            return self.notfound()

        form = GroupEditMemberForm(self.request.arguments)
        form.role.choices = [["member", "Member"]]
        if my_role in ("owner", "np-owner"):
            form.role.choices.append(["manager", "Manager"])
            form.role.choices.append(["owner", "Owner"])
            form.role.choices.append(["np-owner", "No-Permissions Owner"])

        form.role.data = edge.role
        form.expiration.data = edge.expiration.strftime(
            "%m/%d/%Y") if edge.expiration else None

        self.render(
            "group-edit-member.html",
            group=group,
            member=member,
            edge=edge,
            form=form,
        )
コード例 #37
0
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        members = group.my_members()
        if not user_role(self.current_user, members):
            return self.forbidden()

        group.revoke_member(self.current_user, self.current_user,
                            "User self-revoked.")

        AuditLog.log(self.session,
                     self.current_user.id,
                     'leave_group',
                     '{} left the group.'.format(self.current_user.name),
                     on_group_id=group.id)

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
コード例 #38
0
ファイル: permissions_grant.py プロジェクト: graham/grouper
    def get(self, name=None):
        grantable = user_grantable_permissions(self.session, self.current_user)
        if not grantable:
            return self.forbidden()

        group = Group.get(self.session, None, name)
        if not group:
            return self.notfound()

        form = PermissionGrantForm()
        form.permission.choices = [["", "(select one)"]]
        for perm in grantable:
            grantable = "{} ({})".format(perm[0].name, perm[1])
            form.permission.choices.append([perm[0].name, grantable])

        return self.render(
            "permission-grant.html",
            form=form,
            group=group,
        )
コード例 #39
0
    def get(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        # Only members can request permissions
        if not self.current_user.is_member(group.my_members()):
            return self.forbidden()

        args_by_perm = get_grantable_permissions(
            self.session, settings.restricted_ownership_permissions)
        dropdown_form, text_form = GroupPermissionRequest._get_forms(
            args_by_perm, None)

        self.render("group-permission-request.html",
                    dropdown_form=dropdown_form,
                    text_form=text_form,
                    group=group,
                    args_by_perm_json=json.dumps(args_by_perm),
                    dropdown_help=settings.permission_request_dropdown_help,
                    text_help=settings.permission_request_text_help)
コード例 #40
0
def test_group_add_remove_member(make_session, session, users, groups):
    make_session.return_value = session

    username = '******'
    groupname = 'team-sre'

    # add
    assert (u'User', username) not in groups[groupname].my_members()
    call_main('group', 'add_member', '--owner', groupname, username)
    all_members = Group.get(session, name=groupname).my_members()
    assert (u'User', username) in all_members
    _, _, _, role, _, _ = all_members[(u'User', username)]
    assert GROUP_EDGE_ROLES[role] == "owner"

    # remove
    call_main('group', 'remove_member', groupname, username)
    assert (u'User', username) not in Group.get(session,
                                                name=groupname).my_members()

    # bulk add
    usernames = {'*****@*****.**', '*****@*****.**', '*****@*****.**'}
    call_main('group', 'add_member', '--member', groupname, *usernames)
    members = {
        u
        for _, u in Group.get(session, name=groupname).my_members().keys()
    }
    assert usernames.issubset(members)

    # bulk remove
    call_main('group', 'remove_member', groupname, *usernames)
    members = {
        u
        for _, u in Group.get(session, name=groupname).my_members().keys()
    }
    assert not members.intersection(usernames)

    # check user/group name
    call_main('group', 'add_member', '--member', 'invalid group name',
              username)
    assert (u'User', username) not in Group.get(session,
                                                name=groupname).my_members()

    bad_username = '******'
    call_main('group', 'add_member', '--member', groupname, bad_username)
    assert (u'User',
            bad_username) not in Group.get(session,
                                           name=groupname).my_members()
コード例 #41
0
ファイル: group_enable.py プロジェクト: rra/grouper
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        members = group.my_members()
        if not user_role(self.current_user, members) in ("owner", "np-owner"):
            return self.forbidden()

        # Enabling and disabling service accounts via the group endpoints is forbidden
        # because we need the preserve_membership data that is only available via the
        # UserEnable form.
        if is_service_account(self.session, group=group):
            return self.forbidden()

        group.enable()

        self.session.commit()

        AuditLog.log(self.session, self.current_user.id, "enable_group", "Enabled group.", on_group_id=group.id)

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
コード例 #42
0
    def get(self, group_id=None, name=None, name2=None, member_type=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if self.current_user.name == name2:
            return self.forbidden()

        members = group.my_members()
        my_role = self.current_user.my_role(members)
        if my_role not in ("manager", "owner", "np-owner"):
            return self.forbidden()

        member = members.get((member_type.capitalize(), name2), None)
        if not member:
            return self.notfound()

        edge = GroupEdge.get(
            self.session,
            group_id=group.id,
            member_type=OBJ_TYPES[member.type],
            member_pk=member.id,
        )
        if not edge:
            return self.notfound()

        form = GroupEditMemberForm(self.request.arguments)
        form.role.choices = [["member", "Member"]]
        if my_role in ("owner", "np-owner"):
            form.role.choices.append(["manager", "Manager"])
            form.role.choices.append(["owner", "Owner"])
            form.role.choices.append(["np-owner", "No-Permissions Owner"])

        form.role.data = edge.role
        form.expiration.data = edge.expiration.strftime("%m/%d/%Y") if edge.expiration else None

        self.render(
            "group-edit-member.html", group=group, member=member, edge=edge, form=form,
        )
コード例 #43
0
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if not user_can_manage_group(self.session, group, self.current_user):
            return self.forbidden()

        form = GroupRemoveForm(self.request.arguments)
        if not form.validate():
            return self.send_error(status_code=400)

        member_type, member_name = form.data["member_type"], form.data["member"]

        members = group.my_members()
        if not members.get((member_type.capitalize(), member_name), None):
            return self.notfound()

        removed_member = get_user_or_group(self.session, member_name, user_or_group=member_type)

        if self.current_user == removed_member:
            return self.send_error(
                status_code=400,
                reason="Can't remove yourself. Leave group instead."
            )

        if (is_service_account(self.session, group=group) and
                get_service_account(self.session, group=group).user.name == removed_member.name):
            return self.send_error(
                status_code=400,
                reason="Can't remove a service account user from the service account group."
            )

        group.revoke_member(self.current_user, removed_member, "Removed by owner/np-owner/manager")
        AuditLog.log(self.session, self.current_user.id, 'remove_from_group',
                     '{} was removed from the group.'.format(removed_member.name),
                     on_group_id=group.id, on_user_id=removed_member.id)
        return self.redirect("/groups/{}?refresh=yes".format(group.name))
コード例 #44
0
    def get(self, request_id, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        members = group.my_members()
        my_role = self.current_user.my_role(members)
        if my_role not in ("manager", "owner", "np-owner"):
            return self.forbidden()

        request = self.session.query(Request).filter_by(id=request_id).scalar()
        if not request:
            return self.notfound()

        form = GroupRequestModifyForm(self.request.arguments)
        form.status.choices = self._get_choices(request.status)

        updates = request.my_status_updates()

        self.render(
            "group-request-update.html", group=group, request=request,
            members=members, form=form, statuses=REQUEST_STATUS_CHOICES, updates=updates
        )
コード例 #45
0
def test_group_add_remove_member(make_session, session, users, groups):
    make_session.return_value = session

    username = '******'
    groupname = 'team-sre'

    # add
    assert (u'User', username) not in groups[groupname].my_members()
    call_main('group', 'add_member', '--owner', groupname, username)
    all_members = Group.get(session, name=groupname).my_members()
    assert (u'User', username) in all_members
    _, _, _, role, _, _ = all_members[(u'User', username)]
    assert GROUP_EDGE_ROLES[role] == "owner"

    # remove
    call_main('group', 'remove_member', groupname, username)
    assert (u'User', username) not in Group.get(session, name=groupname).my_members()

    # bulk add
    usernames = {'*****@*****.**', '*****@*****.**', '*****@*****.**'}
    call_main('group', 'add_member', '--member', groupname, *usernames)
    members = {u for _, u in Group.get(session, name=groupname).my_members().keys()}
    assert usernames.issubset(members)

    # bulk remove
    call_main('group', 'remove_member', groupname, *usernames)
    members = {u for _, u in Group.get(session, name=groupname).my_members().keys()}
    assert not members.intersection(usernames)

    # check user/group name
    call_main('group', 'add_member', '--member', 'invalid group name', username)
    assert (u'User', username) not in Group.get(session, name=groupname).my_members()

    bad_username = '******'
    call_main('group', 'add_member', '--member', groupname, bad_username)
    assert (u'User', bad_username) not in Group.get(session, name=groupname).my_members()
コード例 #46
0
ファイル: test_grouper_ctl_group.py プロジェクト: rra/grouper
def test_group_add_remove_member(make_session, session, users, groups):
    make_session.return_value = session

    username = "******"
    groupname = "team-sre"

    # add
    assert (u"User", username) not in groups[groupname].my_members()
    call_main("group", "add_member", "--owner", groupname, username)
    all_members = Group.get(session, name=groupname).my_members()
    assert (u"User", username) in all_members
    _, _, _, role, _, _ = all_members[(u"User", username)]
    assert GROUP_EDGE_ROLES[role] == "owner"

    # remove
    call_main("group", "remove_member", groupname, username)
    assert (u"User", username) not in Group.get(session, name=groupname).my_members()

    # bulk add
    usernames = {"*****@*****.**", "*****@*****.**", "*****@*****.**"}
    call_main("group", "add_member", "--member", groupname, *usernames)
    members = {u for _, u in Group.get(session, name=groupname).my_members().keys()}
    assert usernames.issubset(members)

    # bulk remove
    call_main("group", "remove_member", groupname, *usernames)
    members = {u for _, u in Group.get(session, name=groupname).my_members().keys()}
    assert not members.intersection(usernames)

    # check user/group name
    call_main("group", "add_member", "--member", "invalid group name", username)
    assert (u"User", username) not in Group.get(session, name=groupname).my_members()

    bad_username = "******"
    call_main("group", "add_member", "--member", groupname, bad_username)
    assert (u"User", bad_username) not in Group.get(session, name=groupname).my_members()
コード例 #47
0
ファイル: test_permissions.py プロジェクト: graham/grouper
def test_grant_and_revoke(session, standard_graph, graph, groups, permissions,
                          http_client, base_url):
    """Test that permission grant and revokes are reflected correctly."""
    group_name = "team-sre"
    permission_name = "sudo"
    user_name = "*****@*****.**"

    def _check_graph_for_perm(graph):
        return any(
            map(lambda x: x.permission == permission_name,
                graph.permission_metadata[group_name]))

    # make some permission admins
    perm_admin, _ = Permission.get_or_create(session,
                                             name=PERMISSION_ADMIN,
                                             description="")
    session.commit()
    grant_permission(groups["security-team"], perm_admin)

    # grant attempt by non-permission admin
    fe_url = url(base_url, "/permissions/grant/{}".format(group_name))
    with pytest.raises(HTTPError):
        yield http_client.fetch(fe_url,
                                method="POST",
                                body=urlencode({
                                    "permission": permission_name,
                                    "argument": "specific_arg"
                                }),
                                headers={'X-Grouper-User': "******"})

    graph.update_from_db(session)
    assert not _check_graph_for_perm(graph), "no permissions granted"

    # grant by permission admin
    resp = yield http_client.fetch(fe_url,
                                   method="POST",
                                   body=urlencode({
                                       "permission": permission_name,
                                       "argument": "specific_arg"
                                   }),
                                   headers={'X-Grouper-User': user_name})
    assert resp.code == 200

    graph.update_from_db(session)
    assert _check_graph_for_perm(graph), "permissions granted, successfully"

    # figure out mapping_id of grant
    permission_id = Permission.get(session, name=permission_name).id
    group_id = Group.get(session, name=group_name).id
    mapping = session.query(PermissionMap).filter(
        PermissionMap.permission_id == permission_id,
        PermissionMap.group_id == group_id).first()

    # revoke permission by non-admin
    fe_url = url(
        base_url, "/permissions/{}/revoke/{}".format(permission_name,
                                                     mapping.id))
    with pytest.raises(HTTPError):
        yield http_client.fetch(fe_url,
                                method="POST",
                                body=urlencode({}),
                                headers={'X-Grouper-User': "******"})

    graph.update_from_db(session)
    assert _check_graph_for_perm(graph), "permissions not revoked"

    # revoke permission for realz
    resp = yield http_client.fetch(fe_url,
                                   method="POST",
                                   body=urlencode({}),
                                   headers={'X-Grouper-User': user_name})
    assert resp.code == 200

    graph.update_from_db(session)
    assert not _check_graph_for_perm(graph), "permissions revoked successfully"
コード例 #48
0
    def post(self, group_id=None, name=None, name2=None, member_type=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if self.current_user.name == name2:
            return self.forbidden()

        members = group.my_members()
        my_role = self.current_user.my_role(members)
        if my_role not in ("manager", "owner", "np-owner"):
            return self.forbidden()

        member = members.get((member_type.capitalize(), name2), None)
        if not member:
            return self.notfound()

        if member.type == "Group":
            user_or_group = Group.get(self.session, member.id)
        else:
            user_or_group = User.get(self.session, member.id)
        if not user_or_group:
            return self.notfound()

        edge = GroupEdge.get(
            self.session,
            group_id=group.id,
            member_type=OBJ_TYPES[member.type],
            member_pk=member.id,
        )
        if not edge:
            return self.notfound()

        form = GroupEditMemberForm(self.request.arguments)
        form.role.choices = [["member", "Member"]]
        if my_role in ("owner", "np-owner"):
            form.role.choices.append(["manager", "Manager"])
            form.role.choices.append(["owner", "Owner"])
            form.role.choices.append(["np-owner", "No-Permissions Owner"])

        if not form.validate():
            return self.render(
                "group-edit-member.html", group=group, member=member, edge=edge, form=form,
                alerts=self.get_form_alerts(form.errors),
            )

        fail_message = 'This join is denied with this role at this time.'
        try:
            user_can_join = assert_can_join(group, user_or_group, role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = e
        if not user_can_join:
            return self.render(
                "group-edit-member.html", form=form, group=group, member=member, edge=edge,
                alerts=[
                    Alert('danger', fail_message, 'Audit Policy Enforcement')
                ]
            )

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")

        group.edit_member(self.current_user, user_or_group, form.data["reason"],
                          role=form.data["role"], expiration=expiration)

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
コード例 #49
0
ファイル: test_permissions.py プロジェクト: rra/grouper
def _load_permissions_by_group_name(session, group_name):
    group = Group.get(session, name=group_name)
    return [name for _, name, _, _, _ in group.my_permissions()]
コード例 #50
0
ファイル: test_permissions.py プロジェクト: graham/grouper
def _load_permissions_by_group_name(session, group_name):
    group = Group.get(session, name=group_name)
    return [name for _, name, _, _, _ in group.my_permissions()]
コード例 #51
0
ファイル: email_util.py プロジェクト: Acidity/grouper
def notify_edge_expiration(settings, session, edge):
    """Send notification that an edge has expired.

    Handles email notification and audit logging.

    Args:
        settings (Settings): Grouper Settings object for current run.
        session (Session): Object for db session.
        edge (GroupEdge): The expiring edge.
    """
    # TODO(herb): get around circular depdendencies; long term remove call to
    # send_async_email() from grouper.models
    from grouper.model_soup import Group
    from grouper.models.base.constants import OBJ_TYPES_IDX
    from grouper.models.user import User

    # TODO(rra): Arbitrarily use the first listed owner of the group from which membership expired
    # as the actor, since we have to provide an actor and we didn't record who set the expiration on
    # the edge originally.
    actor_id = next(edge.group.my_owners().itervalues()).id

    # Pull data about the edge and the affected user or group.
    group_name = edge.group.name
    if OBJ_TYPES_IDX[edge.member_type] == "User":
        user = User.get(session, pk=edge.member_pk)
        member_name = user.username
        recipients = [member_name]
        member_is_user = True
    else:
        subgroup = Group.get(session, pk=edge.member_pk)
        member_name = subgroup.groupname
        recipients = subgroup.my_owners_as_strings()
        member_is_user = False

    # Log to the audit log.  How depends on whether a user's membership has expired or a group's
    # membership has expired.
    audit_data = {
        "action": "expired_from_group",
        "actor_id": actor_id,
        "description": "{} expired out of the group".format(member_name),
    }
    if member_is_user:
        AuditLog.log(session, on_user_id=user.id, on_group_id=edge.group_id, **audit_data)
    else:
        # Make an audit log entry for both the subgroup and the parent group so that it will show up
        # in the FE view for both groups.
        AuditLog.log(session, on_group_id=edge.group_id, **audit_data)
        AuditLog.log(session, on_group_id=subgroup.id, **audit_data)

    # Send email notification to the affected people.
    email_context = {
        "group_name": group_name,
        "member_name": member_name,
        "member_is_user": member_is_user,
    }
    send_email(
        session=session,
        recipients=recipients,
        subject="Membership in {} expired".format(group_name),
        template="expiration",
        settings=settings,
        context=email_context,
    )
コード例 #52
0
    def post(self, request_id, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        members = group.my_members()
        my_role = user_role(self.current_user, members)
        if my_role not in ("manager", "owner", "np-owner"):
            return self.forbidden()

        request = self.session.query(Request).filter_by(id=request_id).scalar()
        if not request:
            return self.notfound()

        form = GroupRequestModifyForm(self.request.arguments)
        form.status.choices = self._get_choices(request.status)

        updates = request.my_status_updates()

        if not form.validate():
            return self.render("group-request-update.html",
                               group=group,
                               request=request,
                               members=members,
                               form=form,
                               alerts=self.get_form_alerts(form.errors),
                               statuses=REQUEST_STATUS_CHOICES,
                               updates=updates)

        # We have to test this here, too, to ensure that someone can't sneak in with a pending
        # request that used to be allowed.
        if form.data["status"] != "cancelled":
            fail_message = 'This join is denied with this role at this time.'
            try:
                user_can_join = assert_can_join(request.requesting,
                                                request.get_on_behalf(),
                                                role=request.edge.role)
            except UserNotAuditor as e:
                user_can_join = False
                fail_message = e
            if not user_can_join:
                return self.render("group-request-update.html",
                                   group=group,
                                   request=request,
                                   members=members,
                                   form=form,
                                   statuses=REQUEST_STATUS_CHOICES,
                                   updates=updates,
                                   alerts=[
                                       Alert('danger', fail_message,
                                             'Audit Policy Enforcement')
                                   ])

        request.update_status(self.current_user, form.data["status"],
                              form.data["reason"])
        self.session.commit()

        AuditLog.log(self.session,
                     self.current_user.id,
                     'update_request',
                     'Updated request to status: {}'.format(
                         form.data["status"]),
                     on_group_id=group.id,
                     on_user_id=request.requester.id)

        edge = self.session.query(GroupEdge).filter_by(
            id=request.edge_id).one()

        approver_mail_to = [
            user.name for user in group.my_approver_users()
            if user.name != self.current_user.name
            and user.name != request.requester.username
        ]

        send_email(
            self.session,
            approver_mail_to,
            "Request to join {} by {} has been {}".format(
                group.groupname, request.requester.name, form.data['status']),
            "approver_request_updated",
            settings,
            {
                'group_name': group.name,
                'requester': request.requester.username,
                'changed_by': self.current_user.name,
                'status': form.data['status'],
                'role': edge.role,
                'reason': form.data['reason'],
            },
        )

        if form.data['status'] == 'actioned':
            send_email(
                self.session, [request.requester.name],
                'Added to group: {}'.format(group.groupname),
                'request_actioned', settings, {
                    'group_name': group.name,
                    'actioned_by': self.current_user.name,
                    'reason': form.data['reason'],
                    'expiration': edge.expiration,
                    'role': edge.role,
                })
        elif form.data['status'] == 'cancelled':
            send_email(
                self.session, [request.requester.name],
                'Request to join cancelled: {}'.format(group.groupname),
                'request_cancelled', settings, {
                    'group_name': group.name,
                    'cancelled_by': self.current_user.name,
                    'reason': form.data['reason'],
                    'expiration': edge.expiration,
                    'role': edge.role,
                })

        # No explicit refresh because handler queries SQL.
        if form.data['redirect_aggregate']:
            return self.redirect("/user/requests")
        else:
            return self.redirect("/groups/{}/requests".format(group.name))
コード例 #53
0
ファイル: email_util.py プロジェクト: graham/grouper
def notify_edge_expiration(settings, session, edge):
    """Send notification that an edge has expired.

    Handles email notification and audit logging.

    Args:
        settings (Settings): Grouper Settings object for current run.
        session (Session): Object for db session.
        edge (GroupEdge): The expiring edge.
    """
    # TODO(herb): get around circular depdendencies; long term remove call to
    # send_async_email() from grouper.models
    from grouper.model_soup import Group
    from grouper.models.base.constants import OBJ_TYPES_IDX
    from grouper.models.user import User

    # TODO(rra): Arbitrarily use the first listed owner of the group from which membership expired
    # as the actor, since we have to provide an actor and we didn't record who set the expiration on
    # the edge originally.
    actor_id = next(edge.group.my_owners().itervalues()).id

    # Pull data about the edge and the affected user or group.
    group_name = edge.group.name
    if OBJ_TYPES_IDX[edge.member_type] == "User":
        user = User.get(session, pk=edge.member_pk)
        member_name = user.username
        recipients = [member_name]
        member_is_user = True
    else:
        subgroup = Group.get(session, pk=edge.member_pk)
        member_name = subgroup.groupname
        recipients = subgroup.my_owners_as_strings()
        member_is_user = False

    # Log to the audit log.  How depends on whether a user's membership has expired or a group's
    # membership has expired.
    audit_data = {
        "action": "expired_from_group",
        "actor_id": actor_id,
        "description": "{} expired out of the group".format(member_name),
    }
    if member_is_user:
        AuditLog.log(session,
                     on_user_id=user.id,
                     on_group_id=edge.group_id,
                     **audit_data)
    else:
        # Make an audit log entry for both the subgroup and the parent group so that it will show up
        # in the FE view for both groups.
        AuditLog.log(session, on_group_id=edge.group_id, **audit_data)
        AuditLog.log(session, on_group_id=subgroup.id, **audit_data)

    # Send email notification to the affected people.
    email_context = {
        "group_name": group_name,
        "member_name": member_name,
        "member_is_user": member_is_user,
    }
    send_email(
        session=session,
        recipients=recipients,
        subject="Membership in {} expired".format(group_name),
        template="expiration",
        settings=settings,
        context=email_context,
    )
コード例 #54
0
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        form = GroupJoinForm(self.request.arguments)
        form.member.choices = self._get_choices(group)
        if not form.validate():
            return self.render("group-join.html",
                               form=form,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

        member = self._get_member(form.data["member"])

        fail_message = 'This join is denied with this role at this time.'
        try:
            user_can_join = assert_can_join(group,
                                            member,
                                            role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = e
        if not user_can_join:
            return self.render("group-join.html",
                               form=form,
                               group=group,
                               alerts=[
                                   Alert('danger', fail_message,
                                         'Audit Policy Enforcement')
                               ])

        if group.canjoin == "nobody":
            fail_message = 'This group cannot be joined at this time.'
            return self.render("group-join.html",
                               form=form,
                               group=group,
                               alerts=[Alert('danger', fail_message)])

        # We only use the default expiration time if no expiration time was given
        # This does mean that if a user wishes to join a group with no expiration
        # (even with an owner's permission) that has an auto expiration, they must
        # first be accepted to the group and then have the owner edit the user to
        # have no expiration.

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")
        elif group.auto_expire:
            expiration = datetime.utcnow() + group.auto_expire

        request = group.add_member(requester=self.current_user,
                                   user_or_group=member,
                                   reason=form.data["reason"],
                                   status=GROUP_JOIN_CHOICES[group.canjoin],
                                   expiration=expiration,
                                   role=form.data["role"])
        self.session.commit()

        if group.canjoin == 'canask':
            AuditLog.log(self.session,
                         self.current_user.id,
                         'join_group',
                         '{} requested to join with role: {}'.format(
                             member.name, form.data["role"]),
                         on_group_id=group.id)

            mail_to = [
                user.name for user in group.my_users()
                if GROUP_EDGE_ROLES[user.role] in ('manager', 'owner',
                                                   'np-owner')
            ]

            email_context = {
                "requester": member.name,
                "requested_by": self.current_user.name,
                "request_id": request.id,
                "group_name": group.name,
                "reason": form.data["reason"],
                "expiration": expiration,
                "role": form.data["role"],
                "references_header": request.reference_id,
            }

            subj = self.render_template('email/pending_request_subj.tmpl',
                                        group=group.name,
                                        user=self.current_user.name)
            send_email(self.session, mail_to, subj, 'pending_request',
                       settings, email_context)

        elif group.canjoin == 'canjoin':
            AuditLog.log(self.session,
                         self.current_user.id,
                         'join_group',
                         '{} auto-approved to join with role: {}'.format(
                             member.name, form.data["role"]),
                         on_group_id=group.id)
        else:
            raise Exception('Need to update the GroupJoin.post audit logging')

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
コード例 #55
0
ファイル: group_add.py プロジェクト: nathanielherman/grouper
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if not self.current_user.can_manage(group):
            return self.forbidden()

        members = group.my_members()
        my_role = self.current_user.my_role(members)
        form = self.get_form(role=my_role)
        if not form.validate():
            return self.render(
                "group-add.html", form=form, group=group,
                alerts=self.get_form_alerts(form.errors)
            )

        member = get_user_or_group(self.session, form.data["member"])
        if not member:
            form.member.errors.append("User or group not found.")
        elif (member.type, member.name) in group.my_members():
            form.member.errors.append("User or group is already a member of this group.")
        elif group.name == member.name:
            form.member.errors.append("By definition, this group is a member of itself already.")

        # Ensure this doesn't violate auditing constraints
        fail_message = 'This join is denied with this role at this time.'
        try:
            user_can_join = assert_can_join(group, member, role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = e
        if not user_can_join:
            form.member.errors.append(fail_message)

        if form.member.errors:
            return self.render(
                "group-add.html", form=form, group=group,
                alerts=self.get_form_alerts(form.errors)
            )

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")

        group.add_member(
            requester=self.current_user,
            user_or_group=member,
            reason=form.data["reason"],
            status='actioned',
            expiration=expiration,
            role=form.data["role"]
        )
        self.session.commit()

        AuditLog.log(self.session, self.current_user.id, 'join_group',
                     '{} added to group with role: {}'.format(
                         member.name, form.data["role"]),
                     on_group_id=group.id)

        if member.type == "User":
            send_email(
                self.session,
                [member.name],
                'Added to group: {}'.format(group.name),
                'request_actioned',
                settings,
                {
                    'group': group.name,
                    'actioned_by': self.current_user.name,
                    'reason': form.data['reason'],
                    'expiration': expiration,
                    'role': form.data['role'],
                }
            )

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
コード例 #56
0
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        # Only members can request permissions
        if not self.current_user.is_member(group.my_members()):
            return self.forbidden()

        # check inputs
        args_by_perm = get_grantable_permissions(
            self.session, settings.restricted_ownership_permissions)
        dropdown_form, text_form = GroupPermissionRequest._get_forms(
            args_by_perm, self.request.arguments)

        argument_type = self.request.arguments.get("argument_type")
        if argument_type and argument_type[0] == "text":
            form = text_form
        elif argument_type and argument_type[0] == "dropdown":
            form = dropdown_form
            form.argument.choices = [
                (a, a) for a in args_by_perm[form.permission_name.data]
            ]
        else:
            # someone messing with the form
            self.log_message("unknown argument type",
                             group_name=group.name,
                             argument_type=argument_type)
            return self.forbidden()

        if not form.validate():
            return self.render(
                "group-permission-request.html",
                dropdown_form=dropdown_form,
                text_form=text_form,
                group=group,
                args_by_perm_json=json.dumps(args_by_perm),
                alerts=self.get_form_alerts(form.errors),
                dropdown_help=settings.permission_request_dropdown_help,
                text_help=settings.permission_request_text_help,
            )

        permission = Permission.get(self.session, form.permission_name.data)
        assert permission is not None, "our prefilled permission should exist or we have problems"

        # save off request
        try:
            permissions.create_request(self.session, self.current_user, group,
                                       permission, form.argument.data,
                                       form.reason.data)
        except permissions.RequestAlreadyGranted:
            alerts = [
                Alert("danger",
                      "This group already has this permission and argument.")
            ]
        except permissions.RequestAlreadyExists:
            alerts = [
                Alert(
                    "danger",
                    "Request for permission and argument already exists, please wait patiently."
                )
            ]
        except permissions.NoOwnersAvailable:
            self.log_message("prefilled perm+arg have no owner",
                             group_name=group.name,
                             permission_name=permission.name,
                             argument=form.argument.data)
            alerts = [
                Alert(
                    "danger",
                    "No owners available for requested permission and argument."
                    " If this error persists please contact an adminstrator.")
            ]
        else:
            alerts = None

        if alerts:
            return self.render(
                "group-permission-request.html",
                dropdown_form=dropdown_form,
                text_form=text_form,
                group=group,
                args_by_perm_json=json.dumps(args_by_perm),
                alerts=alerts,
            )
        else:
            return self.redirect("/groups/{}".format(group.name))
コード例 #57
0
ファイル: group_add.py プロジェクト: graham/grouper
    def post(self, group_id=None, name=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()

        if not user_can_manage_group(self.session, group, self.current_user):
            return self.forbidden()

        members = group.my_members()
        my_role = user_role(self.current_user, members)
        form = self.get_form(role=my_role)
        if not form.validate():
            return self.render(
                "group-add.html", form=form, group=group,
                alerts=self.get_form_alerts(form.errors)
            )

        member = get_user_or_group(self.session, form.data["member"])
        if member.type == "User" and is_service_account(self.session, member):
            # For service accounts, we want to always add the group to other groups, not the user
            member = get_service_account(self.session, user=member).group
        if not member:
            form.member.errors.append("User or group not found.")
        elif (member.type, member.name) in group.my_members():
            form.member.errors.append("User or group is already a member of this group.")
        elif group.name == member.name:
            form.member.errors.append("By definition, this group is a member of itself already.")

        # Ensure this doesn't violate auditing constraints
        fail_message = 'This join is denied with this role at this time.'
        try:
            user_can_join = assert_can_join(group, member, role=form.data["role"])
        except UserNotAuditor as e:
            user_can_join = False
            fail_message = e
        if not user_can_join:
            form.member.errors.append(fail_message)

        if form.member.errors:
            return self.render(
                "group-add.html", form=form, group=group,
                alerts=self.get_form_alerts(form.errors)
            )

        expiration = None
        if form.data["expiration"]:
            expiration = datetime.strptime(form.data["expiration"], "%m/%d/%Y")

        try:
            group.add_member(
                requester=self.current_user,
                user_or_group=member,
                reason=form.data["reason"],
                status='actioned',
                expiration=expiration,
                role=form.data["role"]
            )
        except InvalidRoleForMember as e:
            return self.render(
                "group-add.html", form=form, group=group,
                alerts=[
                    Alert('danger', e.message)
                ]
            )

        self.session.commit()

        AuditLog.log(self.session, self.current_user.id, 'join_group',
                     '{} added to group with role: {}'.format(
                         member.name, form.data["role"]),
                     on_group_id=group.id)

        if member.type == "User":
            send_email(
                self.session,
                [member.name],
                'Added to group: {}'.format(group.name),
                'request_actioned',
                settings,
                {
                    'group_name': group.name,
                    'actioned_by': self.current_user.name,
                    'reason': form.data['reason'],
                    'expiration': expiration,
                    'role': form.data['role'],
                }
            )

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
コード例 #58
0
ファイル: permissions_grant.py プロジェクト: graham/grouper
    def post(self, name=None):
        grantable = user_grantable_permissions(self.session, self.current_user)
        if not grantable:
            return self.forbidden()

        group = Group.get(self.session, None, name)
        if not group:
            return self.notfound()

        form = PermissionGrantForm(self.request.arguments)
        form.permission.choices = [["", "(select one)"]]
        for perm in grantable:
            grantable_str = "{} ({})".format(perm[0].name, perm[1])
            form.permission.choices.append([perm[0].name, grantable_str])

        if not form.validate():
            return self.render("permission-grant.html",
                               form=form,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

        permission = Permission.get(self.session, form.data["permission"])
        if not permission:
            return self.notfound()  # Shouldn't happen.

        allowed = False
        for perm in grantable:
            if perm[0].name == permission.name:
                if matches_glob(perm[1], form.data["argument"]):
                    allowed = True
                    break
        if not allowed:
            form.argument.errors.append(
                "You do not have grant authority over that permission/argument combination."
            )
            return self.render(
                "permission-grant.html",
                form=form,
                group=group,
                alerts=self.get_form_alerts(form.errors),
            )

        # If the permission is audited, then see if the subtree meets auditing requirements.
        if permission.audited:
            fail_message = (
                "Permission is audited and this group (or a subgroup) contains "
                +
                "owners, np-owners, or managers who have not received audit training."
            )
            try:
                permission_ok = assert_controllers_are_auditors(group)
            except UserNotAuditor as e:
                permission_ok = False
                fail_message = e
            if not permission_ok:
                form.permission.errors.append(fail_message)
                return self.render(
                    "permission-grant.html",
                    form=form,
                    group=group,
                    alerts=self.get_form_alerts(form.errors),
                )

        try:
            grant_permission(self.session,
                             group.id,
                             permission.id,
                             argument=form.data["argument"])
        except IntegrityError:
            self.session.rollback()
            form.argument.errors.append(
                "Permission and Argument already mapped to this group.")
            return self.render(
                "permission-grant.html",
                form=form,
                group=group,
                alerts=self.get_form_alerts(form.errors),
            )

        self.session.commit()

        AuditLog.log(self.session,
                     self.current_user.id,
                     'grant_permission',
                     'Granted permission with argument: {}'.format(
                         form.data["argument"]),
                     on_permission_id=permission.id,
                     on_group_id=group.id)

        return self.redirect("/groups/{}?refresh=yes".format(group.name))