コード例 #1
0
ファイル: user.py プロジェクト: santoshankr/grouper
def disable_user(session, user):
    """Disables an enabled user"""

    get_plugin_proxy().will_disable_user(session, user)

    user.enabled = False
    Counter.incr(session, "updates")
コード例 #2
0
ファイル: user.py プロジェクト: santoshankr/grouper
 def just_created(self):
     # type: () -> None
     """Call the user_created plugin on new User creation."""
     # This is a little weird because the default value of the column isn't applied in the
     # object at the time this is called, so role_user may be None instead of False.
     is_service_account = self.role_user is not None and self.role_user
     get_plugin_proxy().user_created(self, is_service_account)
コード例 #3
0
ファイル: stats.py プロジェクト: dropbox/grouper
def set_defaults():
    # type: () -> None
    instance = task_id()
    if instance is None:
        instance = 0

    default_tags = {"instance": str(instance)}

    get_plugin_proxy().set_default_stats_tags(default_tags)
コード例 #4
0
ファイル: group_member.py プロジェクト: santoshankr/grouper
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
コード例 #5
0
def _check_machine_set(service_account, machine_set):
    # type: (ServiceAccount, str) -> None
    """Verify a service account machine set with plugins.

    Raises:
        BadMachineSet: if some plugin rejected the machine set
    """
    try:
        get_plugin_proxy().check_machine_set(service_account.user.username, machine_set)
    except PluginRejectedMachineSet as e:
        raise BadMachineSet(str(e))
コード例 #6
0
ファイル: public_key.py プロジェクト: dropbox/grouper
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
コード例 #7
0
    def run(self, session, dry_run=True):
        for key in session.query(PublicKey):
            pubkey = sshpubkeys.SSHKey(key.public_key, strict=True)

            logging.info("Processing Key (id={})".format(key.id))

            try:
                pubkey.parse()
            except sshpubkeys.InvalidKeyException as e:
                logging.error("Invalid Key (id={}): {}".format(key.id, e.message))
                continue

            try:
                get_plugin_proxy().will_add_public_key(pubkey)
            except PluginRejectedPublicKey as e:
                logging.error("Bad Key (id={}): {}".format(key.id, e.message))
                continue
コード例 #8
0
ファイル: permissions.py プロジェクト: santoshankr/grouper
def get_owners_by_grantable_permission(session, separate_global=False):
    """
    Returns all known permission arguments with owners. This consolidates
    permission grants supported by grouper itself as well as any grants
    governed by plugins.

    Args:
        session(sqlalchemy.orm.session.Session): database session

    Returns:
        A map of permission to argument to owners of the form {permission:
        {argument: [owner1, ...], }, } where 'owners' are models.Group objects.
        And 'argument' can be '*' which means 'anything'.
    """
    all_permissions = {permission.name: permission for permission in Permission.get_all(session)}
    all_groups = session.query(Group).filter(Group.enabled == True).all()

    owners_by_arg_by_perm = defaultdict(lambda: defaultdict(list))

    all_group_permissions = session.query(
            Permission.name,
            PermissionMap.argument,
            PermissionMap.granted_on,
            Group,
    ).filter(
            PermissionMap.group_id == Group.id,
            Permission.id == PermissionMap.permission_id,
    ).all()

    grants_by_group = defaultdict(list)

    for grant in all_group_permissions:
        grants_by_group[grant.Group.id].append(grant)

    for group in all_groups:
        # special case permission admins
        group_permissions = grants_by_group[group.id]
        if any(filter(lambda g: g.name == PERMISSION_ADMIN, group_permissions)):
            for perm_name in all_permissions:
                owners_by_arg_by_perm[perm_name]["*"].append(group)
            if separate_global:
                owners_by_arg_by_perm[GLOBAL_OWNERS]["*"].append(group)
            continue

        grants = [gp for gp in group_permissions if gp.name == PERMISSION_GRANT]

        for perm, arg in filter_grantable_permissions(session, grants,
                all_permissions=all_permissions):
            owners_by_arg_by_perm[perm.name][arg].append(group)

    # merge in plugin results
    for res in get_plugin_proxy().get_owner_by_arg_by_perm(session):
        for perm, owners_by_arg in res.items():
            for arg, owners in owners_by_arg.items():
                owners_by_arg_by_perm[perm][arg] += owners

    return owners_by_arg_by_perm
