Esempio n. 1
0
    def __init__(self, tmpdir):
        # type: (LocalPath) -> None
        self.settings = Settings()
        self.settings.database = db_url(tmpdir)
        self.plugins = PluginProxy([])

        # Reinitialize the global plugin proxy with an empty set of plugins in case a previous test
        # initialized plugins.  This can go away once a plugin proxy is injected into everything
        # that needs it instead of maintained as a global.
        set_global_plugin_proxy(self.plugins)

        self.initialize_database()
        self.session = SessionFactory(self.settings).create_session()
        self.graph = GroupGraph()
        session_factory = SingletonSessionFactory(self.session)
        self.repository_factory = GraphRepositoryFactory(
            self.settings, self.plugins, session_factory, self.graph)
        self.sql_repository_factory = SQLRepositoryFactory(
            self.settings, self.plugins, session_factory)
        self.service_factory = ServiceFactory(self.settings, self.plugins,
                                              self.repository_factory)
        self.usecase_factory = UseCaseFactory(self.settings, self.plugins,
                                              self.service_factory)
        self._transaction_service = self.service_factory.create_transaction_service(
        )
Esempio n. 2
0
 def open_database(self) -> None:
     self.session = SessionFactory(self.settings).create_session()
     session_factory = SingletonSessionFactory(self.session)
     self.repository_factory = GraphRepositoryFactory(
         self.settings, self.plugins, session_factory, self.graph)
     self.sql_repository_factory = SQLRepositoryFactory(
         self.settings, self.plugins, session_factory)
     self.service_factory = ServiceFactory(self.settings, self.plugins,
                                           self.repository_factory)
     self.usecase_factory = UseCaseFactory(self.settings, self.plugins,
                                           self.service_factory)
     self._transaction_service = self.service_factory.create_transaction_service(
     )
Esempio n. 3
0
def create_graph_usecase_factory(settings, session=None, graph=None):
    # type: (Settings, Optional[Session], Optional[GroupGraph]) -> UseCaseFactory
    """Create a graph-backed UseCaseFactory, with optional injection of a Session and GroupGraph.

    Session and graph injection is supported primarily for tests.  If not injected, they will be
    created on demand.
    """
    repository_factory = GraphRepositoryFactory(settings, session, graph)
    service_factory = ServiceFactory(repository_factory)
    return UseCaseFactory(service_factory)
Esempio n. 4
0
 def __init__(self, tmpdir):
     # type: (LocalPath) -> None
     self.session = self.create_session(tmpdir)
     self.graph = GroupGraph()
     self.settings = Settings({"database": db_url(tmpdir)})
     self.repository_factory = GraphRepositoryFactory(
         self.settings, self.session, self.graph)
     self.service_factory = ServiceFactory(self.repository_factory)
     self.usecase_factory = UseCaseFactory(self.service_factory)
     self._transaction_service = self.service_factory.create_transaction_service(
     )
Esempio n. 5
0
def create_graph_usecase_factory(
    settings,  # type: Settings
    plugins,  # type: PluginProxy
    session_factory=None,  # type: Optional[SessionFactory]
    graph=None,  # type: Optional[GroupGraph]
):
    # type: (...) -> UseCaseFactory
    """Create a graph-backed UseCaseFactory, with optional injection of a Session and GroupGraph.

    Session factory and graph injection is supported primarily for tests.  If not injected, they
    will be created on demand.
    """
    if not session_factory:
        session_factory = SessionFactory(settings)
    repository_factory = GraphRepositoryFactory(settings, plugins, session_factory, graph)
    service_factory = ServiceFactory(settings, plugins, repository_factory)
    return UseCaseFactory(settings, plugins, service_factory)
