예제 #1
0
def test_sa_pubkeys(session, users, http_client, base_url):
    user = users['*****@*****.**']

    # Add account
    create_role_user(session, user, '*****@*****.**', 'Hi', 'canjoin')

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

    assert u is not None
    assert g is not None
    assert is_role_user(session, user=u)
    assert is_role_user(session, group=g)
    assert get_role_user(session, user=u).group.id == g.id
    assert get_role_user(session, group=g).user.id == u.id
    assert not is_role_user(session, user=user)
    assert not is_role_user(session, group=Group.get(session, name="team-sre"))

    assert not get_public_keys_of_user(session, user.id)

    with pytest.raises(HTTPError):
        # add it
        fe_url = url(base_url, '/users/{}/public-key/add'.format("*****@*****.**"))
        resp = yield http_client.fetch(fe_url, method="POST",
                body=urlencode({'public_key': SSH_KEY_1}),
                headers={'X-Grouper-User': "******"})

    # add it
    fe_url = url(base_url, '/users/{}/public-key/add'.format("*****@*****.**"))
    resp = yield http_client.fetch(fe_url, method="POST",
            body=urlencode({'public_key': SSH_KEY_1}),
            headers={'X-Grouper-User': user.username})
    assert resp.code == 200

    # add bad key -- shouldn't add
    fe_url = url(base_url, '/users/{}/public-key/add'.format("*****@*****.**"))
    resp = yield http_client.fetch(fe_url, method="POST",
            body=urlencode({'public_key': SSH_KEY_BAD}),
            headers={'X-Grouper-User': user.username})
    assert resp.code == 200

    sa = User.get(session, name="*****@*****.**")
    keys = get_public_keys_of_user(session, sa.id)
    assert len(keys) == 1
    assert keys[0].public_key == SSH_KEY_1

    with pytest.raises(HTTPError):
        # delete it
        fe_url = url(base_url, '/users/{}/public-key/{}/delete'.format("*****@*****.**", keys[0].id))
        resp = yield http_client.fetch(fe_url, method="POST", body='',
                headers={'X-Grouper-User': "******"})

    # delete it
    fe_url = url(base_url, '/users/{}/public-key/{}/delete'.format("*****@*****.**", keys[0].id))
    resp = yield http_client.fetch(fe_url, method="POST", body='',
            headers={'X-Grouper-User': user.username})
    assert resp.code == 200

    sa = User.get(session, name="*****@*****.**")
    assert not get_public_keys_of_user(session, sa.id)
예제 #2
0
def test_sa_tokens(session, users, http_client, base_url):
    user = users['*****@*****.**']

    # Add account
    create_role_user(session, user, '*****@*****.**', 'Hi', 'canjoin')

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

    assert u is not None
    assert g is not None
    assert is_role_user(session, user=u)
    assert is_role_user(session, group=g)
    assert get_role_user(session, user=u).group.id == g.id
    assert get_role_user(session, group=g).user.id == u.id
    assert not is_role_user(session, user=user)
    assert not is_role_user(session, group=Group.get(session, name="team-sre"))

    with pytest.raises(HTTPError):
        # Add token
        fe_url = url(base_url, '/users/{}/tokens/add'.format("*****@*****.**"))
        resp = yield http_client.fetch(fe_url, method="POST",
                body=urlencode({'name': 'myDHDToken'}),
                headers={'X-Grouper-User': "******"})

    # Add token
    fe_url = url(base_url, '/users/{}/tokens/add'.format("*****@*****.**"))
    resp = yield http_client.fetch(fe_url, method="POST",
            body=urlencode({'name': 'myDHDToken'}),
            headers={'X-Grouper-User': user.username})
    assert resp.code == 200

    # Verify add
    fe_url = url(base_url, '/users/{}'.format("*****@*****.**"))
    resp = yield http_client.fetch(fe_url, method="GET",
            headers={'X-Grouper-User': user.username})
    assert resp.code == 200
    assert "Added token: myDHDToken" in resp.body

    with pytest.raises(HTTPError):
        # Disable token
        fe_url = url(base_url, '/users/{}/tokens/1/disable'.format("*****@*****.**"))
        resp = yield http_client.fetch(fe_url, method="POST",
                body="",
                headers={'X-Grouper-User': "******"})

    # Disable token
    fe_url = url(base_url, '/users/{}/tokens/1/disable'.format("*****@*****.**"))
    resp = yield http_client.fetch(fe_url, method="POST",
            body="",
            headers={'X-Grouper-User': user.username})
    assert resp.code == 200

    # Verify disable
    fe_url = url(base_url, '/users/{}'.format("*****@*****.**"))
    resp = yield http_client.fetch(fe_url, method="GET",
            headers={'X-Grouper-User': user.username})
    assert resp.code == 200
    assert "Disabled token: myDHDToken" in resp.body
예제 #3
0
 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()
예제 #4
0
 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()
예제 #5
0
def test_group_name_checks(session, tmpdir, users, groups):  # noqa: F811
    username = "******"
    groupname = "team-sre"

    # check user/group name
    call_main(session, tmpdir, "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(session, tmpdir, "group", "add_member", "--member", groupname, bad_username)
    assert (u"User", bad_username) not in Group.get(session, name=groupname).my_members()
예제 #6
0
def test_group_bulk_add_remove(session, tmpdir, users, groups):  # noqa: F811
    groupname = "team-sre"

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

    # bulk remove
    call_main(session, tmpdir, "group", "remove_member", groupname, *usernames)
    members = {u for _, u in Group.get(session, name=groupname).my_members()}
    assert not members.intersection(usernames)
예제 #7
0
def test_group_disable_group_owner(get_plugin_proxy, session, tmpdir, users, groups):  # noqa: F811
    get_plugin_proxy.return_value = PluginProxy([GroupOwnershipPolicyPlugin()])

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

    # add
    call_main(session, tmpdir, "group", "add_member", "--owner", groupname, username)
    assert (u"User", username) in Group.get(session, name=groupname).my_members()

    # disable (fails)
    call_main(session, tmpdir, "user", "disable", username)
    assert (u"User", username) in Group.get(session, name=groupname).my_members()
예제 #8
0
def test_group_name_checks(make_session, session, users, groups):
    make_session.return_value = session

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

    # 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()
예제 #9
0
def test_group_add_remove_member(session, tmpdir, users, groups):  # noqa: F811
    username = "******"
    groupname = "team-sre"

    # add
    assert (u"User", username) not in groups[groupname].my_members()
    call_main(session, tmpdir, "group", "add_member", "--member", 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] == "member"

    # remove
    call_main(session, tmpdir, "group", "remove_member", groupname, username)
    assert (u"User", username) not in Group.get(session, name=groupname).my_members()
예제 #10
0
def test_group_bulk_add_remove(make_session, session, users, groups):
    make_session.return_value = session

    groupname = 'team-sre'

    # 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)
예제 #11
0
    def get(self, *args, **kwargs):
        # type: (*Any, **Any) -> None
        group_id = kwargs.get("group_id")  # type: Optional[int]
        name = kwargs.get("name")  # type: Optional[str]

        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,
        )
