Exemple #1
0
def add_public_key(session, user, public_key_str):
    """Add a public key for a particular user.

    Args:
        session: db session
        user: User model of user in question
        public_key_str: public key to add

    Return created PublicKey model or raises DuplicateKey if key is already in use.
    """
    pubkey = sshpubkey.PublicKey.from_str(public_key_str)
    db_pubkey = PublicKey(
        user=user,
        public_key='%s %s %s' % (pubkey.key_type, pubkey.key, pubkey.comment),
        fingerprint=pubkey.fingerprint,
        key_size=pubkey.key_size,
        key_type=pubkey.key_type,
    )
    try:
        db_pubkey.add(session)
        Counter.incr(session, "updates")
    except IntegrityError:
        session.rollback()
        raise DuplicateKey()

    session.commit()

    return db_pubkey
Exemple #2
0
def grant_permission_to_tag(session, tag_id, permission_id, argument=''):
    # type: (Session, int, int, str) -> bool
    """
    Grant a permission to this tag. This will fail if the (permission, argument) has already
    been granted to this tag.

    Args:
        session(models.base.session.Sessioan): database session
        tag_id(int): the id of the tag we're granting the permission to
        permission_id(int): the id of the permission to be granted
        argument(str): must match constants.ARGUMENT_VALIDATION

    Throws:
        AssertError if argument does not match ARGUMENT_VALIDATION regex

    Returns:
        bool indicating whether the function succeeded or not
    """
    assert re.match(ARGUMENT_VALIDATION, argument), 'Permission argument does not match regex.'

    try:
        mapping = TagPermissionMap(permission_id=permission_id, tag_id=tag_id, argument=argument)
        mapping.add(session)

        Counter.incr(session, "updates")
    except IntegrityError:
        session.rollback()
        return False

    session.commit()
    return True
Exemple #3
0
def disable_permission_auditing(session: Session, permission_name: str,
                                actor_user_id: int) -> None:
    """Set a permission as audited.

    Args:
        session: Database session
        permission_name: Name of permission in question
        actor_user_id: ID of user who is disabling auditing
    """
    permission = get_permission(session, permission_name)
    if not permission:
        raise NoSuchPermission(name=permission_name)

    permission.audited = False

    AuditLog.log(
        session,
        actor_user_id,
        "disable_auditing",
        "Disabled auditing.",
        on_permission_id=permission.id,
    )

    Counter.incr(session, "updates")

    session.commit()
Exemple #4
0
    def update_status(self, requester, status, reason):
        now = datetime.utcnow()
        current_status = self.status
        self.status = status

        request_status_change = RequestStatusChange(request=self,
                                                    user_id=requester.id,
                                                    from_status=current_status,
                                                    to_status=status,
                                                    change_at=now).add(
                                                        self.session)
        self.session.flush()

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

        if status == "actioned":
            edge = self.session.query(GroupEdge).filter_by(
                id=self.edge_id).one()
            edge.apply_changes(self)

        Counter.incr(self.session, "updates")
Exemple #5
0
def test_passwords_api(session, users, http_client, base_url, graph):
    user = users['*****@*****.**']
    TEST_PASSWORD = "******"

    add_new_user_password(session, "test", TEST_PASSWORD, user.id)
    assert len(user_passwords(session, user)) == 1, "The user should only have a single password"

    graph.update_from_db(session)
    c = Counter.get(session, name="updates")
    api_url = url(base_url, '/users/{}'.format(user.username))
    resp = yield http_client.fetch(api_url)
    body = json.loads(resp.body)
    assert body["checkpoint"] == c.count, "The API response is not up to date"
    assert body["data"]["user"]["passwords"] != [], "The user should not have an empty passwords field"
    assert body["data"]["user"]["passwords"][0]["name"] == "test", "The password should have the same name"
    assert body["data"]["user"]["passwords"][0]["func"] == "crypt(3)-$6$", "This test does not support any hash functions other than crypt(3)-$6$"
    assert body["data"]["user"]["passwords"][0]["hash"] == crypt.crypt(TEST_PASSWORD, body["data"]["user"]["passwords"][0]["salt"]), "The hash should be the same as hashing the password and the salt together using the hashing function"
    assert body["data"]["user"]["passwords"][0]["hash"] != crypt.crypt("hello", body["data"]["user"]["passwords"][0]["salt"]), "The hash should not be the same as hashing the wrong password and the salt together using the hashing function"

    delete_user_password(session, "test", user.id)
    c = Counter.get(session, name="updates")
    graph.update_from_db(session)
    api_url = url(base_url, '/users/{}'.format(user.username))
    resp = yield http_client.fetch(api_url)
    body = json.loads(resp.body)
    assert body["checkpoint"] == c.count, "The API response is not up to date"
    assert body["data"]["user"]["passwords"] == [], "The user should not have any passwords"
