diff --git a/go.mod b/go.mod index 967fa84cd5..a25538f9c2 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/allegro/bigcache v1.2.1 github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc github.com/caos/logging v0.0.2 - github.com/caos/oidc v0.15.2 + github.com/caos/oidc v0.15.3 github.com/caos/orbos v1.5.14-0.20210428081839-983ffc569980 github.com/cockroachdb/cockroach-go/v2 v2.1.0 github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43 @@ -24,7 +24,7 @@ require ( github.com/ghodss/yaml v1.0.0 github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b - github.com/golang/mock v1.5.0 + github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.2 github.com/golang/snappy v0.0.2 // indirect github.com/gorilla/csrf v1.7.0 @@ -71,13 +71,13 @@ require ( golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c golang.org/x/text v0.3.6 - golang.org/x/tools v0.1.0 + golang.org/x/tools v0.1.1 google.golang.org/api v0.34.0 google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20210406143921-e86de6bf7a46 google.golang.org/grpc v1.36.1 google.golang.org/protobuf v1.26.0 - gopkg.in/square/go-jose.v2 v2.5.1 + gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 gotest.tools v2.2.0+incompatible k8s.io/api v0.19.2 diff --git a/go.sum b/go.sum index 0c6d0291c2..f55f8944ba 100644 --- a/go.sum +++ b/go.sum @@ -138,8 +138,8 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBW github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo= github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= github.com/caos/oidc v0.14.4/go.mod h1:H5Y2zw3YIrWqQOoy0wcmZva2a66bumDyU2iOhXiM9uA= -github.com/caos/oidc v0.15.2 h1:fvR8Mtnv+d0Lw+tmXHS5u8XYpuE2xCNpobPA66rx/9Q= -github.com/caos/oidc v0.15.2/go.mod h1:JiK5RXSOgag66wiSOMEkS+yS4R46Baz6dGwfr60VfvI= +github.com/caos/oidc v0.15.3 h1:DNzzvSgUbhUewrZKOVF9nDop0AfMy0wjnMy/rD9f8xA= +github.com/caos/oidc v0.15.3/go.mod h1:doQ1B/mGnQWbgS+UOANIQCPJe1+KACyxQ8wjV2d11h0= github.com/caos/orbos v1.5.14-0.20210428081839-983ffc569980 h1:Fz0aYUwGMA2tsu5w7SryqFGjqGClJVHbyhBMT5SXtPU= github.com/caos/orbos v1.5.14-0.20210428081839-983ffc569980/go.mod h1:2I8oiZb5SMRm/qTLvwpSmdV0M6ex8J/UKyxUGfKaqJo= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= @@ -360,8 +360,9 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= -github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -930,6 +931,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= @@ -1046,8 +1048,9 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1097,8 +1100,9 @@ golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4 h1:b0LrWgu8+q7z4J+0Y3Umo5q1dL7NXBkKBWkaVkAq17E= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190517181255-950ef44c6e07/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1184,8 +1188,10 @@ golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1270,8 +1276,9 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20201030143252-cf7a54d06671/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1406,8 +1413,9 @@ gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= diff --git a/internal/api/oidc/auth_request_converter.go b/internal/api/oidc/auth_request_converter.go index 66b548e202..52ca9a0630 100644 --- a/internal/api/oidc/auth_request_converter.go +++ b/internal/api/oidc/auth_request_converter.go @@ -113,6 +113,7 @@ func AuthRequestFromBusiness(authReq *domain.AuthRequest) (_ op.AuthRequest, err func CreateAuthRequestToBusiness(ctx context.Context, authReq *oidc.AuthRequest, userAgentID, userID string) *domain.AuthRequest { return &domain.AuthRequest{ + CreationDate: time.Now(), AgentID: userAgentID, BrowserInfo: ParseBrowserInfoFromContext(ctx), ApplicationID: authReq.ClientID, @@ -122,7 +123,7 @@ func CreateAuthRequestToBusiness(ctx context.Context, authReq *oidc.AuthRequest, PossibleLOAs: ACRValuesToBusiness(authReq.ACRValues), UiLocales: UILocalesToBusiness(authReq.UILocales), LoginHint: authReq.LoginHint, - MaxAuthAge: authReq.MaxAge, + MaxAuthAge: MaxAgeToBusiness(authReq.MaxAge), UserID: userID, Request: &domain.AuthRequestOIDC{ Scopes: authReq.Scopes, @@ -161,21 +162,23 @@ func IpFromContext(ctx context.Context) net.IP { return net.ParseIP(ipString) } -func PromptToBusiness(prompt oidc.Prompt) domain.Prompt { - switch prompt { - case oidc.PromptNone: - return domain.PromptNone - case oidc.PromptLogin: - return domain.PromptLogin - case oidc.PromptConsent: - return domain.PromptConsent - case oidc.PromptSelectAccount: - return domain.PromptSelectAccount - case "create": //this prompt is not final yet, so not implemented in oidc lib - return domain.PromptCreate - default: - return domain.PromptUnspecified +func PromptToBusiness(oidcPrompt []string) []domain.Prompt { + prompts := make([]domain.Prompt, len(oidcPrompt)) + for _, oidcPrompt := range oidcPrompt { + switch oidcPrompt { + case oidc.PromptNone: + prompts = append(prompts, domain.PromptNone) + case oidc.PromptLogin: + prompts = append(prompts, domain.PromptLogin) + case oidc.PromptConsent: + prompts = append(prompts, domain.PromptConsent) + case oidc.PromptSelectAccount: + prompts = append(prompts, domain.PromptSelectAccount) + case "create": //this prompt is not final yet, so not implemented in oidc lib + prompts = append(prompts, domain.PromptCreate) + } } + return prompts } func ACRValuesToBusiness(values []string) []domain.LevelOfAssurance { @@ -193,6 +196,14 @@ func UILocalesToBusiness(tags []language.Tag) []string { return locales } +func MaxAgeToBusiness(maxAge *uint) *time.Duration { + if maxAge == nil { + return nil + } + dur := time.Duration(*maxAge) * time.Second + return &dur +} + func ResponseTypeToBusiness(responseType oidc.ResponseType) domain.OIDCResponseType { switch responseType { case oidc.ResponseTypeCode: @@ -291,6 +302,6 @@ func (r *RefreshTokenRequest) GetSubject() string { return r.UserID } -func (r *RefreshTokenRequest) SetCurrentScopes(scopes oidc.Scopes) { +func (r *RefreshTokenRequest) SetCurrentScopes(scopes []string) { r.Scopes = scopes } diff --git a/internal/api/oidc/client.go b/internal/api/oidc/client.go index 7b6f7d910e..96e3ceee35 100644 --- a/internal/api/oidc/client.go +++ b/internal/api/oidc/client.go @@ -80,7 +80,7 @@ func (o *OPStorage) GetKeyByIDAndIssuer(ctx context.Context, keyID, issuer strin }, nil } -func (o *OPStorage) ValidateJWTProfileScopes(ctx context.Context, subject string, scopes oidc.Scopes) (oidc.Scopes, error) { +func (o *OPStorage) ValidateJWTProfileScopes(ctx context.Context, subject string, scopes []string) ([]string, error) { user, err := o.repo.UserByID(ctx, subject) if err != nil { return nil, err diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index 3899208944..1775e6ce8e 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -523,7 +523,7 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth return nil, errors.ThrowInvalidArgument(nil, "EVENT-ds27a", "Errors.Internal") } steps := make([]domain.NextStep, 0) - if !checkLoggedIn && request.Prompt == domain.PromptNone { + if !checkLoggedIn && domain.IsPrompt(request.Prompt, domain.PromptNone) { return append(steps, &domain.RedirectToCallbackStep{}), nil } if request.UserID == "" { @@ -532,15 +532,15 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth return steps, nil } steps = append(steps, new(domain.LoginStep)) - if request.Prompt == domain.PromptCreate { + if domain.IsPrompt(request.Prompt, domain.PromptCreate) { return append(steps, &domain.RegistrationStep{}), nil } - if request.Prompt == domain.PromptSelectAccount || request.Prompt == domain.PromptUnspecified { + if len(request.Prompt) == 0 || domain.IsPrompt(request.Prompt, domain.PromptSelectAccount) { users, err := repo.usersForUserSelection(request) if err != nil { return nil, err } - if len(users) > 0 || request.Prompt == domain.PromptSelectAccount { + if len(users) > 0 || domain.IsPrompt(request.Prompt, domain.PromptSelectAccount) { steps = append(steps, &domain.SelectUserStep{Users: users}) } } @@ -557,7 +557,7 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *domain.Auth } isInternalLogin := request.SelectedIDPConfigID == "" && userSession.SelectedIDPConfigID == "" - if !isInternalLogin && len(request.LinkingUsers) == 0 && !checkVerificationTime(userSession.ExternalLoginVerification, repo.ExternalLoginCheckLifeTime) { + if !isInternalLogin && len(request.LinkingUsers) == 0 && !checkVerificationTimeMaxAge(userSession.ExternalLoginVerification, repo.ExternalLoginCheckLifeTime, request) { selectedIDPConfigID := request.SelectedIDPConfigID if selectedIDPConfigID == "" { selectedIDPConfigID = userSession.SelectedIDPConfigID @@ -638,7 +638,7 @@ func (repo *AuthRequestRepo) firstFactorChecked(request *domain.AuthRequest, use var step domain.NextStep if request.LoginPolicy.PasswordlessType != domain.PasswordlessTypeNotAllowed && user.IsPasswordlessReady() { - if checkVerificationTime(userSession.PasswordlessVerification, repo.MultiFactorCheckLifeTime) { + if checkVerificationTimeMaxAge(userSession.PasswordlessVerification, repo.MultiFactorCheckLifeTime, request) { request.AuthTime = userSession.PasswordlessVerification return nil } @@ -649,7 +649,7 @@ func (repo *AuthRequestRepo) firstFactorChecked(request *domain.AuthRequest, use return &domain.InitPasswordStep{} } - if checkVerificationTime(userSession.PasswordVerification, repo.PasswordCheckLifeTime) { + if checkVerificationTimeMaxAge(userSession.PasswordVerification, repo.PasswordCheckLifeTime, request) { request.PasswordVerified = true request.AuthTime = userSession.PasswordVerification return nil @@ -686,14 +686,14 @@ func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, } fallthrough case domain.MFALevelSecondFactor: - if checkVerificationTime(userSession.SecondFactorVerification, repo.SecondFactorCheckLifeTime) { + if checkVerificationTimeMaxAge(userSession.SecondFactorVerification, repo.SecondFactorCheckLifeTime, request) { request.MFAsVerified = append(request.MFAsVerified, auth_req_model.MFATypeToDomain(userSession.SecondFactorVerificationType)) request.AuthTime = userSession.SecondFactorVerification return nil, true, nil } fallthrough case domain.MFALevelMultiFactor: - if checkVerificationTime(userSession.MultiFactorVerification, repo.MultiFactorCheckLifeTime) { + if checkVerificationTimeMaxAge(userSession.MultiFactorVerification, repo.MultiFactorCheckLifeTime, request) { request.MFAsVerified = append(request.MFAsVerified, auth_req_model.MFATypeToDomain(userSession.MultiFactorVerificationType)) request.AuthTime = userSession.MultiFactorVerification return nil, true, nil @@ -765,6 +765,16 @@ func getLoginPolicyIDPProviders(provider idpProviderViewProvider, iamID, orgID s return iam_es_model.IDPProviderViewsToModel(idpProviders), nil } +func checkVerificationTimeMaxAge(verificationTime time.Time, lifetime time.Duration, request *domain.AuthRequest) bool { + if !checkVerificationTime(verificationTime, lifetime) { + return false + } + if request.MaxAuthAge == nil { + return true + } + return verificationTime.After(request.CreationDate.Add(-*request.MaxAuthAge)) +} + func checkVerificationTime(verificationTime time.Time, lifetime time.Duration) bool { return verificationTime.Add(lifetime).After(time.Now().UTC()) } diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go index 760e1422f4..637dbfb9c7 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go @@ -251,7 +251,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { { "prompt none and checkLoggedIn false, callback step", fields{}, - args{&domain.AuthRequest{Prompt: domain.PromptNone}, false}, + args{&domain.AuthRequest{Prompt: []domain.Prompt{domain.PromptNone}}, false}, []domain.NextStep{&domain.RedirectToCallbackStep{}}, nil, }, @@ -278,7 +278,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { fields{ userSessionViewProvider: &mockViewErrUserSession{}, }, - args{&domain.AuthRequest{Prompt: domain.PromptSelectAccount}, false}, + args{&domain.AuthRequest{Prompt: []domain.Prompt{domain.PromptSelectAccount}}, false}, nil, errors.IsInternal, }, @@ -301,7 +301,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { }, userEventProvider: &mockEventUser{}, }, - args{&domain.AuthRequest{Prompt: domain.PromptSelectAccount}, false}, + args{&domain.AuthRequest{Prompt: []domain.Prompt{domain.PromptSelectAccount}}, false}, []domain.NextStep{ &domain.LoginStep{}, &domain.SelectUserStep{ @@ -341,7 +341,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { }, userEventProvider: &mockEventUser{}, }, - args{&domain.AuthRequest{Prompt: domain.PromptSelectAccount, RequestedOrgID: "orgID1"}, false}, + args{&domain.AuthRequest{Prompt: []domain.Prompt{domain.PromptSelectAccount}, RequestedOrgID: "orgID1"}, false}, []domain.NextStep{ &domain.LoginStep{}, &domain.SelectUserStep{ @@ -370,7 +370,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { }, userEventProvider: &mockEventUser{}, }, - args{&domain.AuthRequest{Prompt: domain.PromptSelectAccount}, false}, + args{&domain.AuthRequest{Prompt: []domain.Prompt{domain.PromptSelectAccount}}, false}, []domain.NextStep{ &domain.LoginStep{}, &domain.SelectUserStep{ @@ -848,7 +848,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { }, args{&domain.AuthRequest{ UserID: "UserID", - Prompt: domain.PromptNone, + Prompt: []domain.Prompt{domain.PromptNone}, Request: &domain.AuthRequestOIDC{}, LoginPolicy: &domain.LoginPolicy{ SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP}, @@ -880,7 +880,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { }, args{&domain.AuthRequest{ UserID: "UserID", - Prompt: domain.PromptNone, + Prompt: []domain.Prompt{domain.PromptNone}, Request: &domain.AuthRequestOIDC{}, LoginPolicy: &domain.LoginPolicy{ SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP}, @@ -912,7 +912,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { }, args{&domain.AuthRequest{ UserID: "UserID", - Prompt: domain.PromptNone, + Prompt: []domain.Prompt{domain.PromptNone}, Request: &domain.AuthRequestOIDC{}, LoginPolicy: &domain.LoginPolicy{ SecondFactors: []domain.SecondFactorType{domain.SecondFactorTypeOTP}, diff --git a/internal/domain/auth_request.go b/internal/domain/auth_request.go index 8aa9d9a62e..21ea1aba18 100644 --- a/internal/domain/auth_request.go +++ b/internal/domain/auth_request.go @@ -18,11 +18,11 @@ type AuthRequest struct { ApplicationID string CallbackURI string TransferState string - Prompt Prompt + Prompt []Prompt PossibleLOAs []LevelOfAssurance UiLocales []string LoginHint string - MaxAuthAge uint32 + MaxAuthAge *time.Duration Request Request levelOfAssurance LevelOfAssurance @@ -75,6 +75,15 @@ const ( PromptCreate ) +func IsPrompt(prompt []Prompt, requestedPrompt Prompt) bool { + for _, p := range prompt { + if p == requestedPrompt { + return true + } + } + return false +} + type LevelOfAssurance int const (