예제 #12
0
파일: audit.py 프로젝트: dropbox/grouper
def get_auditors_group(settings, session):
    # type: (Settings, Session) -> Group
    """Retrieve the group for auditors

    Arg(s):
        settings (settings): settings, to get the `auditors_group` name
        session (session): database session

    Return:
        Group object for the group for Grouper auditors, whose name is
        specified with `auditors_group` settings.

    Raise:
        Raise NoSuchGroup exception if either the name for the
        auditors group is not configured, or the group does not exist
        in the database. Raise GroupDoesNotHaveAuditPermission if the group
        does not actually have the PERMISSION_AUDITOR permission.
    """
    # TODO: switch to exc.NoSuchGroup to remove one source dependency
    # on graph.py
    group_name = get_auditors_group_name(settings)
    if not group_name:
        raise NoSuchGroup("Please ask your admin to configure the `auditors_group` settings")
    group = Group.get(session, name=group_name)
    if not group:
        raise NoSuchGroup("Please ask your admin to configure the default group for auditors")
    if not any([p.name == PERMISSION_AUDITOR for p in group.my_permissions()]):
        raise GroupDoesNotHaveAuditPermission()
    return group
예제 #13
0
def get_role_user(session, user=None, group=None):
    # type: (Session, User, Group) -> RoleUser
    """
    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:
        RoleUserNotFound: 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_role_user(session, user, group):
        raise RoleUserNotFound()

    if user:
        name = user.name
    else:
        assert group is not None
        name = group.name
    return RoleUser(User.get(session, name=name), Group.get(session, name=name))
예제 #14
0
    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 = get_requests_by_group(self.session, group, status=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_INDICES,
            '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,
        )
예제 #15
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()

        on_behalf = get_on_behalf_by_request(self.session, request)

        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, on_behalf=on_behalf,
            members=members, form=form, statuses=REQUEST_STATUS_CHOICES, updates=updates
        )
예제 #16
0
    def post(self, user_id=None, name=None):
        service_account = ServiceAccount.get(self.session, user_id, name)
        if not service_account:
            return self.notfound()

        if not self.check_access(self.session, self.current_user, service_account):
            return self.forbidden()

        form = self.get_form()
        if not form.validate():
            return self.render(
                "service-account-enable.html",
                form=form,
                user=service_account.user,
                alerts=self.get_form_alerts(form.errors),
            )

        owner = Group.get(self.session, name=form.data["owner"])
        if owner is None:
            form.owner.errors.append("Group not found.")
            return self.render(
                "service-account-enable.html",
                form=form,
                user=service_account.user,
                alerts=self.get_form_alerts(form.errors),
            )

        enable_service_account(self.session, self.current_user, service_account, owner)
        return self.redirect(
            "/groups/{}/service/{}?refresh=yes".format(owner.name, service_account.user.username)
        )
예제 #17
0
def test_group_disable_group_owner(user_make_session, group_make_session, get_plugin_proxy, session,
                                   users, groups):
    group_make_session.return_value = session
    user_make_session.return_value = session
    get_plugin_proxy.return_value = PluginProxy([GroupOwnershipPolicyPlugin()])

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

    # add
    call_main('group', 'add_member', '--owner', groupname, username)
    assert (u'User', username) in Group.get(session, name=groupname).my_members()

    # disable (fails)
    call_main('user', 'disable', username)
    assert (u'User', username) in Group.get(session, name=groupname).my_members()
예제 #18
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) 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_role_user(self.session, group=group):
            return self.forbidden()

        group.disable()

        self.session.commit()

        AuditLog.log(self.session, self.current_user.id, 'disable_group',
                     'Disabled group.', on_group_id=group.id)

        if group.audit:
            # complete the audit
            group.audit.complete = True
            self.session.commit()

            AuditLog.log(self.session, self.current_user.id, 'complete_audit',
                         'Disabling group completes group audit.', on_group_id=group.id)

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
    def post(self, group_id=None, name=None, account_id=None, accountname=None, mapping_id=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()
        service_account = ServiceAccount.get(self.session, account_id, accountname)
        if not service_account:
            return self.notfound()

        if not self.check_access(self.session, self.current_user, service_account):
            return self.forbidden()

        mapping = ServiceAccountPermissionMap.get(self.session, mapping_id)
        if not mapping:
            return self.notfound()

        permission = mapping.permission
        argument = mapping.argument

        mapping.delete(self.session)
        Counter.incr(self.session, "updates")
        self.session.commit()

        AuditLog.log(
            self.session,
            self.current_user.id,
            "revoke_permission",
            "Revoked permission with argument: {}".format(argument),
            on_permission_id=permission.id,
            on_group_id=group.id,
            on_user_id=service_account.user.id,
        )

        return self.redirect(
            "/groups/{}/service/{}?refresh=yes".format(group.name, service_account.user.username)
        )
예제 #20
0
    def post(self, group_id=None, name=None, account_id=None, accountname=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()
        service_account = ServiceAccount.get(self.session, account_id, accountname)
        if not service_account:
            return self.notfound()

        if not can_manage_service_account(self.session, service_account, self.current_user):
            return self.forbidden()

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

        try:
            edit_service_account(self.session, self.current_user, service_account,
                                 form.data["description"], form.data["machine_set"])
        except BadMachineSet as e:
            form.machine_set.errors.append(str(e))
            return self.render(
                "service-account-edit.html", service_account=service_account, group=group,
                form=form, alerts=self.get_form_alerts(form.errors)
            )

        return self.redirect("/groups/{}/service/{}".format(
            group.name, service_account.user.username))
예제 #21
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)]
예제 #22
0
def test_oneoff(mock_make_session, 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_load_plugins.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'
예제 #23
0
def test_group_add_remove_owner(get_plugin_proxy, session, tmpdir, users, groups):  # noqa: F811
    get_plugin_proxy.return_value = PluginProxy([GroupOwnershipPolicyPlugin()])

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

    # add
    assert (u"User", username) not in groups[groupname].my_members()
    call_main(session, tmpdir, "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 (fails)
    call_main(session, tmpdir, "group", "remove_member", groupname, username)
    assert (u"User", username) in Group.get(session, name=groupname).my_members()
예제 #24
0
def test_add_role_user(session, users, http_client, base_url):  # noqa: F811
    user = users["*****@*****.**"]

    # Add account
    create_role_user(session, user, "*****@*****.**", "Hi", "canjoin")

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

    assert u is not None
    assert g is not None
    assert is_role_user(session, user=u)
    assert is_role_user(session, group=g)
    assert get_role_user(session, user=u).group.id == g.id
    assert get_role_user(session, group=g).user.id == u.id
    assert not is_role_user(session, user=user)
    assert not is_role_user(session, group=Group.get(session, name="team-sre"))
예제 #25
0
def test_oneoff(mock_load_plugins, session, tmpdir):  # noqa: F811
    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_load_plugins.return_value = [FakeOneOff()]

    # dry_run
    call_main(session, tmpdir, "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(session, tmpdir, "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(session, tmpdir, "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(session, tmpdir, "oneoff", "run", "--no-dry_run", "FakeOneOff", "bad_arg")

    call_main(session, tmpdir, "oneoff", "run", "--no-dry_run", "FakeOneOff", "key=valuewith=")
    assert User.get(session, name=other_username) is not None, '"valuewith= in arg, create user2'
예제 #26
0
파일: setup.py 프로젝트: dropbox/grouper
 def add_group_to_group(self, member, group, expiration=None):
     # type: (str, str, Optional[datetime]) -> None
     self.create_group(member)
     self.create_group(group)
     member_obj = Group.get(self.session, name=member)
     assert member_obj
     group_obj = Group.get(self.session, name=group)
     assert group_obj
     edge = GroupEdge(
         group_id=group_obj.id,
         member_type=OBJ_TYPES["Group"],
         member_pk=member_obj.id,
         expiration=expiration,
         active=True,
         _role=GROUP_EDGE_ROLES.index("member"),
     )
     edge.add(self.session)
예제 #27
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', '--member', 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] == "member"

    # remove
    call_main('group', 'remove_member', groupname, username)
    assert (u'User', username) not in Group.get(session, name=groupname).my_members()
예제 #28
0
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()
예제 #29
0
def test_add_role_user(session, users, http_client, base_url):
    user = users['*****@*****.**']

    # Add account
    create_role_user(session, user, '*****@*****.**', 'Hi', 'canjoin')

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

    assert u is not None
    assert g is not None
    assert is_role_user(session, user=u)
    assert is_role_user(session, group=g)
    assert get_role_user(session, user=u).group.id == g.id
    assert get_role_user(session, group=g).user.id == u.id
    assert not is_role_user(session, user=user)
    assert not is_role_user(session, group=Group.get(session, name="team-sre"))
예제 #30
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"
예제 #31
0
    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 = get_permission(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))
예제 #32
0
파일: sync_db.py 프로젝트: bonniech3n/merou
def sync_db_command(args):
    # Models not implicitly or explictly imported above are explicitly imported here
    from grouper.models.perf_profile import PerfProfile  # noqa: F401

    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 = get_permission(session, name)
        if test:
            continue
        try:
            create_permission(session, name, description)
            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 = get_permission(session, permission_name)
            assert permission, "Permission should have been created earlier!"
            grant_permission(session, admin_group.id, permission.id)

        session.commit()

    auditors_group_name = get_auditors_group_name(settings)
    auditors_group = Group.get(session, name=auditors_group_name)
    if not auditors_group:
        auditors_group = Group(
            groupname=auditors_group_name,
            description=
            "Group for auditors, who can be owners of audited groups.",
            canjoin="canjoin",
        )

        try:
            auditors_group.add(session)
            session.flush()
        except IntegrityError:
            session.rollback()
            raise Exception(
                "Failed to create group: {}".format(auditors_group_name))

        permission = get_permission(session, PERMISSION_AUDITOR)
        assert permission, "Permission should have been created earlier!"
        grant_permission(session, auditors_group.id, permission.id)

        session.commit()
예제 #33
0
파일: audit_log.py 프로젝트: Warrelis/merou
 def _id_for_group(self, group):
     # type: (str) -> int
     group_obj = Group.get(self.session, name=group)
     if not group_obj:
         raise GroupNotFoundException(group)
     return group_obj.id
예제 #34
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:
            request = 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("/permissions/requests/{}".format(request.id))
    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()

        on_behalf = get_on_behalf_by_request(self.session, request)

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

        updates = request.my_status_updates()

        if not form.status.choices:
            alerts = [Alert("info", "Request has already been processed")]
            return self.render("group-request-update.html",
                               group=group,
                               request=request,
                               on_behalf=on_behalf,
                               members=members,
                               form=form,
                               alerts=alerts,
                               statuses=REQUEST_STATUS_CHOICES,
                               updates=updates)

        if not form.validate():
            return self.render("group-request-update.html",
                               group=group,
                               request=request,
                               on_behalf=on_behalf,
                               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,
                    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,
                                   on_behalf=on_behalf,
                                   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
        ]

        subj = "Re: " + self.render_template('email/pending_request_subj.tmpl',
                                             group=group.name,
                                             user=request.requester.username)

        send_email(
            self.session,
            approver_mail_to,
            subj,
            "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'],
                'references_header': request.reference_id,
            },
        )

        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))
예제 #36
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 = 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()

        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")

        try:
            group.edit_member(self.current_user,
                              user_or_group,
                              form.data["reason"],
                              role=form.data["role"],
                              expiration=expiration)
        except (InvalidRoleForMember,
                PluginRejectedGroupMembershipUpdate) as e:
            return self.render("group-edit-member.html",
                               form=form,
                               group=group,
                               member=member,
                               edge=edge,
                               alerts=[Alert('danger', e.message)])

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #37
0
def test_sa_tokens(session, users, http_client, base_url):  # noqa: F811
    user = users["*****@*****.**"]

    # Add account
    create_role_user(session, user, "*****@*****.**", "Hi", "canjoin")

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

    assert u is not None
    assert g is not None
    assert is_role_user(session, user=u)
    assert is_role_user(session, group=g)
    assert get_role_user(session, user=u).group.id == g.id
    assert get_role_user(session, group=g).user.id == u.id
    assert not is_role_user(session, user=user)
    assert not is_role_user(session, group=Group.get(session, name="team-sre"))

    with pytest.raises(HTTPError):
        # Add token
        fe_url = url(base_url, "/users/{}/tokens/add".format("*****@*****.**"))
        resp = yield http_client.fetch(
            fe_url,
            method="POST",
            body=urlencode({"name": "myDHDToken"}),
            headers={"X-Grouper-User": "******"},
        )

    # Add token
    fe_url = url(base_url, "/users/{}/tokens/add".format("*****@*****.**"))
    resp = yield http_client.fetch(
        fe_url,
        method="POST",
        body=urlencode({"name": "myDHDToken"}),
        headers={"X-Grouper-User": user.username},
    )
    assert resp.code == 200

    # Verify add
    fe_url = url(base_url, "/users/{}".format("*****@*****.**"))
    resp = yield http_client.fetch(fe_url, method="GET", headers={"X-Grouper-User": user.username})
    assert resp.code == 200
    assert b"Added token: myDHDToken" in resp.body

    with pytest.raises(HTTPError):
        # Disable token
        fe_url = url(base_url, "/users/{}/tokens/1/disable".format("*****@*****.**"))
        resp = yield http_client.fetch(
            fe_url, method="POST", body="", headers={"X-Grouper-User": "******"}
        )

    # Disable token
    fe_url = url(base_url, "/users/{}/tokens/1/disable".format("*****@*****.**"))
    resp = yield http_client.fetch(
        fe_url, method="POST", body="", headers={"X-Grouper-User": user.username}
    )
    assert resp.code == 200

    # Verify disable
    fe_url = url(base_url, "/users/{}".format("*****@*****.**"))
    resp = yield http_client.fetch(fe_url, method="GET", headers={"X-Grouper-User": user.username})
    assert resp.code == 200
    assert b"Disabled token: myDHDToken" in resp.body
예제 #38
0
def test_service_accounts(setup):
    # type: (SetupTest) -> None
    """Tests remaining non-usecase service account functions."""
    with setup.transaction():
        setup.create_service_account("*****@*****.**", "team-sre",
                                     "some machines", "some service account")
        setup.add_user_to_group("*****@*****.**", "team-sre", "owner")
        setup.add_user_to_group("*****@*****.**", "admins")
        setup.grant_permission_to_group(USER_ADMIN, "", "admins")
        setup.add_user_to_group("*****@*****.**", "team-sre")
        setup.create_user("*****@*****.**")
        setup.grant_permission_to_service_account("team-sre", "*",
                                                  "*****@*****.**")
        setup.create_group("security-team")

    group = Group.get(setup.session, name="team-sre")
    assert group
    accounts = get_service_accounts(setup.session, group)
    assert len(accounts) == 1
    service_account = accounts[0]
    assert service_account.user.name == "*****@*****.**"
    assert service_account.user.is_service_account

    # zorkian should be able to manage the account, as should gary, but oliver (not a member of the
    # group) should not.
    zorkian_user = User.get(setup.session, name="*****@*****.**")
    assert zorkian_user
    gary_user = User.get(setup.session, name="*****@*****.**")
    assert gary_user
    oliver_user = User.get(setup.session, name="*****@*****.**")
    assert oliver_user
    assert can_manage_service_account(setup.session, service_account,
                                      zorkian_user)
    assert can_manage_service_account(setup.session, service_account,
                                      gary_user)
    assert not can_manage_service_account(setup.session, service_account,
                                          oliver_user)

    # Diabling the service account should remove the link to the group.
    disable_service_account(setup.session, zorkian_user, service_account)
    assert service_account.user.enabled == False
    assert get_service_accounts(setup.session, group) == []

    # The user should also be gone from the graph and have its permissions removed.
    setup.graph.update_from_db(setup.session)
    group_details = setup.graph.get_group_details("team-sre")
    assert "service_accounts" not in group_details
    metadata = setup.graph.user_metadata["*****@*****.**"]
    assert not metadata["enabled"]
    assert "owner" not in metadata["service_account"]
    user_details = setup.graph.get_user_details("*****@*****.**")
    assert user_details["permissions"] == []

    # We can re-enable and attach to a different group.
    new_group = Group.get(setup.session, name="security-team")
    assert new_group
    enable_service_account(setup.session, zorkian_user, service_account,
                           new_group)
    assert service_account.user.enabled == True
    assert get_service_accounts(setup.session, group) == []
    accounts = get_service_accounts(setup.session, new_group)
    assert len(accounts) == 1
    assert accounts[0].user.name == "*****@*****.**"

    # Check that this is reflected in the graph and the user has no permissions.
    setup.graph.update_from_db(setup.session)
    group_details = setup.graph.get_group_details("security-team")
    assert group_details["service_accounts"] == ["*****@*****.**"]
    metadata = setup.graph.user_metadata["*****@*****.**"]
    assert metadata["service_account"]["owner"] == "security-team"
    user_details = setup.graph.get_user_details("*****@*****.**")
    assert user_details["permissions"] == []
예제 #39
0
 def disable_group(self, group):
     # type: (str) -> None
     group_obj = Group.get(self.session, name=group)
     assert group_obj
     group_obj.enabled = False
예제 #40
0
    def post(self, *args, **kwargs):
        # type: (*Any, **Any) -> None
        request_id = kwargs["request_id"]  # type: int
        group_id = kwargs.get("group_id")  # type: Optional[int]
        name = kwargs.get("name")  # type: Optional[str]

        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()

        on_behalf = get_on_behalf_by_request(self.session, request)

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

        updates = request.my_status_updates()

        if not form.status.choices:
            alerts = [Alert("info", "Request has already been processed")]
            return self.render(
                "group-request-update.html",
                group=group,
                request=request,
                on_behalf=on_behalf,
                members=members,
                form=form,
                alerts=alerts,
                statuses=REQUEST_STATUS_CHOICES,
                updates=updates,
            )

        if not form.validate():
            return self.render(
                "group-request-update.html",
                group=group,
                request=request,
                on_behalf=on_behalf,
                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, on_behalf, role=request.edge.role
                )
            except UserNotAuditor as e:
                user_can_join = False
                fail_message = str(e)
            if not user_can_join:
                return self.render(
                    "group-request-update.html",
                    group=group,
                    request=request,
                    on_behalf=on_behalf,
                    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
        ]

        subj = "Re: " + self.render_template(
            "email/pending_request_subj.tmpl", group=group.name, user=request.requester.username
        )

        send_email(
            self.session,
            approver_mail_to,
            subj,
            "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"],
                "references_header": request.reference_id,
            },
        )

        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))
예제 #41
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()

        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_role_user(self.session, member):
            # For service accounts, we want to always add the group to other groups, not the user
            member = get_role_user(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()

        on_user_id = member.id if member.type == "User" else None
        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,
                     on_user_id=on_user_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))
예제 #42
0
def test_grant_and_revoke(
        session,
        standard_graph,
        graph,
        groups,
        permissions,
        http_client,
        base_url  # noqa: F811
):
    """Test that permission grant and revokes are reflected correctly."""
    group_name = "team-sre"
    permission_name = "sudo"
    user_name = "*****@*****.**"

    def _check_graph_for_perm(graph):
        # type: (GroupGraph) -> bool
        return any([
            g["permission"] == permission_name and g["distance"] == 0
            for g in graph.get_group_details(group_name)["permissions"]
        ])

    # make some permission admins
    grant_permission(groups["security-team"], permissions[PERMISSION_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 = get_permission(session, 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"
예제 #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.")

        role_user = is_role_user(self.session, group=group)

        if role_user and get_role_user(
                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.",
            )

        try:
            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,
            )
        except PluginRejectedGroupMembershipUpdate as e:
            alert = Alert("danger", str(e))

            if role_user:
                return self.redirect("/service/{}".format(group.name),
                                     alerts=[alert])
            else:
                return self.redirect("/groups/{}".format(group.name),
                                     alerts=[alert])

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #44
0
    def post(self):
        form = AuditCreateForm(self.request.arguments)
        if not form.validate():
            return self.render("audit-create.html",
                               form=form,
                               alerts=self.get_form_alerts(form.errors))

        user = self.get_current_user()
        if not user_has_permission(self.session, user, AUDIT_MANAGER):
            return self.forbidden()

        # Step 1, detect if there are non-completed audits and fail if so.
        open_audits = self.session.query(Audit).filter(
            Audit.complete == False).all()
        if open_audits:
            raise Exception("Sorry, there are audits in progress.")
        ends_at = datetime.strptime(form.data["ends_at"], "%m/%d/%Y")

        # Step 2, find all audited groups and schedule audits for each.
        audited_groups = []
        for groupname in self.graph.groups:
            if not self.graph.get_group_details(groupname)["audited"]:
                continue
            group = Group.get(self.session, name=groupname)
            audit = Audit(group_id=group.id, ends_at=ends_at)
            try:
                audit.add(self.session)
                self.session.flush()
            except IntegrityError:
                self.session.rollback()
                raise Exception("Failed to start the audit. Please try again.")

            # Update group with new audit
            audited_groups.append(group)
            group.audit_id = audit.id

            # Step 3, now get all members of this group and set up audit rows for those edges.
            for member in group.my_members().values():
                auditmember = AuditMember(audit_id=audit.id,
                                          edge_id=member.edge_id)
                try:
                    auditmember.add(self.session)
                except IntegrityError:
                    self.session.rollback()
                    raise Exception(
                        "Failed to start the audit. Please try again.")

        self.session.commit()

        AuditLog.log(
            self.session,
            self.current_user.id,
            "start_audit",
            "Started global audit.",
            category=AuditLogCategory.audit,
        )

        # Calculate schedule of emails, basically we send emails at various periods in advance
        # of the end of the audit period.
        schedule_times = []
        not_before = datetime.utcnow() + timedelta(1)
        for days_prior in (28, 21, 14, 7, 3, 1):
            email_time = ends_at - timedelta(days_prior)
            email_time.replace(hour=17, minute=0, second=0)
            if email_time > not_before:
                schedule_times.append((days_prior, email_time))

        # Now send some emails. We do this separately/later to ensure that the audits are all
        # created. Email notifications are sent multiple times if group audits are still
        # outstanding.
        for group in audited_groups:
            mail_to = [
                member.name for member in group.my_users()
                if GROUP_EDGE_ROLES[member.role] in ("owner", "np-owner")
            ]

            send_email(
                self.session,
                mail_to,
                "Group Audit: {}".format(group.name),
                "audit_notice",
                settings,
                {
                    "group": group.name,
                    "ends_at": ends_at
                },
            )

            for days_prior, email_time in schedule_times:
                send_async_email(
                    self.session,
                    mail_to,
                    "Group Audit: {} - {} day(s) left".format(
                        group.name, days_prior),
                    "audit_notice_reminder",
                    settings,
                    {
                        "group": group.name,
                        "ends_at": ends_at,
                        "days_left": days_prior
                    },
                    email_time,
                    async_key="audit-{}".format(group.id),
                )

        return self.redirect("/audits")
예제 #45
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"
예제 #46
0
 def get(self, group_id=None, name=None):
     group = Group.get(self.session, group_id, name)
     if not group:
         return self.notfound()
     form = ServiceAccountCreateForm()
     return self.render("service-account-create.html", form=form, group=group)
예제 #47
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))
예제 #48
0
    def post(self,
             group_id=None,
             name=None,
             account_id=None,
             accountname=None):
        group = Group.get(self.session, group_id, name)
        if not group:
            return self.notfound()
        service_account = ServiceAccount.get(self.session, account_id,
                                             accountname)
        if not service_account:
            return self.notfound()
        user = service_account.user

        if not self.check_access(self.session, self.current_user,
                                 service_account):
            return self.forbidden()

        grantable = group.my_permissions()
        form = self.get_form(grantable)
        if not form.validate():
            return self.render("service-account-permission-grant.html",
                               form=form,
                               user=user,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

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

        allowed = False
        for perm in grantable:
            if perm[1] == permission.name:
                if matches_glob(perm[3], form.data["argument"]):
                    allowed = True
                    break
        if not allowed:
            form.argument.errors.append(
                "The group {} does not have that permission".format(
                    group.name))
            return self.render("service-account-permission-grant.html",
                               form=form,
                               user=user,
                               group=group,
                               alerts=self.get_form_alerts(form.errors))

        try:
            grant_permission_to_service_account(self.session, service_account,
                                                permission,
                                                form.data["argument"])
        except IntegrityError:
            self.session.rollback()
            return self.render("service-account-permission-grant.html",
                               form=form,
                               user=user,
                               alerts=self.get_form_alerts(form.errors))

        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,
                     on_user_id=service_account.user.id)

        return self.redirect("/groups/{}/service/{}?refresh=yes".format(
            group.name, service_account.user.username))
예제 #49
0
    def post(self, *args, **kwargs):
        # type: (*Any, **Any) -> None
        group_id = kwargs.get("group_id")  # type: Optional[int]
        name = kwargs.get("name")  # type: Optional[str]

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

        members = group.my_members()
        member_groups = {g for t, g in members if t == "Group"}
        user_is_member = self._is_user_a_member(group, members)

        form = GroupJoinForm(self.request.arguments)
        form.member.choices = self._get_choices(group, member_groups,
                                                user_is_member)
        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"])
        if not member:
            return self.render(
                "group-join.html",
                form=form,
                group=group,
                alerts=[
                    Alert(
                        "danger", "Unknown user or group: {}".format(
                            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 = str(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)])

        if group.require_clickthru_tojoin:
            if not form.data["clickthru_agreement"]:
                return self.render(
                    "group-join.html",
                    form=form,
                    group=group,
                    alerts=[
                        Alert(
                            "danger",
                            "please accept review of the group's description",
                            "Clickthru Enforcement",
                        )
                    ],
                )

        # 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))
예제 #50
0
def notify_edge_expiration(settings: Settings, session: Session,
                           edge: GroupEdge) -> None:
    """Send notification that an edge has expired.

    Handles email notification and audit logging.

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

    # Pull data about the edge and the affected user or group.
    #
    # TODO(rra): The audit log currently has no way of representing a system action.  Everything
    # must be attributed to a user.  When expiring a user, use the user themselves as the actor for
    # the audit log entry.  When expiring a group, use an arbitrary owner of the group from which
    # they are expiring or, if that fails, an arbitrary owner of the group whose membership is
    # expiring.  If neither group has an owner, raise an exception.  This can all go away once the
    # audit log has a mechanism for recording system actions.
    group_name = edge.group.name
    if OBJ_TYPES_IDX[edge.member_type] == "User":
        user = User.get(session, pk=edge.member_pk)
        assert user
        actor_id = user.id
        member_name = user.username
        recipients = [member_name]
        member_is_user = True
    else:
        subgroup = Group.get(session, pk=edge.member_pk)
        parent_owners = edge.group.my_owners()
        if parent_owners:
            actor_id = list(parent_owners.values())[0].id
        else:
            child_owners = subgroup.my_owners()
            if child_owners:
                actor_id = list(child_owners.values())[0].id
            else:
                msg = "{} and {} both have no owners during expiration of {}'s membership".format(
                    group_name, subgroup.groupname, subgroup.groupname)
                raise UnknownActorDuringExpirationException(msg)
        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:
        assert 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,
    )