Exemple #6
0
    def post(self, name=None, mapping_id=None):
        mapping = TagPermissionMap.get(self.session, id=mapping_id)
        if not mapping:
            return self.notfound()

        if not user_has_permission(self.session, self.current_user, TAG_EDIT,
                                   mapping.tag.name):
            return self.forbidden()

        permission = mapping.permission
        tag = mapping.tag

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

        AuditLog.log(
            self.session,
            self.current_user.id,
            "revoke_tag_permission",
            "Revoked permission with argument: {}".format(mapping.argument),
            on_tag_id=tag.id,
            on_permission_id=permission.id,
        )

        return self.redirect("/tags/{}?refresh=yes".format(tag.name))
    def set_metadata(self, key, value):
        if not re.match(PERMISSION_VALIDATION, key):
            raise ValueError('Metadata key does not match regex.')

        row = None
        for try_row in self.my_metadata():
            if try_row.data_key == key:
                row = try_row
                break

        if row:
            if value is None:
                row.delete(self.session)
            else:
                row.data_value = value
        else:
            if value is None:
                # Do nothing, a delete on a key that's not set
                return
            else:
                row = UserMetadata(user_id=self.id, data_key=key, data_value=value)
                row.add(self.session)

        Counter.incr(self.session, "updates")
        self.session.commit()
    def post(self, name=None, mapping_id=None):
        grantable = self.current_user.my_grantable_permissions()
        if not grantable:
            return self.forbidden()

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

        allowed = False
        for perm in grantable:
            if perm[0].name == mapping.permission.name:
                if matches_glob(perm[1], mapping.argument):
                    allowed = True
        if not allowed:
            return self.forbidden()

        permission = mapping.permission
        group = mapping.group

        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(mapping.argument),
                     on_group_id=group.id, on_permission_id=permission.id)

        return self.redirect('/groups/{}?refresh=yes'.format(group.name))
Exemple #9
0
    def post(self, name=None, mapping_id=None):
        mapping = PermissionMap.get(self.session, id=mapping_id)

        if not mapping:
            return self.notfound()

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

        permission = mapping.permission
        group = mapping.group

        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(
                         mapping.argument),
                     on_group_id=group.id,
                     on_permission_id=permission.id)

        return self.redirect('/groups/{}?refresh=yes'.format(group.name))
Exemple #10
0
def grant_permission_to_service_account(session: Session,
                                        account: ServiceAccount,
                                        permission: Permission,
                                        argument: str = "") -> None:
    """Grant a permission to this service account.

    This will fail if the (permission, argument) has already been granted to this group.

    Args:
        session: Database session
        account: A ServiceAccount object being granted a permission
        permission: A Permission object being granted
        argument: Must match constants.ARGUMENT_VALIDATION

    Throws:
        AssertError if argument does not match ARGUMENT_VALIDATION regex
    """
    assert re.match(ARGUMENT_VALIDATION + r"$",
                    argument), "Invalid permission argument"

    mapping = ServiceAccountPermissionMap(permission_id=permission.id,
                                          service_account_id=account.id,
                                          argument=argument)
    mapping.add(session)

    Counter.incr(session, "updates")

    session.commit()
Exemple #11
0
def disable_user(session, user):
    """Disables an enabled user"""

    get_plugin_proxy().will_disable_user(session, user)

    user.enabled = False
    Counter.incr(session, "updates")
Exemple #12
0
def grant_permission_to_service_account(session, account, permission, argument=""):
    """
    Grant a permission to this service account. This will fail if the (permission, argument) has
    already been granted to this group.

    Args:
        session(models.base.session.Session): database session
        account(ServiceAccount): a ServiceAccount object being granted a permission
        permission(Permission): a Permission object being granted
        argument(str): must match constants.ARGUMENT_VALIDATION

    Throws:
        AssertError if argument does not match ARGUMENT_VALIDATION regex
    """
    assert re.match(
        ARGUMENT_VALIDATION + r"$", argument
    ), "Permission argument does not match regex."

    mapping = ServiceAccountPermissionMap(
        permission_id=permission.id, service_account_id=account.id, argument=argument
    )
    mapping.add(session)

    Counter.incr(session, "updates")

    session.commit()
