kanidm/designs/claims.rst
2020-03-26 11:56:20 +10:00

168 lines
5.9 KiB
ReStructuredText

Claims Design
-------------
Claims are a way of associating privileges to sessions, to scope and limit access of an identity.
This can be based on what credentials were used to authenticate, by the user requesting claims
for a session, or by time limiting claims.
These tend to fall into three major categories
Default Interactive Claims
--------------------------
When an identity authenticates they are given a set of claims associated to their interactive
login. This could include the ability to trigger a claim request or to view personal details.
Static Application Claims (or lack of)
--------------------------------------
Static application passwords (IE a device imap/smtp password) should have a claim to "email"
but not to read personal data and shouldn't be able to change passwords etc.
Ephemeral Claims
----------------
These are permissions that are limited in time - they *must* be requested and generally require
re-authentication with a subset of credentials. This can include the ability to alter ones own
account or time limiting admins ability to alter other accounts.
Detailed Design
---------------
As a result of these scenarios this leads to the following required observations.
* Claims must be associated to the credentials of the account
* Possible claims that could be assigned derive from membership to a group
* Claims must be understood by access controls of the server
* Claims must be present in user auth tokens for end applications to be able to verify
* Two types of claims exist - ephemeral and static
This leads to a pseudo design such as:
class: claim
name: claim_email
claim_name: email
member: account_1
class: claim
name: claim_unused
claim_name: unused
class: system, claim
name: claim_interactive
claim_name: interactive
class: claim, claim_ephemeral
name: claim_alter_self
claim_name: alter_self
claim_lifetime: 300 # seconds
member: account_1
name: account_1
...
primary_credential: {
type: password|webauthn|password+webauthn
claims: [ claim_alter_self ] //note that interactive is implied
}
application_credentialn: {
name: iphone imap password
type: generated_password
claims: [ claim_email ]
}
When we authenticate with the email password, because there is no lifetime this becomes a static
claim:
UserAuthToken {
name: account_1
claims: [ email ]
}
If we authenticate with the primary credential, the static claims are initially issued, and because
it's the primary token, we get the implied system interactive claim.
UserAuthToken {
name; account_1
claims: [ interactive ]
}
To have the "alter_self" claim, we must perform an auth-request-claim operation which re-verifies
a credential. This is a subset of the Auth operation
auth-request-claim ----> verify aci of request (are you interactive? )
<---- return challenge
send password/cred ----> verify credential
<---- update UAT with ephemeral claim
Then the UserAuthToken would be:
UserAuthToken {
name; account_1
claims: [ interactive, alter_self(expire_at_time) ]
}
This means:
* Consuming applications need to verify the claim list
* They need te verify the claim's expiry times.
For kanidm, to use claims in access controls, these must become filterable elements. On
UAT to Entry as part of the event conversion we will perform
load entry to member
for each claim in UAT:
if claim is not expired
alter memory entry -> add claim
ACP's can then have filters such as:
Eq('claim', 'alter_self')
This implies that claim's are in schema to allow filter construction and validation, and in
the protected module to prevent their creation.
Questions
---------
We should only be able to request claims on interactive (primary) credential sessions. How should
we mark this? I think the UAT needs to retain "what credential id" was used to authenticate, and then
emit this to the entry so that it can also be filtered on to determine primary vs application cred.
Claim and other generated attrs must be system protected, even though they have to exist in schema
for filter verification. This likely needs to be added to system_protected plugin to prevent claims
from being added to any entry type.
Once a claim is dynamically added to the entry it must move to a new state that prevents reserialisation to the DB.
Trust Considerations
--------------------
Claims should not be replicated, and are auth-silo specific. This is because
trusts as designed are about account and group sharing, rather than about detailed privilege or
resource granting in the trusting domain.
Because claims should be associated to groups, we can also apply account pw policy to groups.
This means that at the very least we have to consider replication of credential metadata though
so that the trusting domain can assign the claims somewhere (this metadata will be needed for
account cred policy and group membership later anyway). For example:
spn: claire@domainb
class: [trustedaccount, object]
trustedcredential: [ name, id, claims ]
This way when the account authenticates to the trusting domain, because the credential ID that was
used is in the UAT, this allows the trusting domain to inspect what credential was used, and to
be able to assign it's domain local claims to the session. This could then have a similar work
flow when ephemeral claims are needed.
mental note: because groups will define account policy, when a trusted account is a member of a group
and it doesn't meet that groups account policy requirements, it should be listed in the uat as
a rejected group so that we can easily diagnose when an account is insufficient to receive that group
or that claim as a result. This may affect how we treat memberof on the session though when
we do UAT to entry. An argument could be made to strip the memberofs when they are in the rejected
list ...