예제 #51
0
    def post(self, *args, **kwargs):
        # type: (*Any, **Any) -> None
        form, args_by_perm = self._build_form(self.request.arguments)

        if not form.validate():
            return self.render(
                "permission-request.html",
                args_by_perm_json=json.dumps(args_by_perm),
                form=form,
                alerts=self.get_form_alerts(form.errors),
            )

        group = Group.get(self.session, name=form.group_name.data)
        if group is None:
            raise HTTPError(status_code=400, reason="that group does not exist")

        permission = get_permission(self.session, form.permission_name.data)
        if permission is None:
            raise HTTPError(status_code=400, reason="that permission does not exist")

        if permission.name not in args_by_perm:
            raise HTTPError(status_code=400, reason="that permission was not in the form")

        # save off request
        try:
            request = 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.",
                )
            ]
        except UserNotAuditor as e:
            alerts = [Alert("danger", str(e))]
        else:
            alerts = []

        if alerts:
            return self.render(
                "permission-request.html",
                args_by_perm_json=json.dumps(args_by_perm),
                form=form,
                alerts=alerts,
            )
        else:
            return self.redirect("/permissions/requests/{}".format(request.id))
예제 #52
0
def test_disable_role_user(session, users, http_client, base_url):  # noqa: F811
    user = users["*****@*****.**"]

    # Add account
    create_role_user(session, user, "*****@*****.**", "Hi", "canjoin")

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

    assert u is not None
    assert g is not None
    assert is_role_user(session, user=u)
    assert is_role_user(session, group=g)
    assert get_role_user(session, user=u).group.id == g.id
    assert get_role_user(session, group=g).user.id == u.id
    assert not is_role_user(session, user=user)
    assert not is_role_user(session, group=Group.get(session, name="team-sre"))

    disable_role_user(session, user=u)
    u = User.get(session, name="*****@*****.**")
    assert not u.enabled, "The SA User should be disabled"
    g = Group.get(session, name="*****@*****.**")
    assert not g.enabled, "The SA Group should be disabled"

    enable_role_user(session, actor=user, group=g, preserve_membership=True)
    u = User.get(session, name="*****@*****.**")
    assert u.enabled, "The SA User should be enabled"
    g = Group.get(session, name="*****@*****.**")
    assert g.enabled, "The SA Group should be enabled"

    with pytest.raises(HTTPError):
        fe_url = url(base_url, "/groups/{}/disable".format("*****@*****.**"))
        yield http_client.fetch(
            fe_url, method="POST", body="", headers={"X-Grouper-User": user.username}
        )

    u = User.get(session, name="*****@*****.**")
    assert u.enabled, "Attempting to disable SAs through groups/disable should not work"
    g = Group.get(session, name="*****@*****.**")
    assert g.enabled, "Attempting to disable SAs through groups/disable should not work"

    fe_url = url(base_url, "/users/{}/disable".format("*****@*****.**"))
    yield http_client.fetch(
        fe_url, method="POST", body="", headers={"X-Grouper-User": user.username}
    )

    u = User.get(session, name="*****@*****.**")
    assert not u.enabled, "The SA User should be disabled"
    g = Group.get(session, name="*****@*****.**")
    assert not g.enabled, "The SA Group should be disabled"

    with pytest.raises(HTTPError):
        fe_url = url(base_url, "/groups/{}/enable".format("*****@*****.**"))
        yield http_client.fetch(
            fe_url, method="POST", body="", headers={"X-Grouper-User": user.username}
        )

    u = User.get(session, name="*****@*****.**")
    assert not u.enabled, "Attempting to enable SAs through groups/enable should not work"
    g = Group.get(session, name="*****@*****.**")
    assert not g.enabled, "Attempting to enable SAs through groups/enable should not work"
