Skip to content

Commit

Permalink
IFC-29 Convert account node to use a generic (opsmill#3807)
Browse files Browse the repository at this point in the history
  • Loading branch information
gmazoyer authored Jul 26, 2024
1 parent bbdf03f commit d0dca10
Show file tree
Hide file tree
Showing 45 changed files with 445 additions and 558 deletions.
10 changes: 4 additions & 6 deletions backend/infrahub/api/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,7 @@ async def get_menu(branch: Branch = Depends(get_branch_dep)) -> list[InterfaceMe
log.info("menu_request", branch=branch.name)

full_schema = registry.schema.get_full(branch=branch, duplicate=False)
objects = InterfaceMenu(
title="Objects",
children=[],
)
objects = InterfaceMenu(title="Objects", children=[])

structure: dict[str, list[InterfaceMenu]] = {}

Expand Down Expand Up @@ -201,13 +198,14 @@ async def get_menu(branch: Branch = Depends(get_branch_dep)) -> list[InterfaceMe
),
],
)

admin = InterfaceMenu(
title="Admin",
children=[
InterfaceMenu(
title="Accounts",
path=f"/objects/{InfrahubKind.ACCOUNT}",
icon=_extract_node_icon(full_schema[InfrahubKind.ACCOUNT]),
path=f"/objects/{InfrahubKind.GENERICACCOUNT}",
icon=_extract_node_icon(full_schema[InfrahubKind.GENERICACCOUNT]),
),
InterfaceMenu(
title="Webhooks",
Expand Down
13 changes: 7 additions & 6 deletions backend/infrahub/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from infrahub.exceptions import AuthorizationError, NodeNotFoundError

if TYPE_CHECKING:
from infrahub.core.protocols import CoreAccount
from infrahub.core.protocols import CoreGenericAccount
from infrahub.database import InfrahubDatabase

# from ..datatypes import AuthResult
Expand Down Expand Up @@ -50,17 +50,19 @@ async def authenticate_with_password(
db: InfrahubDatabase, credentials: models.PasswordCredential, branch: Optional[str] = None
) -> models.UserToken:
selected_branch = await registry.get_branch(db=db, branch=branch)
response: list[CoreAccount] = await NodeManager.query(
schema=InfrahubKind.ACCOUNT,

response: list[CoreGenericAccount] = await NodeManager.query(
schema=InfrahubKind.GENERICACCOUNT,
db=db,
branch=selected_branch,
filters={"name__value": credentials.username},
limit=1,
)

if not response:
raise NodeNotFoundError(
branch_name=selected_branch.name,
node_type=InfrahubKind.ACCOUNT,
node_type=InfrahubKind.GENERICACCOUNT,
identifier=credentials.username,
message="That login user doesn't exist in the system",
)
Expand All @@ -72,7 +74,6 @@ async def authenticate_with_password(
raise AuthorizationError("Incorrect password")

now = datetime.now(tz=timezone.utc)

refresh_expires = now + timedelta(seconds=config.SETTINGS.security.refresh_token_lifetime)
session_id = await create_db_refresh_token(db=db, account_id=account.id, expiration=refresh_expires)
access_token = generate_access_token(account_id=account.id, role=account.role.value.value, session_id=session_id)
Expand All @@ -97,7 +98,7 @@ async def create_fresh_access_token(
if not refresh_token:
raise AuthorizationError("The provided refresh token has been invalidated in the database")

account: Optional[CoreAccount] = await NodeManager.get_one(id=refresh_data.account_id, db=db)
account: Optional[CoreGenericAccount] = await NodeManager.get_one(id=refresh_data.account_id, db=db)
if not account:
raise NodeNotFoundError(
branch_name=selected_branch.name,
Expand Down
5 changes: 3 additions & 2 deletions backend/infrahub/core/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ async def query_init(self, db: InfrahubDatabase, **kwargs: Any) -> None:

self.params["token_value"] = self.token

# ruff: noqa: E501
query = """
MATCH (at:InternalAccountToken)-[r1:HAS_ATTRIBUTE]-(a:Attribute {name: "token"})-[r2:HAS_VALUE]-(av:AttributeValue { value: $token_value })
WHERE %s
WITH at
MATCH (at)-[r31]-(:Relationship)-[r41]-(acc:CoreAccount)-[r5:HAS_ATTRIBUTE]-(an:Attribute {name: "name"})-[r6:HAS_VALUE]-(av:AttributeValue)
MATCH (at)-[r32]-(:Relationship)-[r42]-(acc:CoreAccount)-[r7:HAS_ATTRIBUTE]-(ar:Attribute {name: "role"})-[r8:HAS_VALUE]-(avr:AttributeValue)
MATCH (at)-[r31]-(:Relationship)-[r41]-(acc:CoreGenericAccount)-[r5:HAS_ATTRIBUTE]-(an:Attribute {name: "name"})-[r6:HAS_VALUE]-(av:AttributeValue)
MATCH (at)-[r32]-(:Relationship)-[r42]-(acc:CoreGenericAccount)-[r7:HAS_ATTRIBUTE]-(ar:Attribute {name: "role"})-[r8:HAS_VALUE]-(avr:AttributeValue)
WHERE %s
""" % (
"\n AND ".join(token_filter_perms),
Expand Down
1 change: 1 addition & 0 deletions backend/infrahub/core/constants/infrahubkind.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
DATAVALIDATOR = "CoreDataValidator"
FILECHECK = "CoreFileCheck"
FILETHREAD = "CoreFileThread"
GENERICACCOUNT = "CoreGenericAccount"
GENERATORCHECK = "CoreGeneratorCheck"
GENERATORDEFINITION = "CoreGeneratorDefinition"
GENERATORINSTANCE = "CoreGeneratorInstance"
Expand Down
14 changes: 2 additions & 12 deletions backend/infrahub/core/initialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,23 +234,13 @@ async def create_account(
) -> Node:
token_schema = db.schema.get_node_schema(name=InfrahubKind.ACCOUNTTOKEN)
obj = await Node.init(db=db, schema=InfrahubKind.ACCOUNT)
await obj.new(
db=db,
name=name,
type="User",
role=role,
password=password,
)
await obj.new(db=db, name=name, account_type="User", role=role, password=password)
await obj.save(db=db)
log.info(f"Created Account: {name}", account_name=name)

if token_value:
token = await Node.init(db=db, schema=token_schema)
await token.new(
db=db,
token=token_value,
account=obj,
)
await token.new(db=db, token=token_value, account=obj)
await token.save(db=db)

return obj
Expand Down
20 changes: 12 additions & 8 deletions backend/infrahub/core/protocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ class CoreComment(CoreNode):
created_by: RelationshipManager


class CoreGenericAccount(CoreNode):
name: String
password: HashedPassword
label: StringOptional
description: StringOptional
account_type: Enum
role: Enum
tokens: RelationshipManager


class CoreGenericRepository(CoreNode):
name: String
description: StringOptional
Expand Down Expand Up @@ -171,14 +181,8 @@ class BuiltinTag(CoreNode):
description: StringOptional


class CoreAccount(LineageOwner, LineageSource):
name: String
password: HashedPassword
label: StringOptional
description: StringOptional
type: Enum
role: Enum
tokens: RelationshipManager
class CoreAccount(LineageOwner, LineageSource, CoreGenericAccount):
pass


class CoreArtifact(CoreTaskTarget):
Expand Down
6 changes: 4 additions & 2 deletions backend/infrahub/core/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,11 @@ def get_data_type(self, name: str) -> type[InfrahubDataType]:
raise DataTypeNotFoundError(name=name)
return self.data_type[name]

def get_full_schema(self, branch: Optional[Union[Branch, str]] = None) -> dict[str, MainSchemaTypes]:
def get_full_schema(
self, branch: Optional[Union[Branch, str]] = None, duplicate: bool = True
) -> dict[str, MainSchemaTypes]:
"""Return all the nodes in the schema for a given branch."""
return self.schema.get_full(branch=branch)
return self.schema.get_full(branch=branch, duplicate=duplicate)

def delete_all(self) -> None:
self.branch = {}
Expand Down
73 changes: 43 additions & 30 deletions backend/infrahub/core/schema/definitions/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
"relationships": [
{
"name": "created_by",
"peer": InfrahubKind.ACCOUNT,
"peer": InfrahubKind.GENERICACCOUNT,
"optional": True,
"branch": BranchSupportType.AGNOSTIC.value,
"cardinality": "one",
Expand Down Expand Up @@ -131,7 +131,7 @@
},
{
"name": "created_by",
"peer": InfrahubKind.ACCOUNT,
"peer": InfrahubKind.GENERICACCOUNT,
"optional": True,
"branch": BranchSupportType.AGNOSTIC.value,
"cardinality": "one",
Expand Down Expand Up @@ -703,6 +703,41 @@
},
],
},
{
"name": "GenericAccount",
"namespace": "Core",
"description": "User Account for Infrahub",
"include_in_menu": False,
"label": "Account",
"icon": "mdi:account",
"default_filter": "name__value",
"order_by": ["name__value"],
"display_labels": ["label__value"],
"human_friendly_id": ["name__value"],
"branch": BranchSupportType.AGNOSTIC.value,
"documentation": "/topics/auth",
"attributes": [
{"name": "name", "kind": "Text", "unique": True},
{"name": "password", "kind": "HashedPassword", "unique": False},
{"name": "label", "kind": "Text", "optional": True},
{"name": "description", "kind": "Text", "optional": True},
{
"name": "account_type",
"kind": "Text",
"default_value": AccountType.USER.value,
"enum": AccountType.available_types(),
},
{
"name": "role",
"kind": "Text",
"default_value": AccountRole.READ_ONLY.value,
"enum": AccountRole.available_types(),
},
],
"relationships": [
{"name": "tokens", "peer": InfrahubKind.ACCOUNTTOKEN, "optional": True, "cardinality": "many"},
],
},
],
"nodes": [
{
Expand Down Expand Up @@ -787,29 +822,7 @@
"display_labels": ["label__value"],
"generate_profile": False,
"branch": BranchSupportType.AGNOSTIC.value,
"inherit_from": [InfrahubKind.LINEAGEOWNER, InfrahubKind.LINEAGESOURCE],
"documentation": "/topics/auth",
"attributes": [
{"name": "name", "kind": "Text", "unique": True},
{"name": "password", "kind": "HashedPassword", "unique": False},
{"name": "label", "kind": "Text", "optional": True},
{"name": "description", "kind": "Text", "optional": True},
{
"name": "type",
"kind": "Text",
"default_value": AccountType.USER.value,
"enum": AccountType.available_types(),
},
{
"name": "role",
"kind": "Text",
"default_value": AccountRole.READ_ONLY.value,
"enum": AccountRole.available_types(),
},
],
"relationships": [
{"name": "tokens", "peer": InfrahubKind.ACCOUNTTOKEN, "optional": True, "cardinality": "many"},
],
"inherit_from": [InfrahubKind.LINEAGEOWNER, InfrahubKind.LINEAGESOURCE, InfrahubKind.GENERICACCOUNT],
},
{
"name": "AccountToken",
Expand All @@ -830,7 +843,7 @@
"relationships": [
{
"name": "account",
"peer": InfrahubKind.ACCOUNT,
"peer": InfrahubKind.GENERICACCOUNT,
"optional": False,
"cardinality": "one",
},
Expand All @@ -851,7 +864,7 @@
"relationships": [
{
"name": "account",
"peer": InfrahubKind.ACCOUNT,
"peer": InfrahubKind.GENERICACCOUNT,
"optional": False,
"cardinality": "one",
},
Expand Down Expand Up @@ -886,7 +899,7 @@
"relationships": [
{
"name": "approved_by",
"peer": InfrahubKind.ACCOUNT,
"peer": InfrahubKind.GENERICACCOUNT,
"optional": True,
"cardinality": "many",
"kind": "Attribute",
Expand All @@ -895,7 +908,7 @@
},
{
"name": "reviewers",
"peer": InfrahubKind.ACCOUNT,
"peer": InfrahubKind.GENERICACCOUNT,
"optional": True,
"kind": "Attribute",
"cardinality": "many",
Expand All @@ -904,7 +917,7 @@
},
{
"name": "created_by",
"peer": InfrahubKind.ACCOUNT,
"peer": InfrahubKind.GENERICACCOUNT,
"optional": True,
"cardinality": "one",
"branch": BranchSupportType.AGNOSTIC.value,
Expand Down
8 changes: 4 additions & 4 deletions backend/infrahub/core/task/user_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

from structlog.stdlib import BoundLogger

from infrahub.core.protocols import CoreAccount
from infrahub.core.protocols import CoreGenericAccount
from infrahub.database import InfrahubDatabase
from infrahub.graphql import GraphqlContext
from infrahub.services.protocols import InfrahubLogger
Expand All @@ -27,7 +27,7 @@ def __init__(
self,
title: str,
db: InfrahubDatabase,
account: Optional[CoreAccount] = None,
account: Optional[CoreGenericAccount] = None,
account_id: Optional[str] = None,
logger: Optional[Union[BoundLogger, InfrahubLogger]] = None,
) -> None:
Expand All @@ -52,7 +52,7 @@ def task(self) -> Task:
raise ValueError("Task hasn't been initialized")

@property
def account(self) -> CoreAccount:
def account(self) -> CoreGenericAccount:
if self._account:
return self._account
raise ValueError("Account hasn't been initialized")
Expand All @@ -67,7 +67,7 @@ async def fetch_account(self) -> bool:
if self._account:
return False

account: Optional[CoreAccount] = await registry.manager.get_one(id=self.account_id, db=self.db)
account: Optional[CoreGenericAccount] = await registry.manager.get_one(id=self.account_id, db=self.db)
if not account:
raise ValueError(f"Unable to find the account associated with {self.account_id}")
self._account = account
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@


class ReadOnlyGraphQLPermissionChecker(GraphQLQueryPermissionCheckerInterface):
allowed_readonly_mutations = ["CoreAccountSelfUpdate"]
allowed_readonly_mutations = ["InfrahubAccountSelfUpdate"]

async def supports(self, account_session: AccountSession) -> bool:
return account_session.authenticated and account_session.read_only
Expand Down
9 changes: 3 additions & 6 deletions backend/infrahub/graphql/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,12 +387,9 @@ def generate_query_mixin(self) -> type[object]:
resolver=default_paginated_list_resolver,
**node_filters,
)
if node_name == InfrahubKind.ACCOUNT:
node_type = self.get_type(name=InfrahubKind.ACCOUNT)
class_attrs["AccountProfile"] = graphene.Field(
node_type,
resolver=account_resolver,
)
if node_name == InfrahubKind.GENERICACCOUNT:
node_type = self.get_type(name=InfrahubKind.GENERICACCOUNT)
class_attrs["AccountProfile"] = graphene.Field(node_type, resolver=account_resolver)

return type("QueryMixin", (object,), class_attrs)

Expand Down
8 changes: 4 additions & 4 deletions backend/infrahub/graphql/mutations/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .account import CoreAccountSelfUpdate, CoreAccountTokenCreate, CoreAccountTokenDelete
from .account import InfrahubAccountSelfUpdate, InfrahubAccountTokenCreate, InfrahubAccountTokenDelete
from .artifact_definition import InfrahubArtifactDefinitionMutation
from .attribute import (
AnyAttributeCreate,
Expand Down Expand Up @@ -55,9 +55,9 @@
"BranchUpdate",
"CheckboxAttributeCreate",
"CheckboxAttributeUpdate",
"CoreAccountSelfUpdate",
"CoreAccountTokenCreate",
"CoreAccountTokenDelete",
"InfrahubAccountSelfUpdate",
"InfrahubAccountTokenCreate",
"InfrahubAccountTokenDelete",
"IPPrefixPoolGetResource",
"IPAddressPoolGetResource",
"InfrahubArtifactDefinitionMutation",
Expand Down
Loading

0 comments on commit d0dca10

Please sign in to comment.