diff --git a/docs/decisions/20240103-use-jwt-claims-for-agent-admin-auth.md b/docs/decisions/20240103-use-jwt-claims-for-agent-admin-auth.md index ec8ba72e1d..bcca30b666 100644 --- a/docs/decisions/20240103-use-jwt-claims-for-agent-admin-auth.md +++ b/docs/decisions/20240103-use-jwt-claims-for-agent-admin-auth.md @@ -75,7 +75,7 @@ Example JWT payload containing `ClientRole`. (Some claims are omitted for readab "resource_access": { "prism-agent": { "roles": [ - "agent-admin" + "admin" ] }, "account": { @@ -107,9 +107,9 @@ __Proposed agent role authorization model__ Role is a plain text that defines what level of access a user has on a system. For the agent, it needs to support 2 roles: -1. __Admin__: `agent-admin`. Admin can never access a tenant wallet. +1. __Admin__: `admin`. Admin can never access a tenant wallet. Agent auth layer must ignore any UMA permission to the wallet. -2. __Tenant__: `agent-tenant` or implicitly inferred if another role is not specified. +2. __Tenant__: `tenant` or implicitly inferred if another role is not specified. Tenant must have UMA permission defined to access the wallet. ### Positive Consequences diff --git a/prism-agent/service/server/src/main/resources/application.conf b/prism-agent/service/server/src/main/resources/application.conf index 0b890ea3ae..d9904d7b6d 100644 --- a/prism-agent/service/server/src/main/resources/application.conf +++ b/prism-agent/service/server/src/main/resources/application.conf @@ -136,7 +136,7 @@ agent { autoUpgradeToRPT = ${?KEYCLOAK_UMA_AUTO_UPGRADE_RPT} # A path of 'roles' claim in the JWT. Nested path maybe indicated by '.' separator. - # The JWT 'roles' claim is expected to be a list of the following values: [agent-admin, agent-tenant] + # The JWT 'roles' claim is expected to be a list of the following values: [admin, tenant] rolesClaimPath = "resource_access."${agent.authentication.keycloak.clientId}".roles" rolesClaimPath = ${?KEYKLOAK_ROLES_CLAIM_PATH} } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/Authenticator.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/Authenticator.scala index c51fc09469..1dd496708f 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/Authenticator.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/Authenticator.scala @@ -48,7 +48,7 @@ trait Authenticator[E <: BaseEntity] { } trait Authorizer[E <: BaseEntity] { - protected def authorizeWalletAccessImpl(entity: E): IO[AuthenticationError, WalletAccessContext] + protected def authorizeWalletAccessLogic(entity: E): IO[AuthenticationError, WalletAccessContext] final def authorizeWalletAccess(entity: E): IO[AuthenticationError, WalletAccessContext] = ZIO @@ -59,7 +59,7 @@ trait Authorizer[E <: BaseEntity] { .filterOrFail(_ != EntityRole.Admin)( AuthenticationError.InvalidRole("Admin role is not allowed to access the tenant's wallet.") ) - .flatMap(_ => authorizeWalletAccessImpl(entity)) + .flatMap(_ => authorizeWalletAccessLogic(entity)) def authorizeWalletAdmin(entity: E): IO[AuthenticationError, WalletAdministrationContext] } @@ -67,7 +67,7 @@ trait Authorizer[E <: BaseEntity] { object EntityAuthorizer extends EntityAuthorizer trait EntityAuthorizer extends Authorizer[Entity] { - override def authorizeWalletAccessImpl(entity: Entity): IO[AuthenticationError, WalletAccessContext] = + override def authorizeWalletAccessLogic(entity: Entity): IO[AuthenticationError, WalletAccessContext] = ZIO.succeed(entity.walletId).map(WalletId.fromUUID).map(WalletAccessContext.apply) override def authorizeWalletAdmin(entity: Entity): IO[AuthenticationError, WalletAdministrationContext] = { @@ -84,8 +84,8 @@ object DefaultEntityAuthenticator extends AuthenticatorWithAuthZ[BaseEntity] { override def isEnabled: Boolean = true override def authenticate(credentials: Credentials): IO[AuthenticationError, BaseEntity] = ZIO.succeed(Entity.Default) - override def authorizeWalletAccessImpl(entity: BaseEntity): IO[AuthenticationError, WalletAccessContext] = - EntityAuthorizer.authorizeWalletAccessImpl(Entity.Default) + override def authorizeWalletAccessLogic(entity: BaseEntity): IO[AuthenticationError, WalletAccessContext] = + EntityAuthorizer.authorizeWalletAccessLogic(Entity.Default) override def authorizeWalletAdmin(entity: BaseEntity): IO[AuthenticationError, WalletAdministrationContext] = EntityAuthorizer.authorizeWalletAdmin(Entity.Default) diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/DefaultAuthenticator.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/DefaultAuthenticator.scala index c8f8aab4f3..a47b510c1c 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/DefaultAuthenticator.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/DefaultAuthenticator.scala @@ -24,7 +24,7 @@ case class DefaultAuthenticator( case keycloakCredentials: JwtCredentials => keycloakAuthenticator(keycloakCredentials) } - override def authorizeWalletAccessImpl(entity: BaseEntity): IO[AuthenticationError, WalletAccessContext] = + override def authorizeWalletAccessLogic(entity: BaseEntity): IO[AuthenticationError, WalletAccessContext] = entity match { case entity: Entity => EntityAuthorizer.authorizeWalletAccess(entity) case kcEntity: KeycloakEntity => keycloakAuthenticator.authorizeWalletAccess(kcEntity) diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/oidc/KeycloakAuthenticator.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/oidc/KeycloakAuthenticator.scala index 7dc7597fa6..9bce9e564f 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/oidc/KeycloakAuthenticator.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/oidc/KeycloakAuthenticator.scala @@ -55,9 +55,9 @@ final class AccessToken private (token: String, claims: JwtClaim, rolesClaimPath private def parseRole(s: String): Option[EntityRole] = { s match { - case "agent-admin" => Some(EntityRole.Admin) - case "agent-tenant" => Some(EntityRole.Tenant) - case _ => None + case "admin" => Some(EntityRole.Admin) + case "tenant" => Some(EntityRole.Tenant) + case _ => None } } } diff --git a/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/oidc/KeycloakAuthenticatorImpl.scala b/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/oidc/KeycloakAuthenticatorImpl.scala index 82e2fe7f2a..4d9f5156d8 100644 --- a/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/oidc/KeycloakAuthenticatorImpl.scala +++ b/prism-agent/service/server/src/main/scala/io/iohk/atala/iam/authentication/oidc/KeycloakAuthenticatorImpl.scala @@ -43,7 +43,7 @@ class KeycloakAuthenticatorImpl( } else ZIO.fail(AuthenticationMethodNotEnabled("Keycloak authentication is not enabled")) } - override def authorizeWalletAccessImpl(entity: KeycloakEntity): IO[AuthenticationError, WalletAccessContext] = { + override def authorizeWalletAccessLogic(entity: KeycloakEntity): IO[AuthenticationError, WalletAccessContext] = { for { walletId <- keycloakPermissionService .listWalletPermissions(entity) @@ -100,7 +100,7 @@ object KeycloakAuthenticatorImpl { new KeycloakAuthenticator { override def isEnabled: Boolean = false override def authenticate(token: String): IO[AuthenticationError, KeycloakEntity] = notEnabledError - override def authorizeWalletAccessImpl(entity: KeycloakEntity): IO[AuthenticationError, WalletAccessContext] = + override def authorizeWalletAccessLogic(entity: KeycloakEntity): IO[AuthenticationError, WalletAccessContext] = notEnabledError override def authorizeWalletAdmin( entity: KeycloakEntity diff --git a/prism-agent/service/server/src/test/resources/logback.xml b/prism-agent/service/server/src/test/resources/logback.xml index a087f966c5..1362021d83 100644 --- a/prism-agent/service/server/src/test/resources/logback.xml +++ b/prism-agent/service/server/src/test/resources/logback.xml @@ -12,7 +12,7 @@ - +