예제 #53
0
def _load_permissions_by_group_name(session, group_name):  # noqa: F811
    group = Group.get(session, name=group_name)
    return [name for _, name, _, _, _ in group.my_permissions()]
예제 #54
0
def test_auditor_promotion(mock_nnp, mock_gagn, session, graph, permissions,
                           users):  # noqa: F811
    """Test automatic promotion of non-auditor approvers

    We set up our own group/user/permission for testing instead of
    using the `standard_graph` fixture---retrofitting it to work for
    us and also not break existing tests is too cumbersome.

    So here are our groups:

    very-special-auditors:
      * user14

    group-1:
      * user11 (o)
      * user12
      * user13 (np-o)
      * user14 (o, a)

    group-2:
      * user13 (np-o)
      * user21 (o)
      * user22

    group-3:
      * user22 (o)
      * user12 (o)

    group-4:
      * user21 (np-o)
      * user41
      * user42 (o)
      * user43 (np-o)

    o: owner, np-o: no-permission owner, a: auditor

    group-1 and group-2 have the permission that we will enable
    auditing. group-4 will be a subgroup of group-1 and thus will
    inherit the audited permission from group-1.

    The expected outcome is: user11, user13, user21, user42, and
    user43 will be added to the auditors group.

    """
    settings = BackgroundSettings()
    set_global_settings(settings)

    #
    # set up our test part of the graph
    #

    # create groups
    AUDITED_GROUP = "audited"
    AUDITORS_GROUP = mock_gagn.return_value = "very-special-auditors"
    PERMISSION_NAME = "test-permission"
    all_groups = {
        groupname: Group.get_or_create(session, groupname=groupname)[0]
        for groupname in ("group-1", "group-2", "group-3", "group-4",
                          AUDITORS_GROUP)
    }
    # create users
    users.update({
        username + "@a.co": User.get_or_create(session,
                                               username=username + "@a.co")[0]
        for username in (
            "user11",
            "user12",
            "user13",
            "user14",
            "user21",
            "user22",
            "user23",
            "user41",
            "user42",
            "user43",
        )
    })
    # create permissions
    permissions.update({
        permission: get_or_create_permission(
            session,
            permission,
            description="{} permission".format(permission))[0]
        for permission in [PERMISSION_NAME]
    })
    # add users to groups
    for (groupname, username, role) in (
        ("group-1", "user11", "owner"),
        ("group-1", "user12", "member"),
        ("group-1", "user13", "np-owner"),
        ("group-1", "user14", "owner"),
        ("group-2", "user13", "np-owner"),
        ("group-2", "user21", "owner"),
        ("group-2", "user22", "member"),
        ("group-3", "user12", "owner"),
        ("group-3", "user22", "owner"),
        ("group-4", "user21", "np-owner"),
        ("group-4", "user41", "member"),
        ("group-4", "user42", "owner"),
        ("group-4", "user43", "np-owner"),
    ):
        add_member(all_groups[groupname], users[username + "@a.co"], role=role)
    # add group-4 as member of group-1
    add_member(all_groups["group-1"], all_groups["group-4"])
    # add user14 to auditors group
    add_member(all_groups[AUDITORS_GROUP], users["*****@*****.**"])
    # grant permissions to groups
    #
    # give the test permission to groups 1 and 2, and group 4 should
    # also inherit from group 1
    grant_permission(all_groups["group-1"], permissions[PERMISSION_NAME])
    grant_permission(all_groups["group-2"], permissions[PERMISSION_NAME])
    grant_permission(all_groups[AUDITORS_GROUP],
                     permissions[PERMISSION_AUDITOR])

    graph.update_from_db(session)
    # done setting up

    # now a few pre-op checks
    assert not graph.get_group_details("group-1").get(AUDITED_GROUP)
    assert not graph.get_group_details("group-4").get(AUDITED_GROUP)
    assert get_users(graph, AUDITORS_GROUP) == set(["*****@*****.**"])
    assert get_users(graph, "group-3") == set(["*****@*****.**", "*****@*****.**"])

    #
    # run the promotion logic -> nothing should happen because the
    # test-permission is not yet audited
    #
    background = BackgroundProcessor(settings, None)
    background.promote_nonauditors(session)
    graph.update_from_db(session)

    # nothing should have happened
    assert not graph.get_group_details("group-1").get(AUDITED_GROUP)
    assert not graph.get_group_details("group-4").get(AUDITED_GROUP)
    assert get_users(graph, AUDITORS_GROUP) == set(["*****@*****.**"])
    assert mock_nnp.call_count == 0

    #
    # now enable auditing for the permission and run the promotion
    # logic again
    #
    enable_permission_auditing(session, PERMISSION_NAME,
                               users["*****@*****.**"].id)
    graph.update_from_db(session)
    assert graph.get_group_details("group-1").get(AUDITED_GROUP)
    assert graph.get_group_details("group-4").get(AUDITED_GROUP)

    background = BackgroundProcessor(settings, None)
    background.promote_nonauditors(session)
    graph.update_from_db(session)

    # check that stuff happened
    assert get_users(graph, AUDITORS_GROUP) == set([
        "*****@*****.**", "*****@*****.**", "*****@*****.**", "*****@*****.**",
        "*****@*****.**", "*****@*****.**"
    ])
    expected_calls = [
        call(settings, session, users["*****@*****.**"],
             all_groups[AUDITORS_GROUP], set(["group-1"])),
        call(
            settings,
            session,
            users["*****@*****.**"],
            all_groups[AUDITORS_GROUP],
            set(["group-1", "group-2"]),
        ),
        call(
            settings,
            session,
            users["*****@*****.**"],
            all_groups[AUDITORS_GROUP],
            set(["group-2", "group-4"]),
        ),
        call(settings, session, users["*****@*****.**"],
             all_groups[AUDITORS_GROUP], set(["group-4"])),
        call(settings, session, users["*****@*****.**"],
             all_groups[AUDITORS_GROUP], set(["group-4"])),
    ]
    assert mock_nnp.call_count == len(expected_calls)
    mock_nnp.assert_has_calls(expected_calls, any_order=True)

    #
    # run the background promotion logic again, and nothing should
    # happen
    #
    mock_nnp.reset_mock()
    background = BackgroundProcessor(settings, None)
    background.promote_nonauditors(session)
    assert mock_nnp.call_count == 0
