-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Authorization rule changes for IDPs isolation [DPP-1336] #15848
Conversation
85c874d
to
a7d6e96
Compare
a7d6e96
to
81aced5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General question:
- Will it be possible to set up a user he admin right and in a non default idp?
- What if the user management service is enabled and someone uses a custom daml access token (one doesn't mention the user id). Can such a request succeed?
- To fetch themselves in GetUserRequest a user doesn't need to provide it's user id but it needs to provide its idp id - this seems a bit unintuitive. Maybe if we renamed the default idp from the empty string to a some other value (e.g. "default") then maybe w could make the
identity_provider_id
fields in the requests default to the current user's idp?
I think these changes need be accompanied by a suite authorization tests because the logic here is really non-trivial.
// Claim is valid only for the specific Identity Provider, | ||
// and identity_provider_id in the request matches the one provided in the claim. | ||
Left(AuthorizationError.InvalidIdentityProviderId(id)) | ||
case _ => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When claims.identityProvider
is the default idp and requestIdentityProviderId
is None then you're succeeding, but requestIdentityProviderId
being None actually means that request idp validation failed.
I think this method should accept only valid requestIdentityProviderIds i.e. requestIdentityProviderId: IdentityProviderId
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If requestIdentityProviderId
is not provided - it's NOT an authorization problem, it will be validated out in the layer below. It is an invalid argument which will be validated further. Not sure how to act here to make sure proper layers are responsible for errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding of this code is that in line 129 Left(AuthorizationError.InvalidIdentityProviderId(id))
is returned also requestIdentityProviderId
is None.
Also, could it even be the case that requestIdentityProviderId
is not provided? Because if it's the empty it actually means the default idp
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me first define here what is what.
claims.identityProviderId
is what is provided from the token. So two options here are possible:
- default IDP (token is issued by the auth config defined in the default configuration)
- non-default IDP having concrete value (as it is of type
IdentityProviderId
)
requestIdentityProviderId
is what we extracted out from the request. Here we distinguish the following cases:
None
, meansidentity_provider_id
from the request which cannot be recognized/parsed. For example String with more than 255 chars, or having invalid characters.- Some value of non-default IDP which is equal to the IDP-ID of the token
- Some value of non-default IDP which is NOT equal to the IDP-ID of the token
- Default IDP (i.e.
identity_provider_id
was an empty string)
What is important to know with the authorization rules we have introduced:
- A
participant_admin
may provide any arbitrary value as IDP-ID (i.e.requestIdentityProviderId
does not matter) and authorization layer should not be restricting the admin (that is why ifclaims.identityProviderId == Default
it is givingRight(())
- An invalid
IdentityProviderId
, i.e. non-LedgerString
, would giveNone
forrequestIdentityProviderId
and authorization layer would allow to pass the filter (but currently only for non-Default IDP), as this is nothing to do withPERMISSION_DENIED
error which can be issued here.
You're right with your statement that None
gives InvalidIdentityProviderId
. So PERMISSION_DENIED
will be issued in the case of non-default IDP. I think I just have to fix it and pass it further to the business logic layer.
I think in general this highlights a bit broken design of the authorization layer. I don't like that in case of invalid request I'm passing things further and let it fail on the business logic. But doing it differently would break current pattern and will be much more work. Do you maybe have suggestions to improve that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would include parts of the justification in form of comment. Surely it is not the last time we will be looking at this code asking same questions as Pawel has
ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/Authorizer.scala
Outdated
Show resolved
Hide resolved
ledger-api/grpc-definitions/com/daml/ledger/api/v1/admin/party_management_service.proto
Show resolved
Hide resolved
...-auth/src/main/scala/com/digitalasset/ledger/api/auth/IdentityProviderAwareAuthService.scala
Outdated
Show resolved
Hide resolved
...-auth/src/main/scala/com/digitalasset/ledger/api/auth/IdentityProviderAwareAuthService.scala
Show resolved
Hide resolved
...gration-api/src/main/scala/platform/apiserver/services/admin/ApiPartyManagementService.scala
Outdated
Show resolved
Hide resolved
...gration-api/src/main/scala/platform/apiserver/services/admin/ApiPartyManagementService.scala
Outdated
Show resolved
Hide resolved
...egration-api/src/main/scala/platform/apiserver/services/admin/ApiUserManagementService.scala
Outdated
Show resolved
Hide resolved
...egration-api/src/main/scala/platform/apiserver/services/admin/ApiUserManagementService.scala
Show resolved
Hide resolved
...ocal-store/src/main/scala/com/daml/platform/localstore/api/IdentityProviderConfigStore.scala
Show resolved
Hide resolved
This should work as before. From the IDP perspective it would be as if request is coming from the default IDP. |
1b42a24
to
9d23bd0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good.
Are you planning to add any tests to this PR? I think it would be worth doing that
ledger-api/grpc-definitions/com/daml/ledger/api/v1/admin/party_management_service.proto
Outdated
Show resolved
Hide resolved
ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthorizationError.scala
Outdated
Show resolved
Hide resolved
ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/Claims.scala
Outdated
Show resolved
Hide resolved
ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/Claims.scala
Show resolved
Hide resolved
ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/ConfigLoader.scala
Outdated
Show resolved
Hide resolved
90c1c34
to
a0c09a7
Compare
ledger/ledger-api-auth/src/main/scala/com/digitalasset/ledger/api/auth/AuthorizationError.scala
Outdated
Show resolved
Hide resolved
...egration-api/src/main/scala/platform/apiserver/services/admin/ApiUserManagementService.scala
Outdated
Show resolved
Hide resolved
@@ -16,7 +16,8 @@ class IdentityProviderConfigStoreMetrics( | |||
override val registry: MetricRegistry, | |||
) extends FactoryWithDBMetrics { | |||
|
|||
val cacheByIssuer = new CacheMetrics(prefix :+ "cache_by_issuer", registry) | |||
val idpConfigCache = new CacheMetrics(prefix :+ "idp_config_cache", registry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to document these new metrics in UNRELEASED.md
override def getIdentityProviderConfig(issuer: LedgerId)(implicit | ||
loggingContext: LoggingContext | ||
): Future[domain.IdentityProviderConfig] = | ||
identityProviderStore.getActiveIdentityProviderByIssuer(issuer) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
which execution context should this run on?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
servicesExecutionContext ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would think so too
...gration-api/src/main/scala/platform/apiserver/services/admin/ApiPartyManagementService.scala
Outdated
Show resolved
Hide resolved
…_management_service.proto Co-authored-by: mziolekda <marcin.ziolek@digitalasset.com>
…api/auth/AuthorizationError.scala Co-authored-by: mziolekda <marcin.ziolek@digitalasset.com>
…server/services/admin/ApiPartyManagementService.scala Co-authored-by: mziolekda <marcin.ziolek@digitalasset.com>
0d0f3e9
to
946ad62
Compare
No description provided.