Exemple #13
0
    def post(self, tag_id=None, name=None):
        tag = PublicKeyTag.get(self.session, tag_id, name)
        if not tag:
            return self.notfound()

        if not user_has_permission(self.session, self.current_user, TAG_EDIT, tag.name):
            return self.forbidden()

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

        tag.description = form.data["description"]
        tag.enabled = form.data["enabled"]
        Counter.incr(self.session, "updates")

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

        AuditLog.log(self.session, self.current_user.id, 'edit_tag',
                     'Edited tag.', on_tag_id=tag.id)

        return self.redirect("/tags/{}".format(tag.name))
Exemple #14
0
def disable_permission_auditing(session, permission_name, actor_user_id):
    """Set a permission as audited.

    Args:
        session(models.base.session.Session): database session
        permission_name(str): name of permission in question
        actor_user_id(int): id of user who is disabling auditing
    """
    permission = get_permission(session, permission_name)
    if not permission:
        raise NoSuchPermission(name=permission_name)

    permission._audited = False

    AuditLog.log(
        session,
        actor_user_id,
        "disable_auditing",
        "Disabled auditing.",
        on_permission_id=permission.id,
    )

    Counter.incr(session, "updates")

    session.commit()
Exemple #15
0
def grant_permission_to_service_account(session,
                                        account,
                                        permission,
                                        argument=""):
    """
    Grant a permission to this service account. This will fail if the (permission, argument) has
    already been granted to this group.

    Args:
        session(models.base.session.Session): database session
        account(ServiceAccount): a ServiceAccount object being granted a permission
        permission(Permission): a Permission object being granted
        argument(str): must match constants.ARGUMENT_VALIDATION

    Throws:
        AssertError if argument does not match ARGUMENT_VALIDATION regex
    """
    assert re.match(ARGUMENT_VALIDATION + r"$",
                    argument), "Permission argument does not match regex."

    mapping = ServiceAccountPermissionMap(permission_id=permission.id,
                                          service_account_id=account.id,
                                          argument=argument)
    mapping.add(session)

    Counter.incr(session, "updates")

    session.commit()
Exemple #16
0
    def update_status(self, requester, status, reason):
        now = datetime.utcnow()
        current_status = self.status
        self.status = status

        request_status_change = RequestStatusChange(
            request=self,
            user_id=requester.id,
            from_status=current_status,
            to_status=status,
            change_at=now
        ).add(self.session)
        self.session.flush()

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

        if status == "actioned":
            edge = self.session.query(GroupEdge).filter_by(
                id=self.edge_id
            ).one()
            edge.apply_changes(self)

        Counter.incr(self.session, "updates")
Exemple #17
0
def disable_user(session, user):
    """Disables an enabled user"""

    get_plugin_proxy().will_disable_user(session, user)

    user.enabled = False
    Counter.incr(session, "updates")
Exemple #18
0
def grant_permission(session: Session,
                     group_id: int,
                     permission_id: int,
                     argument: str = "") -> None:
    """Grant a permission to this group.

    This will fail if the (permission, argument) has already been granted to this group.

    Args:
        session: Database session
        group_id: ID of group to which to grant the permission
        permission_id: ID of permission to grant
        argument: Must match constants.ARGUMENT_VALIDATION

    Throws:
        AssertError if argument does not match ARGUMENT_VALIDATION regex
    """
    assert re.match(ARGUMENT_VALIDATION + r"$",
                    argument), "Invalid permission argument"

    mapping = PermissionMap(permission_id=permission_id,
                            group_id=group_id,
                            argument=argument)
    mapping.add(session)

    Counter.incr(session, "updates")

    session.commit()
Exemple #19
0
    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))
Exemple #20
0
    def post(self, *args: Any, **kwargs: Any) -> None:
        mapping_id = int(self.get_path_argument("mapping_id"))
        mapping = PermissionMap.get(self.session, id=mapping_id)

        if not mapping:
            return self.notfound()

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

        permission = mapping.permission
        group = mapping.group

        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(mapping.argument),
            on_group_id=group.id,
            on_permission_id=permission.id,
        )

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

        tag = PublicKeyTag(
            name=form.data["tagname"],
            description=form.data["description"],
        )

        try:
            tag.add(self.session)
            self.session.flush()
        except IntegrityError:
            self.session.rollback()
            form.tagname.errors.append(
                "{} already exists".format(form.data["tagname"])
            )
            return self.render(
                "tag-create.html", form=form,
                alerts=self.get_form_alerts(form.errors)
            )

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

        AuditLog.log(self.session, self.current_user.id, 'create_tag',
                     'Created new tag.', on_tag_id=tag.id)

        return self.redirect("/tags/{}?refresh=yes".format(tag.name))