Esempio n. 6
0
    def __init__(self, tmpdir):
        # type: (LocalPath) -> None
        self.settings = Settings()
        self.settings.database = db_url(tmpdir)
        self.plugin_proxy = PluginProxy([])

        # Reinitialize the global plugin proxy with an empty set of plugins in case a previous test
        # initialized plugins.  This can go away once a plugin proxy is injected into everything
        # that needs it instead of maintained as a global.
        set_global_plugin_proxy(self.plugin_proxy)

        self.initialize_database()
        self.session = SessionFactory(self.settings).create_session()
        self.graph = GroupGraph()
        self.repository_factory = GraphRepositoryFactory(
            self.settings, self.plugin_proxy, SingletonSessionFactory(self.session), self.graph
        )
        self.service_factory = ServiceFactory(self.repository_factory)
        self.usecase_factory = UseCaseFactory(self.settings, self.service_factory)
        self._transaction_service = self.service_factory.create_transaction_service()
Esempio n. 7
0
class SetupTest(object):
    """Set up the environment for a test.

    Most actions should be done inside of a transaction, created via the transaction() method and
    used as a context handler.  This will ensure that the test setup is committed to the database
    before the test starts running.

    Attributes:
        settings: Settings object for tests (only the database is configured)
        graph: Underlying graph (not refreshed from the database automatically!)
        session: The underlying database session
        plugin_proxy: The plugin proxy used for the tests
        repository_factory: Factory for repository objects
        service_factory: Factory for service objects
        usecase_factory: Factory for usecase objects
    """

    def __init__(self, tmpdir):
        # type: (LocalPath) -> None
        self.settings = Settings()
        self.settings.database = db_url(tmpdir)
        self.plugin_proxy = PluginProxy([])

        # Reinitialize the global plugin proxy with an empty set of plugins in case a previous test
        # initialized plugins.  This can go away once a plugin proxy is injected into everything
        # that needs it instead of maintained as a global.
        set_global_plugin_proxy(self.plugin_proxy)

        self.initialize_database()
        self.session = SessionFactory(self.settings).create_session()
        self.graph = GroupGraph()
        self.repository_factory = GraphRepositoryFactory(
            self.settings, self.plugin_proxy, SingletonSessionFactory(self.session), self.graph
        )
        self.service_factory = ServiceFactory(self.repository_factory)
        self.usecase_factory = UseCaseFactory(self.settings, self.service_factory)
        self._transaction_service = self.service_factory.create_transaction_service()

    def initialize_database(self):
        # type: () -> Session
        schema_repository = SchemaRepository(self.settings)

        # If using a persistent database, clear the database first.
        if "MEROU_TEST_DATABASE" in os.environ:
            schema_repository.drop_schema()

        # Create the database schema.
        schema_repository.initialize_schema()

    def close(self):
        # type: () -> None
        self.session.close()

    @contextmanager
    def transaction(self):
        # type: () -> Iterator[None]
        with self._transaction_service.transaction():
            yield
        self.graph.update_from_db(self.session)

    def create_group(self, name, description="", join_policy=GroupJoinPolicy.CAN_ASK):
        # type: (str, str, GroupJoinPolicy) -> None
        """Create a group, does nothing if it already exists."""
        group_service = self.service_factory.create_group_service()
        if not group_service.group_exists(name):
            group_service.create_group(name, description, join_policy)

    def create_permission(
        self, name, description="", audited=False, enabled=True, created_on=None
    ):
        # type: (str, str, bool, bool, Optional[datetime]) -> None
        """Create a permission, does nothing if it already exists."""
        permission_repository = self.repository_factory.create_permission_repository()
        if not permission_repository.get_permission(name):
            permission_repository.create_permission(
                name, description, audited, enabled, created_on
            )

    def create_user(self, name):
        # type: (str) -> None
        """Create a user, does nothing if it already exists."""
        if User.get(self.session, name=name):
            return
        user = User(username=name)
        user.add(self.session)

    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)

    def add_user_to_group(self, user, group, role="member", expiration=None):
        # type: (str, str, str, Optional[datetime]) -> None
        self.create_user(user)
        self.create_group(group)
        user_obj = User.get(self.session, name=user)
        assert user_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        edge = GroupEdge(
            group_id=group_obj.id,
            member_type=OBJ_TYPES["User"],
            member_pk=user_obj.id,
            expiration=expiration,
            active=True,
            _role=GROUP_EDGE_ROLES.index(role),
        )
        edge.add(self.session)

    def grant_permission_to_group(self, permission, argument, group):
        # type: (str, str, str) -> None
        self.create_group(group)
        self.create_permission(permission)
        group_service = self.service_factory.create_group_service()
        group_service.grant_permission_to_group(permission, argument, group)

    def revoke_permission_from_group(self, permission, argument, group):
        # type: (str, str, str) -> None
        permission_obj = Permission.get(self.session, name=permission)
        assert permission_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        self.session.query(PermissionMap).filter(
            PermissionMap.permission_id == permission_obj.id,
            PermissionMap.group_id == group_obj.id,
            PermissionMap.argument == argument,
        ).delete()

    def create_group_request(self, user, group, role="member"):
        # type: (str, str, str) -> None
        self.create_user(user)
        self.create_group(group)

        user_obj = User.get(self.session, name=user)
        assert user_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj

        # Note: despite the function name, this only creates the request. The flow here is
        # convoluted enough that it seems best to preserve exact behavior for testing.
        group_obj.add_member(
            requester=user_obj, user_or_group=user_obj, reason="", status="pending", role=role
        )

    def create_service_account(self, service_account, owner, description="", machine_set=""):
        # type: (str, str, str, str) -> None
        self.create_group(owner)
        group_obj = Group.get(self.session, name=owner)
        assert group_obj

        if User.get(self.session, name=service_account):
            return
        user = User(username=service_account)
        user.add(self.session)
        service_account_obj = ServiceAccount(
            user_id=user.id, description=description, machine_set=machine_set
        )
        service_account_obj.add(self.session)
        user.is_service_account = True

        self.session.flush()
        owner_map = GroupServiceAccount(
            group_id=group_obj.id, service_account_id=service_account_obj.id
        )
        owner_map.add(self.session)

    def grant_permission_to_service_account(self, permission, argument, service_account):
        # type: (str, str, str) -> None
        self.create_permission(permission)
        permission_obj = Permission.get(self.session, name=permission)
        assert permission_obj
        user_obj = User.get(self.session, name=service_account)
        assert user_obj, "Must create the service account first"
        assert user_obj.is_service_account
        grant = ServiceAccountPermissionMap(
            permission_id=permission_obj.id,
            service_account_id=user_obj.service_account.id,
            argument=argument,
        )
        grant.add(self.session)

    def disable_user(self, user):
        # type: (str) -> None
        user_repository = self.repository_factory.create_user_repository()
        user_repository.disable_user(user)

    def disable_group(self, group):
        # type: (str) -> None
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        group_obj.enabled = False

    def disable_service_account(self, service_account):
        # type: (str) -> None
        service_obj = ServiceAccount.get(self.session, name=service_account)
        assert service_obj
        service_obj.user.enabled = False
        service_obj.owner.delete(self.session)
        permissions = self.session.query(ServiceAccountPermissionMap).filter_by(
            service_account_id=service_obj.id
        )
        for permission in permissions:
            permission.delete(self.session)

    def create_role_user(self, role_user, description="", join_policy=GroupJoinPolicy.CAN_ASK):
        # type: (str, str, GroupJoinPolicy) -> None
        """Create an old-style role user.

        This concept is obsolete and all code related to it will be deleted once all remaining
        legacy role users have been converted to service accounts.  This method should be used only
        for tests to maintain backward compatibility until that happens.
        """
        user = User(username=role_user, role_user=True)
        user.add(self.session)
        self.create_group(role_user, description, join_policy)
        self.add_user_to_group(role_user, role_user)