コード例 #9
0
ファイル: audit_log.py プロジェクト: santoshankr/grouper
    def log(session, actor_id, action, description,
            on_user_id=None, on_group_id=None, on_permission_id=None, on_tag_id=None,
            category=AuditLogCategory.general):
        """
        Log an event in the database.

        Args:
            session(Session): database session
            actor_id(int): actor
            action(str): unique string identifier for action taken
            description(str): description for action taken
            on_user_id(int): user affected, if any
            on_group_id(int): group affected, if any
            on_permission_id(int): permission affected, if any
            category(AuditLogCategory): category of log entry
        """
        entry = AuditLog(
            actor_id=actor_id,
            log_time=datetime.utcnow(),
            action=action,
            description=description,
            on_user_id=on_user_id if on_user_id else None,
            on_group_id=on_group_id if on_group_id else None,
            on_permission_id=on_permission_id if on_permission_id else None,
            on_tag_id=on_tag_id if on_tag_id else None,
            category=int(category),
        )
        try:
            entry.add(session)
            session.flush()
        except IntegrityError:
            session.rollback()
            raise AuditLogFailure()
        session.commit()

        get_plugin_proxy().log_auditlog_entry(entry)
コード例 #10
0
ファイル: graph.py プロジェクト: dropbox/grouper
    def _get_group_grants(session):
        # type: (Session) -> Dict[str, List[GroupPermissionGrant]]
        """Returns a dict of group names to lists of permission grants."""
        permissions = session.query(SQLPermission, PermissionMap, SQLGroup.groupname).filter(
            SQLPermission.id == PermissionMap.permission_id,
            PermissionMap.group_id == SQLGroup.id,
            SQLGroup.enabled == True,
        )

        out = defaultdict(list)  # type: Dict[str, List[GroupPermissionGrant]]
        for (permission, permission_map, groupname) in permissions:
            out[groupname].append(
                GroupPermissionGrant(
                    group=groupname,
                    permission=permission.name,
                    argument=permission_map.argument,
                    granted_on=permission_map.granted_on,
                    is_alias=False,
                    grant_id=permission_map.id,
                )
            )

            aliases = get_plugin_proxy().get_aliases_for_mapped_permission(
                session, permission.name, permission_map.argument
            )

            for (name, arg) in aliases:
                out[groupname].append(
                    GroupPermissionGrant(
                        group=groupname,
                        permission=name,
                        argument=arg,
                        granted_on=permission_map.granted_on,
                        is_alias=True,
                        grant_id=None,
                    )
                )

        return out
コード例 #11
0
ファイル: util.py プロジェクト: dropbox/grouper
    def initialize(self, *args, **kwargs):
        # type: (*Any, **Any) -> None
        self.graph = Graph()
        self.session = self.settings["session"]()  # type: Session
        self.template_engine = self.settings["template_engine"]  # type: FrontendTemplateEngine
        self.plugins = get_plugin_proxy()
        session_factory = SingletonSessionFactory(self.session)
        self.usecase_factory = create_graph_usecase_factory(
            settings(), self.plugins, session_factory
        )

        if self.get_argument("_profile", False):
            self.perf_collector = Collector()
            self.perf_trace_uuid = str(uuid4())  # type: Optional[str]
            self.perf_collector.start()
        else:
            self.perf_collector = None
            self.perf_trace_uuid = None

        self._request_start_time = datetime.utcnow()

        stats.log_rate("requests", 1)
        stats.log_rate("requests_{}".format(self.__class__.__name__), 1)