Exemple #22
0
def grant_permission_to_tag(session, tag_id, permission_id, argument=''):
    # type: (Session, int, int, str) -> bool
    """
    Grant a permission to this tag. This will fail if the (permission, argument) has already
    been granted to this tag.

    Args:
        session(models.base.session.Sessioan): database session
        tag_id(int): the id of the tag we're granting the permission to
        permission_id(int): the id of the permission to be granted
        argument(str): must match constants.ARGUMENT_VALIDATION

    Throws:
        AssertError if argument does not match ARGUMENT_VALIDATION regex

    Returns:
        bool indicating whether the function succeeded or not
    """
    assert re.match(ARGUMENT_VALIDATION + r"$", argument), \
        'Permission argument does not match regex.'

    try:
        mapping = TagPermissionMap(permission_id=permission_id, tag_id=tag_id, argument=argument)
        mapping.add(session)

        Counter.incr(session, "updates")
    except IntegrityError:
        session.rollback()
        return False

    session.commit()
    return True
Exemple #23
0
def test_passwords_api(session, users, http_client, base_url, graph):
    user = users['*****@*****.**']
    TEST_PASSWORD = "******"

    add_new_user_password(session, "test", TEST_PASSWORD, user.id)
    assert len(user_passwords(session, user)) == 1, "The user should only have a single password"

    graph.update_from_db(session)
    c = Counter.get(session, name="updates")
    api_url = url(base_url, '/users/{}'.format(user.username))
    resp = yield http_client.fetch(api_url)
    body = json.loads(resp.body)
    assert body["checkpoint"] == c.count, "The API response is not up to date"
    assert body["data"]["user"]["passwords"] != [], "The user should not have an empty passwords field"
    assert body["data"]["user"]["passwords"][0]["name"] == "test", "The password should have the same name"
    assert body["data"]["user"]["passwords"][0]["func"] == "crypt(3)-$6$", "This test does not support any hash functions other than crypt(3)-$6$"
    assert body["data"]["user"]["passwords"][0]["hash"] == crypt.crypt(TEST_PASSWORD, body["data"]["user"]["passwords"][0]["salt"]), "The hash should be the same as hashing the password and the salt together using the hashing function"
    assert body["data"]["user"]["passwords"][0]["hash"] != crypt.crypt("hello", body["data"]["user"]["passwords"][0]["salt"]), "The hash should not be the same as hashing the wrong password and the salt together using the hashing function"

    delete_user_password(session, "test", user.id)
    c = Counter.get(session, name="updates")
    graph.update_from_db(session)
    api_url = url(base_url, '/users/{}'.format(user.username))
    resp = yield http_client.fetch(api_url)
    body = json.loads(resp.body)
    assert body["checkpoint"] == c.count, "The API response is not up to date"
    assert body["data"]["user"]["passwords"] == [], "The user should not have any passwords"
Exemple #24
0
def add_public_key(session, user, public_key_str):
    """Add a public key for a particular user.

    Args:
        session: db session
        user: User model of user in question
        public_key_str: public key to add

    Return created PublicKey model or raises DuplicateKey if key is already in use.
    """
    pubkey = sshpubkeys.SSHKey(public_key_str, strict=True)
    pubkey.parse()

    db_pubkey = PublicKey(
        user=user,
        public_key=pubkey.keydata.strip(),
        fingerprint=pubkey.hash_md5().replace(b"MD5:", b""),
        key_size=pubkey.bits,
        key_type=pubkey.key_type,
    )
    try:
        db_pubkey.add(session)
        Counter.incr(session, "updates")
    except IntegrityError:
        session.rollback()
        raise DuplicateKey()

    session.commit()

    return db_pubkey
    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)
        )
Exemple #26
0
def disable_permission_auditing(session, permission_name, actor_user_id):
    """Set a permission as audited.

    Args:
        session(models.base.session.Session): database session
        permission_name(str): name of permission in question
        actor_user_id(int): id of user who is disabling auditing
    """
    permission = get_permission(session, permission_name)
    if not permission:
        raise NoSuchPermission(name=permission_name)

    permission.audited = False

    AuditLog.log(
        session,
        actor_user_id,
        "disable_auditing",
        "Disabled auditing.",
        on_permission_id=permission.id,
    )

    Counter.incr(session, "updates")

    session.commit()
Exemple #27
0
    def post(self):
        form = TagCreateForm(self.request.arguments)
        if not form.validate():
            return self.render(
                "tag-create.html", form=form, alerts=self.get_form_alerts(form.errors)
            )

        tag = PublicKeyTag(name=form.data["tagname"], description=form.data["description"])

        try:
            tag.add(self.session)
            self.session.flush()
        except IntegrityError:
            self.session.rollback()
            form.tagname.errors.append("{} already exists".format(form.data["tagname"]))
            return self.render(
                "tag-create.html", form=form, alerts=self.get_form_alerts(form.errors)
            )

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

        AuditLog.log(
            self.session, self.current_user.id, "create_tag", "Created new tag.", on_tag_id=tag.id
        )

        return self.redirect("/tags/{}?refresh=yes".format(tag.name))
