mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-05 14:37:45 +00:00
fix: ignore projectID and origin check for service accounts (#8704)
# Which Problems Are Solved Calls with tokens issued through JWT Profile or Client Credentials Grants were no longer possible and threw a "could not read projectid by clientid (AUTH-GHpw2)" error. ZITADEL checks the allowed origins of an application and load its projectID into the context on any API call. Tokens from service accounts did not contain any clientID and therefore never did that check. But due to a change in https://github.com/zitadel/zitadel/pull/8580, were the service user id was set as client_id in the OIDC session to fix the introspection response (https://github.com/zitadel/zitadel/issues/8590). # How the Problems Are Solved - Check if the project and origin were retrieved and only then check the origins # Additional Changes None. # Additional Context - closes https://github.com/zitadel/zitadel/issues/8676 - relates to https://github.com/zitadel/zitadel/pull/8580 (released on 2.62.0) - relates to https://github.com/zitadel/zitadel/issues/8590
This commit is contained in:
parent
63d733b3a2
commit
c347e75485
@ -116,19 +116,9 @@ func VerifyTokenAndCreateCtxData(ctx context.Context, token, orgID, orgDomain st
|
||||
return CtxData{}, zerrors.ThrowUnauthenticated(errors.Join(err, sysTokenErr), "AUTH-7fs1e", "Errors.Token.Invalid")
|
||||
}
|
||||
}
|
||||
var projectID string
|
||||
var origins []string
|
||||
if clientID != "" {
|
||||
projectID, origins, err = t.ProjectIDAndOriginsByClientID(ctx, clientID)
|
||||
if err != nil {
|
||||
return CtxData{}, zerrors.ThrowPermissionDenied(err, "AUTH-GHpw2", "could not read projectid by clientid")
|
||||
}
|
||||
// We used to check origins for every token, but service users shouldn't be used publicly (native app / SPA).
|
||||
// Therefore, mostly won't send an origin and aren't able to configure them anyway.
|
||||
// For the current time we will only check origins for tokens issued to users through apps (code / implicit flow).
|
||||
if err := checkOrigin(ctx, origins); err != nil {
|
||||
return CtxData{}, err
|
||||
}
|
||||
projectID, err := projectIDAndCheckOriginForClientID(ctx, clientID, t)
|
||||
if err != nil {
|
||||
return CtxData{}, err
|
||||
}
|
||||
if orgID == "" && orgDomain == "" {
|
||||
orgID = resourceOwner
|
||||
@ -151,6 +141,22 @@ func VerifyTokenAndCreateCtxData(ctx context.Context, token, orgID, orgDomain st
|
||||
}, nil
|
||||
}
|
||||
|
||||
func projectIDAndCheckOriginForClientID(ctx context.Context, clientID string, t APITokenVerifier) (string, error) {
|
||||
if clientID == "" {
|
||||
return "", nil
|
||||
}
|
||||
projectID, origins, err := t.ProjectIDAndOriginsByClientID(ctx, clientID)
|
||||
logging.WithFields("clientID", clientID).OnError(err).Debug("could not check projectID and origin of clientID (might be service account)")
|
||||
|
||||
// We used to check origins for every token, but service users shouldn't be used publicly (native app / SPA).
|
||||
// Therefore, mostly won't send an origin and aren't able to configure them anyway.
|
||||
// For the current time we will only check origins for tokens issued to users through apps (code / implicit flow).
|
||||
if projectID == "" {
|
||||
return "", nil
|
||||
}
|
||||
return projectID, checkOrigin(ctx, origins)
|
||||
}
|
||||
|
||||
func SetCtxData(ctx context.Context, ctxData CtxData) context.Context {
|
||||
return context.WithValue(ctx, dataKey, ctxData)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -14,6 +15,8 @@ import (
|
||||
|
||||
oidc_api "github.com/zitadel/zitadel/internal/api/oidc"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/auth"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/management"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/user"
|
||||
)
|
||||
@ -105,6 +108,17 @@ func TestServer_ClientCredentialsExchange(t *testing.T) {
|
||||
updated: machine.GetDetails().GetChangeDate().AsTime(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "openid, profile, email, zitadel",
|
||||
clientID: clientID,
|
||||
clientSecret: clientSecret,
|
||||
scope: []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, domain.ProjectScopeZITADEL},
|
||||
wantClaims: claims{
|
||||
name: name,
|
||||
username: name,
|
||||
updated: machine.GetDetails().GetChangeDate().AsTime(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org id and domain scope",
|
||||
clientID: clientID,
|
||||
@ -173,6 +187,13 @@ func TestServer_ClientCredentialsExchange(t *testing.T) {
|
||||
assert.Empty(t, userinfo.UserInfoEmail)
|
||||
assert.Empty(t, userinfo.UserInfoPhone)
|
||||
assert.Empty(t, userinfo.Address)
|
||||
|
||||
_, err = Instance.Client.Auth.GetMyUser(integration.WithAuthorizationToken(CTX, tokens.AccessToken), &auth.GetMyUserRequest{})
|
||||
if slices.Contains(tt.scope, domain.ProjectScopeZITADEL) {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.Error(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
package oidc_test
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -15,6 +16,8 @@ import (
|
||||
|
||||
oidc_api "github.com/zitadel/zitadel/internal/api/oidc"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/auth"
|
||||
)
|
||||
|
||||
func TestServer_JWTProfile(t *testing.T) {
|
||||
@ -54,6 +57,16 @@ func TestServer_JWTProfile(t *testing.T) {
|
||||
updated: user.GetDetails().GetChangeDate().AsTime(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "openid, profile, email, zitadel",
|
||||
keyData: keyData,
|
||||
scope: []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, domain.ProjectScopeZITADEL},
|
||||
wantClaims: claims{
|
||||
name: name,
|
||||
username: name,
|
||||
updated: user.GetDetails().GetChangeDate().AsTime(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "org id and domain scope",
|
||||
keyData: keyData,
|
||||
@ -129,6 +142,13 @@ func TestServer_JWTProfile(t *testing.T) {
|
||||
assert.Empty(t, userinfo.UserInfoEmail)
|
||||
assert.Empty(t, userinfo.UserInfoPhone)
|
||||
assert.Empty(t, userinfo.Address)
|
||||
|
||||
_, err = Instance.Client.Auth.GetMyUser(integration.WithAuthorizationToken(CTX, tokens.AccessToken), &auth.GetMyUserRequest{})
|
||||
if slices.Contains(tt.scope, domain.ProjectScopeZITADEL) {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.Error(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ const (
|
||||
ProjectIDScope = "urn:zitadel:iam:org:project:id:"
|
||||
ProjectIDScopeZITADEL = "zitadel"
|
||||
AudSuffix = ":aud"
|
||||
ProjectScopeZITADEL = ProjectIDScope + ProjectIDScopeZITADEL + AudSuffix
|
||||
SelectIDPScope = "urn:zitadel:iam:org:idp:id:"
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user