コード例 #12
0
ファイル: graph.py プロジェクト: santoshankr/grouper
    def _get_permission_metadata(session):
        '''
        Returns a dict of groupname: { list of permissions }.
        '''
        out = defaultdict(list)  # groupid -> [ ... ]

        permissions = session.query(Permission, PermissionMap).filter(
            Permission.id == PermissionMap.permission_id,
            PermissionMap.group_id == Group.id,
            Group.enabled == True,
        )

        for (permission, permission_map) in permissions:
            out[permission_map.group.name].append(MappedPermission(
                permission=permission.name,
                audited=permission.audited,
                argument=permission_map.argument,
                groupname=permission_map.group.name,
                granted_on=permission_map.granted_on,
                alias=False,
            ))

            aliases = get_plugin_proxy().get_aliases_for_mapped_permission(
                session, permission.name, permission_map.argument
            )

            for (name, arg) in aliases:
                out[permission_map.group.name].append(MappedPermission(
                    permission=name,
                    audited=permission.audited,
                    argument=arg,
                    groupname=permission_map.group.name,
                    granted_on=permission_map.granted_on,
                    alias=True,
                ))

        return out
コード例 #13
0
ファイル: stats.py プロジェクト: karthik-shanmugam/merou
def log_rate(key, val, count=1):
    # type: (str, float, int) -> None
    get_plugin_proxy().log_rate(key, val, count)
コード例 #14
0
def get_owners_by_grantable_permission(session, separate_global=False):
    """
    Returns all known permission arguments with owners. This consolidates
    permission grants supported by grouper itself as well as any grants
    governed by plugins.

    Args:
        session(sqlalchemy.orm.session.Session): database session

    Returns:
        A map of permission to argument to owners of the form {permission:
        {argument: [owner1, ...], }, } where 'owners' are models.Group objects.
        And 'argument' can be '*' which means 'anything'.
    """
    all_permissions = {
        permission.name: permission
        for permission in Permission.get_all(session)
    }
    all_groups = session.query(Group).filter(Group.enabled == True).all()

    owners_by_arg_by_perm = defaultdict(lambda: defaultdict(list))

    all_group_permissions = session.query(
        Permission.name,
        PermissionMap.argument,
        PermissionMap.granted_on,
        Group,
    ).filter(
        PermissionMap.group_id == Group.id,
        Permission.id == PermissionMap.permission_id,
    ).all()

    grants_by_group = defaultdict(list)

    for grant in all_group_permissions:
        grants_by_group[grant.Group.id].append(grant)

    for group in all_groups:
        # special case permission admins
        group_permissions = grants_by_group[group.id]
        if any(filter(lambda g: g.name == PERMISSION_ADMIN,
                      group_permissions)):
            for perm_name in all_permissions:
                owners_by_arg_by_perm[perm_name]["*"].append(group)
            if separate_global:
                owners_by_arg_by_perm[GLOBAL_OWNERS]["*"].append(group)
            continue

        grants = [
            gp for gp in group_permissions if gp.name == PERMISSION_GRANT
        ]

        for perm, arg in filter_grantable_permissions(
                session, grants, all_permissions=all_permissions):
            owners_by_arg_by_perm[perm.name][arg].append(group)

    # merge in plugin results
    for res in get_plugin_proxy().get_owner_by_arg_by_perm(session):
        for perm, owners_by_arg in res.items():
            for arg, owners in owners_by_arg.items():
                owners_by_arg_by_perm[perm][arg] += owners

    return owners_by_arg_by_perm