def add_service_account(session, group, service_account):
    # type: (Session, Group, ServiceAccount) -> None
    """Add a service account to a group."""
    logging.debug("Adding service account %s to %s", service_account.user.username,
        group.groupname)
    GroupServiceAccount(group_id=group.id, service_account=service_account).add(session)
    Counter.incr(session, "updates")
    session.commit()
Exemple #29
0
def disable_user(session, user):
    """Disables an enabled user"""

    for plugin in get_plugins():
        plugin.will_disable_user(session, user)

    user.enabled = False
    Counter.incr(session, "updates")
Exemple #30
0
    def revoke_member(self, requester, user_or_group, reason):
        """ Revoke a member (User or Group) from this group.

            Arguments:
                requester: A User object of the person requesting the addition
                user_or_group: A User/Group object of the member
                reason: A comment on why this member should exist
        """
        now = datetime.utcnow()

        logging.debug(
            "Revoking member (%s) from %s", user_or_group.name, self.groupname
        )

        # Create the edge even if it doesn't exist so that we can explicitly
        # disable it.
        edge, new = GroupEdge.get_or_create(
            self.session,
            group_id=self.id,
            member_type=user_or_group.member_type,
            member_pk=user_or_group.id,
        )
        self.session.flush()

        request = Request(
            requester_id=requester.id,
            requesting_id=self.id,
            on_behalf_obj_type=user_or_group.member_type,
            on_behalf_obj_pk=user_or_group.id,
            requested_at=now,
            edge_id=edge.id,
            status="actioned",
            changes=build_changes(
                edge, role="member", expiration=None, active=False
            )
        ).add(self.session)
        self.session.flush()

        request_status_change = RequestStatusChange(
            request=request,
            user_id=requester.id,
            to_status="actioned",
            change_at=now
        ).add(self.session)
        self.session.flush()

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

        edge.apply_changes(request)
        self.session.flush()

        Counter.incr(self.session, "updates")
    def revoke_member(self, requester, user_or_group, reason):
        """ Revoke a member (User or Group) from this group.

            Arguments:
                requester: A User object of the person requesting the addition
                user_or_group: A User/Group object of the member
                reason: A comment on why this member should exist
        """
        now = datetime.utcnow()

        logging.debug(
            "Revoking member (%s) from %s", user_or_group.name, self.groupname
        )

        # Create the edge even if it doesn't exist so that we can explicitly
        # disable it.
        edge, new = GroupEdge.get_or_create(
            self.session,
            group_id=self.id,
            member_type=user_or_group.member_type,
            member_pk=user_or_group.id,
        )
        self.session.flush()

        request = Request(
            requester_id=requester.id,
            requesting_id=self.id,
            on_behalf_obj_type=user_or_group.member_type,
            on_behalf_obj_pk=user_or_group.id,
            requested_at=now,
            edge_id=edge.id,
            status="actioned",
            changes=build_changes(
                edge, role="member", expiration=None, active=False
            )
        ).add(self.session)
        self.session.flush()

        request_status_change = RequestStatusChange(
            request=request,
            user_id=requester.id,
            to_status="actioned",
            change_at=now
        ).add(self.session)
        self.session.flush()

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

        edge.apply_changes(request)
        self.session.flush()

        Counter.incr(self.session, "updates")
def add_service_account(session, group, service_account):
    # type: (Session, Group, ServiceAccount) -> None
    """Add a service account to a group."""
    logging.debug("Adding service account %s to %s",
                  service_account.user.username, group.groupname)
    GroupServiceAccount(group_id=group.id,
                        service_account=service_account).add(session)
    Counter.incr(session, "updates")
    session.commit()
Exemple #33
0
def disable_user_token(session, user_token):
    """Disable specified user token.

    Args:
        session(grouper.models.base.session.Session): database session
        user_token(grouper.models.user_token.UserToken): token to disable
    """
    user_token.disabled_at = datetime.utcnow()
    Counter.incr(session, "updates")