Esempio n. 8
0
class SetupTest(object):
    """Set up the environment for a test.

    Most actions should be done inside of a transaction, created via the transaction() method and
    used as a context handler.  This will ensure that the test setup is committed to the database
    before the test starts running.

    Attributes:
        settings: Settings object for tests (only the database is configured)
        graph: Underlying graph (not refreshed from the database automatically!)
        session: The underlying database session
        plugins: The plugin proxy used for the tests
        repository_factory: Factory for repository objects
        sql_repository_factory: Factory that returns only SQL repository objects (no graph)
        service_factory: Factory for service objects
        usecase_factory: Factory for usecase objects
    """
    def __init__(self, tmpdir):
        # type: (LocalPath) -> None
        self.settings = Settings()
        self.settings.database = db_url(tmpdir)
        self.plugins = PluginProxy([])

        # Reinitialize the global plugin proxy with an empty set of plugins in case a previous test
        # initialized plugins.  This can go away once a plugin proxy is injected into everything
        # that needs it instead of maintained as a global.
        set_global_plugin_proxy(self.plugins)

        self.initialize_database()
        self.session = SessionFactory(self.settings).create_session()
        self.graph = GroupGraph()
        session_factory = SingletonSessionFactory(self.session)
        self.repository_factory = GraphRepositoryFactory(
            self.settings, self.plugins, session_factory, self.graph)
        self.sql_repository_factory = SQLRepositoryFactory(
            self.settings, self.plugins, session_factory)
        self.service_factory = ServiceFactory(self.settings, self.plugins,
                                              self.repository_factory)
        self.usecase_factory = UseCaseFactory(self.settings, self.plugins,
                                              self.service_factory)
        self._transaction_service = self.service_factory.create_transaction_service(
        )

    def initialize_database(self):
        # type: () -> Session
        schema_repository = SchemaRepository(self.settings)

        # If using a persistent database, clear the database first.
        if "MEROU_TEST_DATABASE" in os.environ:
            schema_repository.drop_schema()

        # Create the database schema.
        schema_repository.initialize_schema()

    def close(self):
        # type: () -> None
        self.session.close()

    @contextmanager
    def transaction(self):
        # type: () -> Iterator[None]
        with self._transaction_service.transaction():
            yield
        self.graph.update_from_db(self.session)

    def create_group(self,
                     name,
                     description="",
                     join_policy=GroupJoinPolicy.CAN_ASK):
        # type: (str, str, GroupJoinPolicy) -> None
        """Create a group, does nothing if it already exists."""
        group_service = self.service_factory.create_group_service()
        if not group_service.group_exists(name):
            group_service.create_group(name, description, join_policy)

    def create_permission(self,
                          name,
                          description="",
                          audited=False,
                          enabled=True,
                          created_on=None):
        # type: (str, str, bool, bool, Optional[datetime]) -> None
        """Create a permission, does nothing if it already exists."""
        permission_repository = self.repository_factory.create_permission_repository(
        )
        if not permission_repository.get_permission(name):
            permission_repository.create_permission(name, description, audited,
                                                    enabled, created_on)

    def create_user(self, name):
        # type: (str) -> None
        """Create a user, does nothing if it already exists."""
        if User.get(self.session, name=name):
            return
        user = User(username=name)
        user.add(self.session)

    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)

    def add_user_to_group(self, user, group, role="member", expiration=None):
        # type: (str, str, str, Optional[datetime]) -> None
        self.create_user(user)
        self.create_group(group)
        user_obj = User.get(self.session, name=user)
        assert user_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        edge = GroupEdge(
            group_id=group_obj.id,
            member_type=OBJ_TYPES["User"],
            member_pk=user_obj.id,
            expiration=expiration,
            active=True,
            _role=GROUP_EDGE_ROLES.index(role),
        )
        edge.add(self.session)

    def grant_permission_to_group(self, permission, argument, group):
        # type: (str, str, str) -> None
        self.create_group(group)
        self.create_permission(permission)
        group_service = self.service_factory.create_group_service()
        group_service.grant_permission_to_group(permission, argument, group)

    def revoke_permission_from_group(self, permission, argument, group):
        # type: (str, str, str) -> None
        permission_obj = Permission.get(self.session, name=permission)
        assert permission_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        self.session.query(PermissionMap).filter(
            PermissionMap.permission_id == permission_obj.id,
            PermissionMap.group_id == group_obj.id,
            PermissionMap.argument == argument,
        ).delete()

    def create_group_request(self, user, group, role="member"):
        # type: (str, str, str) -> None
        self.create_user(user)
        self.create_group(group)

        user_obj = User.get(self.session, name=user)
        assert user_obj
        group_obj = Group.get(self.session, name=group)
        assert group_obj

        # Note: despite the function name, this only creates the request. The flow here is
        # convoluted enough that it seems best to preserve exact behavior for testing.
        group_obj.add_member(requester=user_obj,
                             user_or_group=user_obj,
                             reason="",
                             status="pending",
                             role=role)

    def create_service_account(self,
                               service_account,
                               owner,
                               machine_set="",
                               description=""):
        # type: (str, str, str, str) -> None
        self.create_group(owner)
        service_account_repository = self.repository_factory.create_service_account_repository(
        )
        service_account_repository.create_service_account(
            service_account, owner, machine_set, description)

    def grant_permission_to_service_account(self, permission, argument,
                                            service_account):
        # type: (str, str, str) -> None
        self.create_permission(permission)
        permission_obj = Permission.get(self.session, name=permission)
        assert permission_obj
        user_obj = User.get(self.session, name=service_account)
        assert user_obj, "Must create the service account first"
        assert user_obj.is_service_account
        grant = ServiceAccountPermissionMap(
            permission_id=permission_obj.id,
            service_account_id=user_obj.service_account.id,
            argument=argument,
        )
        grant.add(self.session)

    def add_metadata_to_user(self, key, value, user):
        # type: (str, str, str) -> None
        sql_user = User.get(self.session, name=user)
        assert sql_user
        metadata = UserMetadata(user_id=sql_user.id,
                                data_key=key,
                                data_value=value)
        metadata.add(self.session)

    def add_public_key_to_user(self, key, user):
        # type: (str, str) -> None
        sql_user = User.get(self.session, name=user)
        assert sql_user
        public_key = SSHKey(key, strict=True)
        public_key.parse()
        sql_public_key = PublicKey(
            user_id=sql_user.id,
            public_key=public_key.keydata.strip(),
            fingerprint=public_key.hash_md5().replace("MD5:", ""),
            fingerprint_sha256=public_key.hash_sha256().replace("SHA256:", ""),
            key_size=public_key.bits,
            key_type=public_key.key_type,
            comment=public_key.comment,
        )
        sql_public_key.add(self.session)

    def disable_user(self, user):
        # type: (str) -> None
        user_repository = self.repository_factory.create_user_repository()
        user_repository.disable_user(user)

    def disable_group(self, group):
        # type: (str) -> None
        group_obj = Group.get(self.session, name=group)
        assert group_obj
        group_obj.enabled = False

    def disable_service_account(self, service_account):
        # type: (str) -> None
        service_obj = ServiceAccount.get(self.session, name=service_account)
        assert service_obj
        service_obj.user.enabled = False
        service_obj.owner.delete(self.session)
        permissions = self.session.query(
            ServiceAccountPermissionMap).filter_by(
                service_account_id=service_obj.id)
        for permission in permissions:
            permission.delete(self.session)

    def create_role_user(self,
                         role_user,
                         description="",
                         join_policy=GroupJoinPolicy.CAN_ASK):
        # type: (str, str, GroupJoinPolicy) -> None
        """Create an old-style role user.

        This concept is obsolete and all code related to it will be deleted once all remaining
        legacy role users have been converted to service accounts.  This method should be used only
        for tests to maintain backward compatibility until that happens.
        """
        user = User(username=role_user, role_user=True)
        user.add(self.session)
        self.create_group(role_user, description, join_policy)
        self.add_user_to_group(role_user, role_user)