コード例 #15
0
ファイル: permissions.py プロジェクト: tecknicaltom/merou
def get_owners_by_grantable_permission(
        session: Session,
        separate_global: bool = False) -> Dict[object, Dict[str, List[Group]]]:
    """Returns all known permission arguments with owners.

    This consolidates permission grants supported by grouper itself as well as any grants governed
    by plugins.

    Args:
        session: Database session
        separate_global: Whether to construct a specific entry for GLOBAL_OWNER in the output map

    Returns:
        A map of permission to argument to owners of the form:
            {permission: {argument: [owner1, ...], }, }
        where owners are Group objects.  argument can be '*' which means anything.
    """
    all_permissions = {
        permission.name: permission
        for permission in get_all_permissions(session)
    }
    all_groups = session.query(Group).filter(Group.enabled == True).all()

    owners_by_arg_by_perm: Dict[object, Dict[str, List[Group]]] = defaultdict(
        lambda: defaultdict(list))

    all_group_permissions = (session.query(
        Permission.name, PermissionMap.argument, PermissionMap.granted_on,
        Group).filter(PermissionMap.group_id == Group.id,
                      Permission.id == PermissionMap.permission_id).all())

    grants_by_group: Dict[str, List[Any]] = defaultdict(list)

    for grant in all_group_permissions:
        grants_by_group[grant.Group.id].append(grant)

    for group in all_groups:
        # special case permission admins
        group_permissions = grants_by_group[group.id]
        if any([g.name == PERMISSION_ADMIN for g in group_permissions]):
            for perm_name in all_permissions:
                owners_by_arg_by_perm[perm_name]["*"].append(group)
            if separate_global:
                owners_by_arg_by_perm[GLOBAL_OWNERS]["*"].append(group)
            continue

        grants = [
            gp for gp in group_permissions if gp.name == PERMISSION_GRANT
        ]

        for perm, arg in filter_grantable_permissions(
                session, grants, all_permissions=all_permissions):
            owners_by_arg_by_perm[perm.name][arg].append(group)

    # merge in plugin results
    for res in get_plugin_proxy().get_owner_by_arg_by_perm(session):
        for permission_name, owners_by_arg in res.items():
            for arg, owners in owners_by_arg.items():
                owners_by_arg_by_perm[permission_name][arg] += owners

    return owners_by_arg_by_perm
コード例 #16
0
ファイル: permissions_test.py プロジェクト: yasaswyk/merou
def test_permission_grant_to_owners(
        session,
        standard_graph,
        groups,
        grantable_permissions,
        permissions  # noqa: F811
):
    """Test we're getting correct owners according to granted
    'grouper.permission.grant' permissions."""
    perm_grant, _, perm1, perm2 = grantable_permissions

    # Disable the group with permission admin since otherwise they're an approver on everything,
    # and check that there are then no approvers.
    groups["permission-admins"].disable()
    session.commit()
    assert not get_owners_by_grantable_permission(
        session), "nothing to begin with"

    # grant a grant on a non-existent permission
    grant_permission(groups["auditors"],
                     perm_grant,
                     argument="notgrantable.one")
    assert not get_owners_by_grantable_permission(
        session), "ignore grants for non-existent perms"

    # grant a wildcard grant -- make sure all permissions are represented and
    # the grant isn't inherited
    grant_permission(groups["all-teams"], perm_grant, argument="grantable.*")
    owners_by_arg_by_perm = get_owners_by_grantable_permission(session)
    expected = [groups["all-teams"]]
    assert owners_by_arg_by_perm[
        perm1.name]["*"] == expected, "grants are not inherited"
    assert len(owners_by_arg_by_perm) == 2
    assert len(owners_by_arg_by_perm[perm1.name]) == 1
    assert len(owners_by_arg_by_perm[perm2.name]) == 1

    # grant on argument substring
    grant_permission(groups["team-sre"],
                     perm_grant,
                     argument="{}/somesubstring*".format(perm1.name))
    owners_by_arg_by_perm = get_owners_by_grantable_permission(session)
    expected = [groups["all-teams"]]
    assert owners_by_arg_by_perm[perm1.name]["*"] == expected
    expected = [groups["team-sre"]]
    assert owners_by_arg_by_perm[perm1.name]["somesubstring*"] == expected

    # make sure get_owner() respect substrings
    res = [
        o.groupname for o, a in get_owner_arg_list(
            session,
            perm1,
            "somesubstring",
            owners_by_arg_by_perm=owners_by_arg_by_perm)
    ]
    assert sorted(res) == ["all-teams", "team-sre"
                           ], "should include substring wildcard matches"

    res = [
        o.groupname for o, a in get_owner_arg_list(
            session,
            perm1,
            "othersubstring",
            owners_by_arg_by_perm=owners_by_arg_by_perm)
    ]
    assert sorted(res) == ["all-teams"
                           ], "negative test of substring wildcard matches"

    class FakePermissionAliasesPlugin(BasePlugin):
        def get_aliases_for_mapped_permission(self, session, permission,
                                              argument):
            # type: (Session, str, str) -> List[Tuple[str, str]]
            if permission != "alias_perm" or argument != "team-sre":
                return []
            return [(PERMISSION_GRANT, "foo-perm/bar-arg")]

    owner_perm = create_permission(session, "alias_perm")
    session.commit()
    get_plugin_proxy().add_plugin(FakePermissionAliasesPlugin())
    grant_permission(groups["team-sre"], owner_perm, "team-sre")
    owners_by_arg_by_perm = get_owners_by_grantable_permission(session)
    expected = [groups["team-sre"]]
    assert owners_by_arg_by_perm["foo-perm"]["bar-arg"] == expected

    # permission admins have all the power
    grant_permission(groups["security-team"], permissions[PERMISSION_ADMIN])
    owners_by_arg_by_perm = get_owners_by_grantable_permission(session)
    all_permissions = get_all_permissions(session)
    for perm in all_permissions:
        assert perm.name in owners_by_arg_by_perm, "all permission should be represented"
        assert (groups["security-team"]
                in owners_by_arg_by_perm[perm.name]["*"]
                ), "permission admin should be wildcard owners"