예제 #55
0
    def post(self, *args: Any, **kwargs: Any) -> None:
        name = self.get_path_argument("name")

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

        members = group.my_members()
        member_groups = {g for t, g in members if t == "Group"}
        user_is_member = self._is_user_a_member(group, members)

        form = GroupJoinForm(self.request.arguments)
        form.member.choices = self._get_choices(group, member_groups,
                                                user_is_member)
        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"])
        if not member:
            return self.render(
                "group-join.html",
                form=form,
                group=group,
                alerts=[
                    Alert(
                        "danger", "Unknown user or group: {}".format(
                            form.data["member"]))
                ],
            )

        try:
            assert_can_join(group, member, role=form.data["role"])
        except UserNotAuditor as e:
            return self.render(
                "group-join.html",
                form=form,
                group=group,
                alerts=[Alert("danger", str(e), "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)])

        if group.require_clickthru_tojoin:
            if not form.data["clickthru_agreement"]:
                return self.render(
                    "group-join.html",
                    form=form,
                    group=group,
                    alerts=[
                        Alert(
                            "danger",
                            "please accept review of the group's description",
                            "Clickthru Enforcement",
                        )
                    ],
                )

        # 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

        # If the requested role is member, set the status based on the group's canjoin setting,
        # which automatically actions the request if the group can be joined by anyone and
        # otherwise sets it pending.
        #
        # However, we don't want to let people autojoin as owner or np-owner even to otherwise open
        # groups, so if the role is not member, force the status to pending.
        if form.data["role"] == "member":
            status = GROUP_JOIN_CHOICES[group.canjoin]
        else:
            status = "pending"

        try:
            request = group.add_member(
                requester=self.current_user,
                user_or_group=member,
                reason=form.data["reason"],
                status=status,
                expiration=expiration,
                role=form.data["role"],
            )
        except InvalidRoleForMember as e:
            return self.render(
                "group-join.html",
                form=form,
                group=group,
                alerts=[Alert("danger", str(e), "Invalid Role")],
            )
        self.session.commit()

        if status == "pending":
            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 status == "actioned":
            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(f"Unknown join status {status}")

        return self.redirect("/groups/{}?refresh=yes".format(group.name))
예제 #56
0
파일: misc_test.py 프로젝트: Warrelis/merou
def test_oneoff(mock_load_plugins, session, tmpdir):  # noqa: F811
    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_load_plugins.return_value = [FakeOneOff()]

    # dry_run
    call_main(session, tmpdir, "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(session, tmpdir, "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(session, tmpdir, "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(session, tmpdir, "oneoff", "run", "--no-dry_run",
                  "FakeOneOff", "bad_arg")

    call_main(session, tmpdir, "oneoff", "run", "--no-dry_run", "FakeOneOff",
              "key=valuewith=")
    assert User.get(
        session,
        name=other_username) is not None, '"valuewith= in arg, create user2'
예제 #57
0
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.models.group import Group

    # 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,
    )
예제 #58
0
def create_request(session: Session, user: User, group: Group,
                   permission: Permission, argument: str,
                   reason: str) -> PermissionRequest:
    """Creates an permission request and sends notification to the responsible approvers.

    Args:
        session: Database session
        user: User requesting permission
        group: Group requested permission would be applied to
        permission: Permission in question to request
        argument: argument for the given permission
        reason: reason the permission should be granted

    Raises:
        RequestAlreadyExists: Trying to create a request that is already pending
        NoOwnersAvailable: No owner is available for the requested perm + arg.
        grouper.audit.UserNotAuditor: The group has owners that are not auditors
    """
    # check if group already has perm + arg pair
    for _, existing_perm_name, _, existing_perm_argument, _ in group.my_permissions(
    ):
        if permission.name == existing_perm_name and argument == existing_perm_argument:
            raise RequestAlreadyGranted()

    # check if request already pending for this perm + arg pair
    existing_count = (session.query(PermissionRequest).filter(
        PermissionRequest.group_id == group.id,
        PermissionRequest.permission_id == permission.id,
        PermissionRequest.argument == argument,
        PermissionRequest.status == "pending",
    ).count())

    if existing_count > 0:
        raise RequestAlreadyExists()

    # determine owner(s)
    owners_by_arg_by_perm = get_owners_by_grantable_permission(
        session, separate_global=True)
    owner_arg_list = get_owner_arg_list(
        session,
        permission,
        argument,
        owners_by_arg_by_perm=owners_by_arg_by_perm)

    if not owner_arg_list:
        raise NoOwnersAvailable()

    if permission.audited:
        # will raise UserNotAuditor if any owner of the group is not an auditor
        assert_controllers_are_auditors(group)

    pending_status = "pending"
    now = datetime.utcnow()

    # multiple steps to create the request
    request = PermissionRequest(
        requester_id=user.id,
        group_id=group.id,
        permission_id=permission.id,
        argument=argument,
        status=pending_status,
        requested_at=now,
    ).add(session)
    session.flush()

    request_status_change = PermissionRequestStatusChange(
        request=request, user=user, to_status=pending_status,
        change_at=now).add(session)
    session.flush()

    Comment(
        obj_type=OBJ_TYPES_IDX.index("PermissionRequestStatusChange"),
        obj_pk=request_status_change.id,
        user_id=user.id,
        comment=reason,
        created_on=now,
    ).add(session)

    # send notification
    email_context = {
        "user_name": user.name,
        "group_name": group.name,
        "permission_name": permission.name,
        "argument": argument,
        "reason": reason,
        "request_id": request.id,
        "references_header": request.reference_id,
    }

    # TODO: would be nicer if it told you which group you're an approver of
    # that's causing this notification

    mail_to = []
    global_owners = owners_by_arg_by_perm[GLOBAL_OWNERS]["*"]
    non_wildcard_owners = [
        grant for grant in owner_arg_list if grant[1] != "*"
    ]
    non_global_owners = [
        grant for grant in owner_arg_list if grant[0] not in global_owners
    ]
    if any(non_wildcard_owners):
        # non-wildcard owners should get all the notifications
        mailto_owner_arg_list = non_wildcard_owners
    elif any(non_global_owners):
        mailto_owner_arg_list = non_global_owners
    else:
        # only the wildcards so they get the notifications
        mailto_owner_arg_list = owner_arg_list

    for owner, arg in mailto_owner_arg_list:
        if owner.email_address:
            mail_to.append(owner.email_address)
        else:
            mail_to.extend([u for t, u in owner.my_members() if t == "User"])

    template_engine = EmailTemplateEngine(settings())
    subject_template = template_engine.get_template(
        "email/pending_permission_request_subj.tmpl")
    subject = subject_template.render(permission=permission.name,
                                      group=group.name)
    send_email(session, set(mail_to), subject, "pending_permission_request",
               settings(), email_context)

    return request
예제 #59
0
def test_sa_pubkeys(session, users, http_client, base_url):  # noqa: F811
    user = users["*****@*****.**"]

    # Add account
    create_role_user(session, user, "*****@*****.**", "Hi", "canjoin")

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

    assert u is not None
    assert g is not None
    assert is_role_user(session, user=u)
    assert is_role_user(session, group=g)
    assert get_role_user(session, user=u).group.id == g.id
    assert get_role_user(session, group=g).user.id == u.id
    assert not is_role_user(session, user=user)
    assert not is_role_user(session, group=Group.get(session, name="team-sre"))

    assert not get_public_keys_of_user(session, user.id)

    with pytest.raises(HTTPError):
        # add it
        fe_url = url(base_url, "/users/{}/public-key/add".format("*****@*****.**"))
        resp = yield http_client.fetch(
            fe_url,
            method="POST",
            body=urlencode({"public_key": SSH_KEY_1}),
            headers={"X-Grouper-User": "******"},
        )

    # add it
    fe_url = url(base_url, "/users/{}/public-key/add".format("*****@*****.**"))
    resp = yield http_client.fetch(
        fe_url,
        method="POST",
        body=urlencode({"public_key": SSH_KEY_1}),
        headers={"X-Grouper-User": user.username},
    )
    assert resp.code == 200

    # add bad key -- shouldn't add
    fe_url = url(base_url, "/users/{}/public-key/add".format("*****@*****.**"))
    resp = yield http_client.fetch(
        fe_url,
        method="POST",
        body=urlencode({"public_key": SSH_KEY_BAD}),
        headers={"X-Grouper-User": user.username},
    )
    assert resp.code == 200

    sa = User.get(session, name="*****@*****.**")
    keys = get_public_keys_of_user(session, sa.id)
    assert len(keys) == 1
    assert keys[0].public_key == SSH_KEY_1

    with pytest.raises(HTTPError):
        # delete it
        fe_url = url(
            base_url, "/users/{}/public-key/{}/delete".format("*****@*****.**", keys[0].id)
        )
        resp = yield http_client.fetch(
            fe_url, method="POST", body="", headers={"X-Grouper-User": "******"}
        )

    # delete it
    fe_url = url(
        base_url, "/users/{}/public-key/{}/delete".format("*****@*****.**", keys[0].id)
    )
    resp = yield http_client.fetch(
        fe_url, method="POST", body="", headers={"X-Grouper-User": user.username}
    )
    assert resp.code == 200

    sa = User.get(session, name="*****@*****.**")
    assert not get_public_keys_of_user(session, sa.id)
예제 #60
0
파일: group.py 프로젝트: Warrelis/merou
 def create_group(self, name, description, join_policy):
     # type: (str, str, GroupJoinPolicy) -> None
     group = SQLGroup(groupname=name,
                      description=description,
                      canjoin=join_policy.value)
     group.add(self.session)