diff --git a/designs/claims.rst b/designs/claims.rst deleted file mode 100644 index bd2cfd714..000000000 --- a/designs/claims.rst +++ /dev/null @@ -1,167 +0,0 @@ -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 ... diff --git a/designs/oauth.rst b/designs/oauth.rst new file mode 100644 index 000000000..ea8101fde --- /dev/null +++ b/designs/oauth.rst @@ -0,0 +1,161 @@ +Oauth + Scopes + Claims +----------------------- + +Oauth is a web authorisation protocol that allows "single sign on". It's key to note +oauth is authorisation, not authentication, as the protocol in it's default forms +do not provide identity or authentication information, only information that +an entity is authorised for the requested resources. + +Oauth can tie into extensions allowing an identity provider to reveal information +about authorised sessions. This extends oauth from an authorisation only system +to a system capable of identity and authorisation. Two primary methods of this +exist today: rfc7662 token introspection, and openid connect. + +High Level Process +------------------ + +A client (user) wishes to access a service (resource, resource server). The resource +server does not have an active session for the client, so it redirects to the +authorisation server to determine if the client should be allowed to proceed, and +has the appropriate permissions (scopes). + +The authorisation server checks the current session of the client and may present +a login flow if required. Given the identity of the client known to the authorisation +sever, and the requested scopes, the authorisation server makes a decision if it +allows the authorisation to proceed. The client is also prompted to consent to the +authorisation. + +If successful the client is redirected back to the resource server with an authorisation +code. The resource server the contacts the authorisation server directly with this +code and exchanges it for a valid token that may be provided to the client. + +The resource server may optionally contact the token introspection endpoint about the +provided oauth token, which yields extra metadata about the identity that holds the +token and completed the authorisation. This metadata may include identity information, +but also may include extended metadata, sometimes refered to as "claims". Claims are +information bound to a token based on properties of the session that may allow +the resource server to make extended authorisation decisions without the need +to contact the authorisation server to arbitrate. + +In this model, Kanidm will function as the authorisation server. + +Kanidm UAT Claims +----------------- + +To ensure that we can filter and make certain autorisation decisions, the Kanidm UAT +needs to be extended with extra claims similar to the token claims. Since we have the +ability to strongly type these, we can add these to the UAT. These should include. + +* The UUID of the authenticating credential +* The expiry time of this session +* the classification of authentication used (MFA, SFA, Cryptographic) +* The expiry time of any elevated permissions +* If the session is "interactive" IE from a true human rather than an API pw. +* If the user is anonymous (?) + +The UAT should be signed with ECDSA so that client applications may inspect the content +IE the session expiry time. This may also allow offline validation. + +The ECDSA public key for this should be stored in the Kanidm "domain" configuration. The +private key should also be stored in this configuration, but thought will be needed about how +to handle this with replication securely IE readonly servers. + +HTTP Endpoints +-------------- + +We should expose the following endpoints: + +* /oauth/authorise +* /oauth/token +* /oauth/token/introspect + +All api responses must have: + +:: + + Cache-Control: no-store + Pragma: no-cache + + +Resource Servers +---------------- + +For a resource server to work with the authorisation server, it must be a registered +application within the authorisation server. + +Each registered resource server will have an associated secret for authentication. The +most simple for of this is a "basic" authorisation header. + +This resource server entry will nominially list what scopes map to which kanidm roles, +which scopes are "always" available to all authenticated users. Additionally, it may +be that we have an extra set of "filter rules" to allow authorisation decisions to be +made based on other factors like group membership. + +:: + + class: oauth_resource_server + class: oauth_resource_server_basic + oauth_rs_name: String, + oauth_rs_basic_secret: String, + # To validate the redirect root + oauth_rs_origin: String/URI + # Scopes that apply to all users + oauth_rs_scope_implicit: String + # Scopes that map to groups which will be enforced. + oauth_rs_scope_map: (String, reference) + # Filter of accounts that may authorise through this. + oauth_rs_account_filter: Filter + # A per-resource server fernet key for token/codes. + # Allows reset per/application in case of suspect compromise. + oauth_rs_token_key: String + +The returned authorisation code should be fernet encrypted and contains the unsigned UAT content of the authorised +user. + +The provided oauth token for this method will be encrypted with the fernet key of the related +resource server. It will contain the unsigned uat of the account in authorised, allowing token +introspection/reflection without needing to access the database. + +Token Introspection +------------------- + +Claims will be mapped to a kanidm namespace. Otherwise the rfc will be followed. + +Security +-------- + +Only PKCE Oauth 2.0 clients are accepted today. Alternately stronger exchange types may be considered +in the future. + +The default filter of accounts will exclude anonymous and tombstones/recycled. + +Should the default filter only allow interactive accounts to participate in this work flow? + +Test Cases / Use Cases +---------------------- + +roles such as idm_admin/admin should also require claim=sudo to use. + +To change your own details (self write) sudo should be required. + +read_self, mail etc should always be granted. + +Anonymous should not have access to any claims. + +sudo time expiry + +The ability to use oauth should require + +Links +----- + +Oauth2: https://tools.ietf.org/html/rfc6749 +pkce: https://tools.ietf.org/html/rfc7636 +token introspection: https://tools.ietf.org/html/rfc7662 +bearer: https://tools.ietf.org/html/rfc6750 +device authorisation grant: https://datatracker.ietf.org/doc/html/rfc8628 +claims ad krb: https://syfuhs.net/2017/07/29/active-directory-claims-and-kerberos-net/ +openid connect: https://openid.net/developers/specs/ + + + diff --git a/designs/sudo.rst b/designs/sudo.rst new file mode 100644 index 000000000..74490eb2f --- /dev/null +++ b/designs/sudo.rst @@ -0,0 +1,32 @@ +Sudo Mode +--------- + +To ensure that certain actions are only performed after re-authentication, we should introduce +a sudo mode to kanidm. This relies on some changes from Oauth.rst (namely interactive session +identification). + +Only interactive sessions (IE not api passwords or radius) must be elligble for sudo mode. + +Sudo mode when requested will perform a partial-reauthentication of the account using a single +factor (if mfa). This is determined based on the credential uuid of the associated session. + +When entered, a short sudo expiry timer is attached to the UAT, which is re-issued after the +re-authentication. + +During UAT to entry processing for api calls, the sudo timer will be checked. If current +time is less than the expiry, then the phantom attribute "sudo" which is boolean, will be set +to the entry. If it is not present, or invalid, it will be set to "false". + +This will allow filtering on sudo=true, meaning that certain default access controls can be +altered to enforce that they require sudo mode. + +Some accounts by default represent a high level of privilege. These should have implicit sudo +granted when they are autheticated. This will be based on a group membership idm_hp_implicit_sudo +and should only apply to admin/idm_admin by default. This will pin the sudo expiry to the expiry +time of the session (rather than a shorter time). + +Some accounts should never be able to enter sudo mode, and this will be based on the lack of +appropriate credentials. IE anonymous can never enter sudo mode, and will always fail. This +will allow the removal of a number of hardcoded anonymous exceptions in the IDM server, allowing +us to use the acp's to enforce rules instead. +