Tim Möhlmann 6398349c24
feat(oidc): token exchange impersonation (#7516)
* add token exchange feature flag

* allow setting reason and actor to access tokens

* impersonation

* set token types and scopes in response

* upgrade oidc to working draft state

* fix tests

* audience and scope validation

* id toke and jwt as input

* return id tokens

* add grant type  token exchange to app config

* add integration tests

* check and deny actors in api calls

* fix instance setting tests by triggering projection on write and cleanup

* insert sleep statements again

* solve linting issues

* add translations

* pin oidc v3.15.0

* resolve comments, add event translation

* fix refreshtoken test

* use ValidateAuthReqScopes from oidc

* apparently the linter can't make up its mind

* persist actor thru refresh tokens and check in tests

* remove unneeded triggers
2024-03-20 10:18:46 +00:00

92 lines
2.5 KiB
Go

package oidc
import "github.com/zitadel/zitadel/internal/domain"
const (
// Password states that the users password has been verified
// Deprecated: use `PWD` instead
Password = "password"
// PWD states that the users password has been verified
PWD = "pwd"
// MFA states that multiple factors have been verified (e.g. pwd and otp or passkey)
MFA = "mfa"
// OTP states that a one time password has been verified (e.g. TOTP)
OTP = "otp"
// UserPresence states that the end users presence has been verified (e.g. passkey and u2f)
UserPresence = "user"
)
// AuthMethodTypesToAMR maps zitadel auth method types to Authentication Method Reference Values
// as defined in [RFC 8176, section 2].
//
// [RFC 8176, section 2]: https://datatracker.ietf.org/doc/html/rfc8176#section-2
func AuthMethodTypesToAMR(methodTypes []domain.UserAuthMethodType) []string {
if methodTypes == nil {
return nil // make sure amr is omitted when not provided / supported
}
amr := make([]string, 0, 4)
var factors, otp int
for _, methodType := range methodTypes {
switch methodType {
case domain.UserAuthMethodTypePassword:
amr = append(amr, PWD)
factors++
case domain.UserAuthMethodTypePasswordless:
amr = append(amr, UserPresence)
factors += 2
case domain.UserAuthMethodTypeU2F:
amr = append(amr, UserPresence)
factors++
case domain.UserAuthMethodTypeOTP,
domain.UserAuthMethodTypeTOTP,
domain.UserAuthMethodTypeOTPSMS,
domain.UserAuthMethodTypeOTPEmail:
// a user could use multiple (t)otp, which is a factor, but still will be returned as a single `otp` entry
otp++
factors++
case domain.UserAuthMethodTypeIDP:
// no AMR value according to specification
factors++
case domain.UserAuthMethodTypeUnspecified:
// ignore
}
}
if otp > 0 {
amr = append(amr, OTP)
}
if factors >= 2 {
amr = append(amr, MFA)
}
return amr
}
func AMRToAuthMethodTypes(amr []string) []domain.UserAuthMethodType {
authMethods := make([]domain.UserAuthMethodType, 0, len(amr))
var (
userPresence bool
mfa bool
)
for _, entry := range amr {
switch entry {
case Password, PWD:
authMethods = append(authMethods, domain.UserAuthMethodTypePassword)
case OTP:
authMethods = append(authMethods, domain.UserAuthMethodTypeOTP)
case UserPresence:
userPresence = true
case MFA:
mfa = true
}
}
if userPresence {
if mfa {
authMethods = append(authMethods, domain.UserAuthMethodTypePasswordless)
} else {
authMethods = append(authMethods, domain.UserAuthMethodTypeU2F)
}
}
return authMethods
}