Exemple #34
0
def persist_group_member_changes(session, group, requester, member, status, reason,
                                 create_edge=False, **updates):
    requested_at = datetime.utcnow()

    if "role" in updates:
        role = updates["role"]
        _validate_role(member.member_type, role)

    get_plugin_proxy().will_update_group_membership(session, group, member, **updates)

    if create_edge:
        edge = _create_edge(session, group, member, updates.get("role", "member"))
    else:
        edge = _get_edge(session, group, member)
        if not edge:
            raise MemberNotFound()

    changes = _serialize_changes(edge, **updates)

    request = Request(
        requester_id=requester.id,
        requesting_id=group.id,
        on_behalf_obj_type=member.member_type,
        on_behalf_obj_pk=member.id,
        requested_at=requested_at,
        edge_id=edge.id,
        status=status,
        changes=changes,
    ).add(session)
    session.flush()

    request_status_change = RequestStatusChange(
        request=request,
        user_id=requester.id,
        to_status=status,
        change_at=requested_at,
    ).add(session)
    session.flush()

    Comment(
        obj_type=OBJ_TYPES["RequestStatusChange"],
        obj_pk=request_status_change.id,
        user_id=requester.id,
        comment=reason,
        created_on=requested_at,
    ).add(session)
    session.flush()

    if status == "actioned":
        edge.apply_changes(request.changes)
        session.flush()

    Counter.incr(session, "updates")

    return request
Exemple #35
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:
            return self.notfound()

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

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

        new_name = form.data["groupname"]
        renamed = group.groupname != new_name

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

        if renamed and Group.get(self.session, name=new_name):
            message = f"A group named '{new_name}' already exists (possibly disabled)"
            form.groupname.errors.append(message)
            return self.render("group-edit.html",
                               group=group,
                               form=form,
                               alerts=self.get_form_alerts(form.errors))

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

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

        url = f"/groups/{group.name}"
        if renamed:
            url += "?refresh=yes"
        self.redirect(url)
def enable_service_account(session, actor, service_account, owner):
    # type: (Session, User, ServiceAccount, Group) -> None
    """Enables a service account and sets a new owner."""
    enable_user(session, service_account.user, actor, preserve_membership=False)
    add_service_account(session, owner, service_account)

    AuditLog.log(session, actor.id, "enable_service_account", "Enabled service account.",
                 on_group_id=owner.id, on_user_id=service_account.user_id)

    Counter.incr(session, "updates")
    session.commit()
Exemple #37
0
def test_groups_email(groups, session, graph, http_client, base_url):
    expected_address = "*****@*****.**"
    sad = groups['sad-team']
    sad.email_address = expected_address
    session.commit()
    Counter.incr(session, "updates")
    graph.update_from_db(session)

    api_url = url(base_url, '/groups/{}'.format(sad.name))
    resp = yield http_client.fetch(api_url)
    body = json.loads(resp.body)

    assert body["data"]["group"]["contacts"]["email"] == expected_address
Exemple #38
0
def test_groups_email(groups, session, graph, http_client, base_url):  # noqa: F811
    expected_address = "*****@*****.**"
    sad = groups["sad-team"]
    sad.email_address = expected_address
    session.commit()
    Counter.incr(session, "updates")
    graph.update_from_db(session)

    api_url = url(base_url, "/groups/{}".format(sad.name))
    resp = yield http_client.fetch(api_url)
    body = json.loads(resp.body)

    assert body["data"]["group"]["contacts"]["email"] == expected_address
Exemple #39
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 = GroupEditForm(self.request.arguments, obj=group)
        if not form.validate():
            return self.render("group-edit.html",
                               group=group,
                               form=form,
                               alerts=self.get_form_alerts(form.errors))

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

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

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

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

        return self.redirect("/groups/{}".format(group.name))
Exemple #40
0
def delete_public_key(session, user_id, key_id):
    """Delete a particular user's public key.

    Args:
        session(models.base.session.Session): database session
        user_id(int): id of user in question
        key_id(int): id of the user's key we want to delete

    Throws:
        KeyNotFound if specified key wasn't found
    """
    pkey = get_public_key(session, user_id, key_id)
    pkey.delete(session)
    Counter.incr(session, "updates")
    session.commit()
Exemple #41
0
def delete_user_password(session, password_name, user_id):
    # type: (Session, str, int) -> None
    """Delete the specified UserPassword.

    Args:
        session(grouper.models.base.session.Session): database session
        password_name: the name of the password to delete
        user_id: the user whose password is being deleted
    """
    p = session.query(UserPassword).filter_by(name=password_name, user_id=user_id).scalar()
    if not p:
        raise PasswordDoesNotExist()
    p.delete(session)
    Counter.incr(session, "updates")
    session.commit()
Exemple #42
0
def delete_public_key(session, user_id, key_id):
    """Delete a particular user's public key.

    Args:
        session(models.base.session.Session): database session
        user_id(int): id of user in question
        key_id(int): id of the user's key we want to delete

    Throws:
        KeyNotFound if specified key wasn't found
    """
    pkey = get_public_key(session, user_id, key_id)
    pkey.delete(session)
    Counter.incr(session, "updates")
    session.commit()