コード例 #17
0
def persist_group_member_changes(
        session,  # type: Session
        group,  # type: Group
        requester,  # type: User
        member,  # type: Union[User, Group]
        status,  # type: str
        reason,  # type: str
        create_edge=False,  # type: bool
        **updates  # type: Any
):
    # type: (...) -> Request
    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
コード例 #18
0
ファイル: permissions_test.py プロジェクト: yasaswyk/merou
def test_permission_plugin(session, grantable_permissions, http_client,
                           base_url):  # noqa: F811
    get_plugin_proxy().add_plugin(PermissionValidationPlugin())
    groupname = "serving-team"
    username = "******"
    permission_name = "grantable.one"

    # Permission request checks
    # Rejected
    fe_url = url(base_url, f"/permissions/request?group={groupname}")
    resp = yield http_client.fetch(
        fe_url,
        method="POST",
        body=urlencode({
            "permission": permission_name,
            "argument": "quite-evil",
            "reason": "blah blah black sheep",
        }),
        headers={"X-Grouper-User": username},
    )
    assert resp.code == 200
    assert b"RFC 3514" in resp.body

    # Accepted
    resp = yield http_client.fetch(
        fe_url,
        method="POST",
        body=urlencode({
            "permission": permission_name,
            "argument": "not-bad",
            "reason": "blah blah black sheep",
        }),
        headers={"X-Grouper-User": username},
    )
    assert resp.code == 200
    assert b"RFC 3514" not in resp.body

    # Permission grant checks

    user_name = "*****@*****.**"
    # Rejected
    fe_url = url(base_url, f"/permissions/grant/{groupname}")
    resp = yield http_client.fetch(
        fe_url,
        method="POST",
        body=urlencode({
            "permission": permission_name,
            "argument": "dastardly-evil"
        }),
        headers={"X-Grouper-User": user_name},
    )
    assert resp.code == 200
    assert b"RFC 3514" in resp.body

    # Accepted
    fe_url = url(base_url, f"/permissions/grant/{groupname}")
    resp = yield http_client.fetch(
        fe_url,
        method="POST",
        body=urlencode({
            "permission": permission_name,
            "argument": "not-bad"
        }),
        headers={"X-Grouper-User": user_name},
    )
    assert resp.code == 200
    assert b"RFC 3514" not in resp.body
コード例 #19
0
ファイル: stats.py プロジェクト: santoshankr/grouper
def log_gauge(key, val):
    # type: (str, float) -> None
    get_plugin_proxy().log_gauge(key, val)
コード例 #20
0
ファイル: stats.py プロジェクト: brandon-rhodes/merou
def log_gauge(key, val):
    # type: (str, float) -> None
    get_plugin_proxy().log_gauge(key, val)