Exemple #43
0
def add_public_key(session, user, public_key_str):
    """Add a public key for a particular user.

    Args:
        session: db session
        user: User model of user in question
        public_key_str: public key to add

    Throws:
        DuplicateKey if key is already in use
        PublicKeyParseError if key can't be parsed
        BadPublicKey if a plugin rejects the key

    Returns:
        PublicKey model object representing the key
    """
    pubkey = sshpubkeys.SSHKey(public_key_str, strict=True)

    try:
        pubkey.parse()
    except sshpubkeys.InvalidKeyException as e:
        raise PublicKeyParseError(str(e))

    try:
        get_plugin_proxy().will_add_public_key(pubkey)
    except PluginRejectedPublicKey as e:
        raise BadPublicKey(str(e))

    db_pubkey = PublicKey(
        user=user,
        public_key=pubkey.keydata.strip(),
        fingerprint=pubkey.hash_md5().replace("MD5:", ""),
        fingerprint_sha256=pubkey.hash_sha256().replace("SHA256:", ""),
        key_size=pubkey.bits,
        key_type=pubkey.key_type,
        comment=pubkey.comment,
    )

    try:
        db_pubkey.add(session)
        Counter.incr(session, "updates")
    except IntegrityError:
        session.rollback()
        raise DuplicateKey()

    session.commit()

    return db_pubkey
Exemple #44
0
def add_public_key(session, user, public_key_str):
    """Add a public key for a particular user.

    Args:
        session: db session
        user: User model of user in question
        public_key_str: public key to add

    Throws:
        DuplicateKey if key is already in use
        PublicKeyParseError if key can't be parsed
        BadPublicKey if a plugin rejects the key

    Returns:
        PublicKey model object representing the key
    """
    pubkey = sshpubkeys.SSHKey(public_key_str, strict=True)

    try:
        pubkey.parse()
    except sshpubkeys.InvalidKeyException as e:
        raise PublicKeyParseError(e.message)

    try:
        get_plugin_proxy().will_add_public_key(pubkey)
    except PluginRejectedPublicKey as e:
        raise BadPublicKey(e.message)

    db_pubkey = PublicKey(
        user=user,
        public_key=pubkey.keydata.strip(),
        fingerprint=pubkey.hash_md5().replace(b"MD5:", b""),
        fingerprint_sha256=pubkey.hash_sha256().replace(b"SHA256:", b""),
        key_size=pubkey.bits,
        key_type=pubkey.key_type,
        comment=pubkey.comment,
    )

    try:
        db_pubkey.add(session)
        Counter.incr(session, "updates")
    except IntegrityError:
        session.rollback()
        raise DuplicateKey()

    session.commit()

    return db_pubkey
Exemple #45
0
def delete_user_password(session, password_name, user_id):
    # type: (Session, str, int) -> None
    """Delete the specified UserPassword.

    Args:
        session(grouper.models.base.session.Session): database session
        password_name: the name of the password to delete
        user_id: the user whose password is being deleted
    """
    p = session.query(UserPassword).filter_by(name=password_name,
                                              user_id=user_id).scalar()
    if not p:
        raise PasswordDoesNotExist()
    p.delete(session)
    Counter.incr(session, "updates")
    session.commit()
def disable_service_account(session, actor, service_account):
    # type: (Session, User, ServiceAccount) -> None
    """Disables a service account and deletes the association with a Group."""
    disable_user(session, service_account.user)
    owner_id = service_account.owner.group.id
    service_account.owner.delete(session)
    permissions = session.query(ServiceAccountPermissionMap).filter_by(
        service_account_id=service_account.id)
    for permission in permissions:
        permission.delete(session)

    AuditLog.log(session, actor.id, "disable_service_account", "Disabled service account.",
                 on_group_id=owner_id, on_user_id=service_account.user_id)

    Counter.incr(session, "updates")
    session.commit()
Exemple #47
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 = GroupEditForm(self.request.arguments, obj=group)
        if not form.validate():
            return self.render(
                "group-edit.html", group=group, form=form,
                alerts=self.get_form_alerts(form.errors)
            )

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

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

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

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

        return self.redirect("/groups/{}".format(group.name))
Exemple #48
0
def add_new_user_password(session, password_name, password, user_id):
    # type: (Session, str, str, int) -> None
    """Add the new user password specified.

    Args:
        session(grouper.models.base.session.Session): database session
        password_name(str): name of the password to be added
        password(str): the (plaintext) password to be added
        user_id(int): the id of the user to add this password to
    """
    p = UserPassword(name=password_name, user_id=user_id)
    p.set_password(password)
    Counter.incr(session, "updates")
    p.add(session)
    try:
        session.commit()
    except IntegrityError:
        raise PasswordAlreadyExists()
Exemple #49
0
def add_new_user_password(session, password_name, password, user_id):
    # type: (Session, str, str, int) -> None
    """Add the new user password specified.

    Args:
        session(grouper.models.base.session.Session): database session
        password_name(str): name of the password to be added
        password(str): the (plaintext) password to be added
        user_id(int): the id of the user to add this password to
    """
    p = UserPassword(name=password_name, user_id=user_id)
    p.set_password(password)
    Counter.incr(session, "updates")
    p.add(session)
    try:
        session.commit()
    except IntegrityError:
        raise PasswordAlreadyExists()
def edit_service_account(session, actor, service_account, description, machine_set):
    # type: (Session, User, ServiceAccount, str, str) -> None
    """Update the description and machine set of a service account.

    Raises:
        PluginRejectedMachineSet: if some plugin rejected the machine set
    """
    if machine_set is not None:
        _check_machine_set(service_account, machine_set)

    service_account.description = description
    service_account.machine_set = machine_set
    Counter.incr(session, "updates")

    session.commit()

    AuditLog.log(session, actor.id, "edit_service_account", "Edited service account.",
                 on_user_id=service_account.user.id)
def test_permissions_aliased_permissions(mocker, session, standard_graph, http_client, base_url):
    proxy = PluginProxy([PermissionAliasesPlugin()])
    mocker.patch('grouper.graph.get_plugin_proxy', return_value=proxy)

    # Force graph update
    Counter.incr(session, "updates")
    standard_graph.update_from_db(session)

    api_url = url(base_url, '/permissions/ssh')
    resp = yield http_client.fetch(api_url)
    body = json.loads(resp.body)

    permissions = [
        (group, p['argument'])
        for group, g in body['data']['groups'].iteritems()
        for p in g['permissions']
    ]

    assert ('sad-team', 'owner=sad-team') in permissions
Exemple #52
0
def add_new_user_token(session, user_token):
    """Add the new user token specified. If user token doesn't contain a
    secret, create one.

    Args:
        session(grouper.models.base.session.Session): database session
        user_token(grouper.models.user_token.UserToken): token to create

    Returns:
        2-tuple of the created UserToken and the secret
    """
    secret = None
    if user_token.hashed_secret is None:
        secret = user_token._set_secret()

    user_token.add(session)
    Counter.incr(session, "updates")

    return user_token, secret
def test_users_aliased_permissions(
    mocker, session, standard_graph, http_client, base_url  # noqa: F811
):
    proxy = PluginProxy([PermissionAliasesPlugin()])
    mocker.patch("grouper.graph.get_plugin_proxy", return_value=proxy)

    # Force graph update
    Counter.incr(session, "updates")
    standard_graph.update_from_db(session)

    api_url = url(base_url, "/users/[email protected]")
    resp = yield http_client.fetch(api_url)
    body = json.loads(resp.body)

    perms = [(p["permission"], p["argument"]) for p in body["data"]["permissions"]]

    assert ("owner", "sad-team") in perms
    assert ("ssh", "owner=sad-team") in perms
    assert ("sudo", "sad-team") in perms
Exemple #54
0
def remove_tag_from_public_key(session, public_key, tag):
    # type: (Session, PublicKey, PublicKeyTag) -> None
    """Removes the tag from the given public key.

    Args:
        session(models.base.session.Session): database session
        public_key(models.public_key.PublicKey): the public key to be tagged
        tag(models.public_key_tag.PublicKeyTag): the tag to be removed from the public key

    Throws:
        TagNotOnKey if the tag was already assigned to the public key
    """
    mapping = session.query(PublicKeyTagMap).filter_by(tag_id=tag.id, key_id=public_key.id).scalar()

    if not mapping:
        raise TagNotOnKey()

    mapping.delete(session)
    Counter.incr(session, "updates")
    session.commit()
Exemple #55
0
def enable_permission_auditing(session, permission_name, actor_user_id):
    """Set a permission as audited.

    Args:
        session(models.base.session.Session): database session
        permission_name(str): name of permission in question
        actor_user_id(int): id of user who is enabling auditing
    """
    permission = Permission.get(session, permission_name)
    if not permission:
        raise NoSuchPermission(name=permission_name)

    permission._audited = True

    AuditLog.log(session, actor_user_id, 'enable_auditing', 'Enabled auditing.',
            on_permission_id=permission.id)

    Counter.incr(session, "updates")

    session.commit()