mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-14 11:58:02 +00:00
fix: consider oidc session events for authN milestones (#8089)
# Which Problems Are Solved
After migrating the access token events in #7822, milestones based on
authentication, resp. theses events would not be reached.
# How the Problems Are Solved
Additionally use the `oidc_session.Added` event to check for
`milestone.AuthenticationSucceededOnInstance` and
`milestone.AuthenticationSucceededOnApplication`.
# Additional Changes
None.
# Additional Context
- relates to #7822
- noticed internally
(cherry picked from commit b6c10c4c83
)
This commit is contained in:
parent
eb8f61d1c1
commit
663484e1fb
@ -22,7 +22,7 @@ import (
|
|||||||
func TestServer_Restrictions_DisallowPublicOrgRegistration(t *testing.T) {
|
func TestServer_Restrictions_DisallowPublicOrgRegistration(t *testing.T) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
domain, _, iamOwnerCtx := Tester.UseIsolatedInstance(t, ctx, SystemCTX)
|
domain, _, _, iamOwnerCtx := Tester.UseIsolatedInstance(t, ctx, SystemCTX)
|
||||||
regOrgUrl, err := url.Parse("http://" + domain + ":8080/ui/login/register/org")
|
regOrgUrl, err := url.Parse("http://" + domain + ":8080/ui/login/register/org")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
// The CSRF cookie must be sent with every request.
|
// The CSRF cookie must be sent with every request.
|
||||||
|
@ -33,7 +33,7 @@ func TestServer_Restrictions_AllowedLanguages(t *testing.T) {
|
|||||||
unsupportedLanguage = language.Afrikaans
|
unsupportedLanguage = language.Afrikaans
|
||||||
)
|
)
|
||||||
|
|
||||||
domain, _, iamOwnerCtx := Tester.UseIsolatedInstance(t, ctx, SystemCTX)
|
domain, _, _, iamOwnerCtx := Tester.UseIsolatedInstance(t, ctx, SystemCTX)
|
||||||
t.Run("assumed defaults are correct", func(tt *testing.T) {
|
t.Run("assumed defaults are correct", func(tt *testing.T) {
|
||||||
tt.Run("languages are not restricted by default", func(ttt *testing.T) {
|
tt.Run("languages are not restricted by default", func(ttt *testing.T) {
|
||||||
restrictions, err := Tester.Client.Admin.GetRestrictions(iamOwnerCtx, &admin.GetRestrictionsRequest{})
|
restrictions, err := Tester.Client.Admin.GetRestrictions(iamOwnerCtx, &admin.GetRestrictionsRequest{})
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestServer_ListInstances(t *testing.T) {
|
func TestServer_ListInstances(t *testing.T) {
|
||||||
domain, instanceID, _ := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
domain, instanceID, _, _ := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestServer_Limits_AuditLogRetention(t *testing.T) {
|
func TestServer_Limits_AuditLogRetention(t *testing.T) {
|
||||||
_, instanceID, iamOwnerCtx := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
_, instanceID, _, iamOwnerCtx := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
||||||
userID, projectID, appID, projectGrantID := seedObjects(iamOwnerCtx, t)
|
userID, projectID, appID, projectGrantID := seedObjects(iamOwnerCtx, t)
|
||||||
beforeTime := time.Now()
|
beforeTime := time.Now()
|
||||||
farPast := timestamppb.New(beforeTime.Add(-10 * time.Hour).UTC())
|
farPast := timestamppb.New(beforeTime.Add(-10 * time.Hour).UTC())
|
||||||
|
@ -27,7 +27,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestServer_Limits_Block(t *testing.T) {
|
func TestServer_Limits_Block(t *testing.T) {
|
||||||
domain, instanceID, iamOwnerCtx := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
domain, instanceID, _, iamOwnerCtx := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
||||||
tests := []*test{
|
tests := []*test{
|
||||||
publicAPIBlockingTest(domain),
|
publicAPIBlockingTest(domain),
|
||||||
{
|
{
|
||||||
|
@ -66,7 +66,7 @@ func TestServer_QuotaNotification_Limit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestServer_QuotaNotification_NoLimit(t *testing.T) {
|
func TestServer_QuotaNotification_NoLimit(t *testing.T) {
|
||||||
_, instanceID, IAMOwnerCTX := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
_, instanceID, _, IAMOwnerCTX := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
||||||
amount := 10
|
amount := 10
|
||||||
percent := 50
|
percent := 50
|
||||||
percentAmount := amount * percent / 100
|
percentAmount := amount * percent / 100
|
||||||
@ -148,7 +148,7 @@ func awaitNotification(t *testing.T, bodies chan []byte, unit quota.Unit, percen
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestServer_AddAndRemoveQuota(t *testing.T) {
|
func TestServer_AddAndRemoveQuota(t *testing.T) {
|
||||||
_, instanceID, _ := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
_, instanceID, _, _ := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
||||||
|
|
||||||
got, err := Tester.Client.System.SetQuota(SystemCTX, &system.SetQuotaRequest{
|
got, err := Tester.Client.System.SetQuota(SystemCTX, &system.SetQuotaRequest{
|
||||||
InstanceId: instanceID,
|
InstanceId: instanceID,
|
||||||
|
@ -76,7 +76,7 @@ func newClient(cc *grpc.ClientConn) Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tester) UseIsolatedInstance(tt *testing.T, iamOwnerCtx, systemCtx context.Context) (primaryDomain, instanceId string, authenticatedIamOwnerCtx context.Context) {
|
func (t *Tester) UseIsolatedInstance(tt *testing.T, iamOwnerCtx, systemCtx context.Context) (primaryDomain, instanceId, adminID string, authenticatedIamOwnerCtx context.Context) {
|
||||||
primaryDomain = RandString(5) + ".integration.localhost"
|
primaryDomain = RandString(5) + ".integration.localhost"
|
||||||
instance, err := t.Client.System.CreateInstance(systemCtx, &system.CreateInstanceRequest{
|
instance, err := t.Client.System.CreateInstance(systemCtx, &system.CreateInstanceRequest{
|
||||||
InstanceName: "testinstance",
|
InstanceName: "testinstance",
|
||||||
@ -89,20 +89,23 @@ func (t *Tester) UseIsolatedInstance(tt *testing.T, iamOwnerCtx, systemCtx conte
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
require.NoError(tt, err)
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
t.createClientConn(iamOwnerCtx, fmt.Sprintf("%s:%d", primaryDomain, t.Config.Port))
|
t.createClientConn(iamOwnerCtx, fmt.Sprintf("%s:%d", primaryDomain, t.Config.Port))
|
||||||
instanceId = instance.GetInstanceId()
|
instanceId = instance.GetInstanceId()
|
||||||
|
owner, err := t.Queries.GetUserByLoginName(authz.WithInstanceID(iamOwnerCtx, instanceId), true, "owner@"+primaryDomain)
|
||||||
|
require.NoError(tt, err)
|
||||||
t.Users.Set(instanceId, IAMOwner, &User{
|
t.Users.Set(instanceId, IAMOwner, &User{
|
||||||
|
User: owner,
|
||||||
Token: instance.GetPat(),
|
Token: instance.GetPat(),
|
||||||
})
|
})
|
||||||
newCtx := t.WithInstanceAuthorization(iamOwnerCtx, IAMOwner, instanceId)
|
newCtx := t.WithInstanceAuthorization(iamOwnerCtx, IAMOwner, instanceId)
|
||||||
|
var adminUser *mgmt.ImportHumanUserResponse
|
||||||
// the following serves two purposes:
|
// the following serves two purposes:
|
||||||
// 1. it ensures that the instance is ready to be used
|
// 1. it ensures that the instance is ready to be used
|
||||||
// 2. it enables a normal login with the default admin user credentials
|
// 2. it enables a normal login with the default admin user credentials
|
||||||
require.EventuallyWithT(tt, func(collectT *assert.CollectT) {
|
require.EventuallyWithT(tt, func(collectT *assert.CollectT) {
|
||||||
_, importErr := t.Client.Mgmt.ImportHumanUser(newCtx, &mgmt.ImportHumanUserRequest{
|
var importErr error
|
||||||
|
adminUser, importErr = t.Client.Mgmt.ImportHumanUser(newCtx, &mgmt.ImportHumanUserRequest{
|
||||||
UserName: "zitadel-admin@zitadel.localhost",
|
UserName: "zitadel-admin@zitadel.localhost",
|
||||||
Email: &mgmt.ImportHumanUserRequest_Email{
|
Email: &mgmt.ImportHumanUserRequest_Email{
|
||||||
Email: "zitadel-admin@zitadel.localhost",
|
Email: "zitadel-admin@zitadel.localhost",
|
||||||
@ -117,7 +120,7 @@ func (t *Tester) UseIsolatedInstance(tt *testing.T, iamOwnerCtx, systemCtx conte
|
|||||||
})
|
})
|
||||||
assert.NoError(collectT, importErr)
|
assert.NoError(collectT, importErr)
|
||||||
}, 2*time.Minute, 100*time.Millisecond, "instance not ready")
|
}, 2*time.Minute, 100*time.Millisecond, "instance not ready")
|
||||||
return primaryDomain, instanceId, newCtx
|
return primaryDomain, instanceId, adminUser.GetUserId(), newCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Tester) CreateHumanUser(ctx context.Context) *user.AddHumanUserResponse {
|
func (s *Tester) CreateHumanUser(ctx context.Context) *user.AddHumanUserResponse {
|
||||||
|
@ -151,7 +151,10 @@ func (s *Tester) CreateAPIClientBasic(ctx context.Context, projectID string) (*m
|
|||||||
const CodeVerifier = "codeVerifier"
|
const CodeVerifier = "codeVerifier"
|
||||||
|
|
||||||
func (s *Tester) CreateOIDCAuthRequest(ctx context.Context, clientID, loginClient, redirectURI string, scope ...string) (authRequestID string, err error) {
|
func (s *Tester) CreateOIDCAuthRequest(ctx context.Context, clientID, loginClient, redirectURI string, scope ...string) (authRequestID string, err error) {
|
||||||
provider, err := s.CreateRelyingParty(ctx, clientID, redirectURI, scope...)
|
return s.CreateOIDCAuthRequestWithDomain(ctx, s.Config.ExternalDomain, clientID, loginClient, redirectURI, scope...)
|
||||||
|
}
|
||||||
|
func (s *Tester) CreateOIDCAuthRequestWithDomain(ctx context.Context, domain, clientID, loginClient, redirectURI string, scope ...string) (authRequestID string, err error) {
|
||||||
|
provider, err := s.CreateRelyingPartyForDomain(ctx, domain, clientID, redirectURI, scope...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -212,11 +215,15 @@ func (s *Tester) OIDCIssuer() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Tester) CreateRelyingParty(ctx context.Context, clientID, redirectURI string, scope ...string) (rp.RelyingParty, error) {
|
func (s *Tester) CreateRelyingParty(ctx context.Context, clientID, redirectURI string, scope ...string) (rp.RelyingParty, error) {
|
||||||
|
return s.CreateRelyingPartyForDomain(ctx, s.Config.ExternalDomain, clientID, redirectURI, scope...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Tester) CreateRelyingPartyForDomain(ctx context.Context, domain, clientID, redirectURI string, scope ...string) (rp.RelyingParty, error) {
|
||||||
if len(scope) == 0 {
|
if len(scope) == 0 {
|
||||||
scope = []string{oidc.ScopeOpenID}
|
scope = []string{oidc.ScopeOpenID}
|
||||||
}
|
}
|
||||||
loginClient := &http.Client{Transport: &loginRoundTripper{http.DefaultTransport}}
|
loginClient := &http.Client{Transport: &loginRoundTripper{http.DefaultTransport}}
|
||||||
return rp.NewRelyingPartyOIDC(ctx, s.OIDCIssuer(), clientID, "", redirectURI, scope, rp.WithHTTPClient(loginClient))
|
return rp.NewRelyingPartyOIDC(ctx, http_util.BuildHTTP(domain, s.Config.Port, s.Config.ExternalSecure), clientID, "", redirectURI, scope, rp.WithHTTPClient(loginClient))
|
||||||
}
|
}
|
||||||
|
|
||||||
type loginRoundTripper struct {
|
type loginRoundTripper struct {
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestServer_QuotaNotification_Limit(t *testing.T) {
|
func TestServer_QuotaNotification_Limit(t *testing.T) {
|
||||||
_, instanceID, iamOwnerCtx := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
_, instanceID, _, iamOwnerCtx := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
||||||
amount := 10
|
amount := 10
|
||||||
percent := 50
|
percent := 50
|
||||||
percentAmount := amount * percent / 100
|
percentAmount := amount * percent / 100
|
||||||
@ -67,7 +67,7 @@ func TestServer_QuotaNotification_Limit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestServer_QuotaNotification_NoLimit(t *testing.T) {
|
func TestServer_QuotaNotification_NoLimit(t *testing.T) {
|
||||||
_, instanceID, iamOwnerCtx := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
_, instanceID, _, iamOwnerCtx := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
||||||
amount := 10
|
amount := 10
|
||||||
percent := 50
|
percent := 50
|
||||||
percentAmount := amount * percent / 100
|
percentAmount := amount * percent / 100
|
||||||
|
@ -4,38 +4,126 @@ package handlers_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/zitadel/oidc/v3/pkg/client/rp"
|
||||||
|
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/integration"
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/app"
|
||||||
"github.com/zitadel/zitadel/pkg/grpc/management"
|
"github.com/zitadel/zitadel/pkg/grpc/management"
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/object"
|
||||||
|
oidc_v2 "github.com/zitadel/zitadel/pkg/grpc/oidc/v2beta"
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/project"
|
||||||
"github.com/zitadel/zitadel/pkg/grpc/system"
|
"github.com/zitadel/zitadel/pkg/grpc/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestServer_TelemetryPushMilestones(t *testing.T) {
|
func TestServer_TelemetryPushMilestones(t *testing.T) {
|
||||||
primaryDomain, instanceID, iamOwnerCtx := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
primaryDomain, instanceID, adminID, iamOwnerCtx := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
||||||
t.Log("testing against instance with primary domain", primaryDomain)
|
t.Log("testing against instance with primary domain", primaryDomain)
|
||||||
awaitMilestone(t, Tester.MilestoneChan, primaryDomain, "InstanceCreated")
|
awaitMilestone(t, Tester.MilestoneChan, primaryDomain, "InstanceCreated")
|
||||||
project, err := Tester.Client.Mgmt.AddProject(iamOwnerCtx, &management.AddProjectRequest{Name: "integration"})
|
|
||||||
if err != nil {
|
projectAdded, err := Tester.Client.Mgmt.AddProject(iamOwnerCtx, &management.AddProjectRequest{Name: "integration"})
|
||||||
t.Fatal(err)
|
require.NoError(t, err)
|
||||||
}
|
|
||||||
awaitMilestone(t, Tester.MilestoneChan, primaryDomain, "ProjectCreated")
|
awaitMilestone(t, Tester.MilestoneChan, primaryDomain, "ProjectCreated")
|
||||||
if _, err = Tester.Client.Mgmt.AddOIDCApp(iamOwnerCtx, &management.AddOIDCAppRequest{
|
|
||||||
ProjectId: project.GetId(),
|
redirectURI := "http://localhost:8888"
|
||||||
Name: "integration",
|
application, err := Tester.Client.Mgmt.AddOIDCApp(iamOwnerCtx, &management.AddOIDCAppRequest{
|
||||||
}); err != nil {
|
ProjectId: projectAdded.GetId(),
|
||||||
t.Fatal(err)
|
Name: "integration",
|
||||||
}
|
RedirectUris: []string{redirectURI},
|
||||||
|
ResponseTypes: []app.OIDCResponseType{app.OIDCResponseType_OIDC_RESPONSE_TYPE_CODE},
|
||||||
|
GrantTypes: []app.OIDCGrantType{app.OIDCGrantType_OIDC_GRANT_TYPE_AUTHORIZATION_CODE},
|
||||||
|
AppType: app.OIDCAppType_OIDC_APP_TYPE_WEB,
|
||||||
|
AuthMethodType: app.OIDCAuthMethodType_OIDC_AUTH_METHOD_TYPE_NONE,
|
||||||
|
DevMode: true,
|
||||||
|
AccessTokenType: app.OIDCTokenType_OIDC_TOKEN_TYPE_JWT,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
awaitMilestone(t, Tester.MilestoneChan, primaryDomain, "ApplicationCreated")
|
awaitMilestone(t, Tester.MilestoneChan, primaryDomain, "ApplicationCreated")
|
||||||
// TODO: trigger and await milestone AuthenticationSucceededOnInstance
|
|
||||||
// TODO: trigger and await milestone AuthenticationSucceededOnApplication
|
// create the session to be used for the authN of the clients
|
||||||
if _, err = Tester.Client.System.RemoveInstance(SystemCTX, &system.RemoveInstanceRequest{InstanceId: instanceID}); err != nil {
|
sessionID, sessionToken, _, _ := Tester.CreatePasswordSession(t, iamOwnerCtx, adminID, "Password1!")
|
||||||
t.Fatal(err)
|
|
||||||
}
|
console := consoleOIDCConfig(iamOwnerCtx, t)
|
||||||
|
loginToClient(iamOwnerCtx, t, primaryDomain, console.GetClientId(), instanceID, console.GetRedirectUris()[0], sessionID, sessionToken)
|
||||||
|
awaitMilestone(t, Tester.MilestoneChan, primaryDomain, "AuthenticationSucceededOnInstance")
|
||||||
|
|
||||||
|
// make sure the client has been projected
|
||||||
|
require.EventuallyWithT(t, func(collectT *assert.CollectT) {
|
||||||
|
_, err := Tester.Client.Mgmt.GetAppByID(iamOwnerCtx, &management.GetAppByIDRequest{
|
||||||
|
ProjectId: projectAdded.GetId(),
|
||||||
|
AppId: application.GetAppId(),
|
||||||
|
})
|
||||||
|
assert.NoError(collectT, err)
|
||||||
|
}, 1*time.Minute, 100*time.Millisecond, "app not found")
|
||||||
|
loginToClient(iamOwnerCtx, t, primaryDomain, application.GetClientId(), instanceID, redirectURI, sessionID, sessionToken)
|
||||||
|
awaitMilestone(t, Tester.MilestoneChan, primaryDomain, "AuthenticationSucceededOnApplication")
|
||||||
|
|
||||||
|
_, err = Tester.Client.System.RemoveInstance(SystemCTX, &system.RemoveInstanceRequest{InstanceId: instanceID})
|
||||||
|
require.NoError(t, err)
|
||||||
awaitMilestone(t, Tester.MilestoneChan, primaryDomain, "InstanceDeleted")
|
awaitMilestone(t, Tester.MilestoneChan, primaryDomain, "InstanceDeleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func loginToClient(iamOwnerCtx context.Context, t *testing.T, primaryDomain, clientID, instanceID, redirectURI, sessionID, sessionToken string) {
|
||||||
|
authRequestID, err := Tester.CreateOIDCAuthRequestWithDomain(iamOwnerCtx, primaryDomain, clientID, Tester.Users.Get(instanceID, integration.IAMOwner).ID, redirectURI, "openid")
|
||||||
|
require.NoError(t, err)
|
||||||
|
callback, err := Tester.Client.OIDCv2.CreateCallback(iamOwnerCtx, &oidc_v2.CreateCallbackRequest{
|
||||||
|
AuthRequestId: authRequestID,
|
||||||
|
CallbackKind: &oidc_v2.CreateCallbackRequest_Session{Session: &oidc_v2.Session{
|
||||||
|
SessionId: sessionID,
|
||||||
|
SessionToken: sessionToken,
|
||||||
|
}},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
provider, err := Tester.CreateRelyingPartyForDomain(iamOwnerCtx, primaryDomain, clientID, redirectURI)
|
||||||
|
require.NoError(t, err)
|
||||||
|
callbackURL, err := url.Parse(callback.GetCallbackUrl())
|
||||||
|
require.NoError(t, err)
|
||||||
|
code := callbackURL.Query().Get("code")
|
||||||
|
_, err = rp.CodeExchange[*oidc.IDTokenClaims](iamOwnerCtx, code, provider, rp.WithCodeVerifier(integration.CodeVerifier))
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func consoleOIDCConfig(iamOwnerCtx context.Context, t *testing.T) *app.OIDCConfig {
|
||||||
|
projects, err := Tester.Client.Mgmt.ListProjects(iamOwnerCtx, &management.ListProjectsRequest{
|
||||||
|
Queries: []*project.ProjectQuery{
|
||||||
|
{
|
||||||
|
Query: &project.ProjectQuery_NameQuery{
|
||||||
|
NameQuery: &project.ProjectNameQuery{
|
||||||
|
Name: "ZITADEL",
|
||||||
|
Method: object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, projects.GetResult(), 1)
|
||||||
|
apps, err := Tester.Client.Mgmt.ListApps(iamOwnerCtx, &management.ListAppsRequest{
|
||||||
|
ProjectId: projects.GetResult()[0].GetId(),
|
||||||
|
Queries: []*app.AppQuery{
|
||||||
|
{
|
||||||
|
Query: &app.AppQuery_NameQuery{
|
||||||
|
NameQuery: &app.AppNameQuery{
|
||||||
|
Name: "Console",
|
||||||
|
Method: object.TextQueryMethod_TEXT_QUERY_METHOD_EQUALS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, apps.GetResult(), 1)
|
||||||
|
return apps.GetResult()[0].GetOidcConfig()
|
||||||
|
}
|
||||||
|
|
||||||
func awaitMilestone(t *testing.T, bodies chan []byte, primaryDomain, expectMilestoneType string) {
|
func awaitMilestone(t *testing.T, bodies chan []byte, primaryDomain, expectMilestoneType string) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||||
"github.com/zitadel/zitadel/internal/repository/milestone"
|
"github.com/zitadel/zitadel/internal/repository/milestone"
|
||||||
|
"github.com/zitadel/zitadel/internal/repository/oidcsession"
|
||||||
"github.com/zitadel/zitadel/internal/repository/project"
|
"github.com/zitadel/zitadel/internal/repository/project"
|
||||||
"github.com/zitadel/zitadel/internal/repository/user"
|
"github.com/zitadel/zitadel/internal/repository/user"
|
||||||
)
|
)
|
||||||
@ -104,6 +105,15 @@ func (p *milestoneProjection) Reducers() []handler.AggregateReducer {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Aggregate: oidcsession.AggregateType,
|
||||||
|
EventReducers: []handler.EventReducer{
|
||||||
|
{
|
||||||
|
Event: oidcsession.AddedType,
|
||||||
|
Reduce: p.reduceOIDCSessionAdded,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Aggregate: milestone.AggregateType,
|
Aggregate: milestone.AggregateType,
|
||||||
EventReducers: []handler.EventReducer{
|
EventReducers: []handler.EventReducer{
|
||||||
@ -217,6 +227,40 @@ func (p *milestoneProjection) reduceUserTokenAdded(event eventstore.Event) (*han
|
|||||||
return handler.NewMultiStatement(e, statements...), nil
|
return handler.NewMultiStatement(e, statements...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *milestoneProjection) reduceOIDCSessionAdded(event eventstore.Event) (*handler.Statement, error) {
|
||||||
|
e, err := assertEvent[*oidcsession.AddedEvent](event)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
statements := []func(eventstore.Event) handler.Exec{
|
||||||
|
handler.AddUpdateStatement(
|
||||||
|
[]handler.Column{
|
||||||
|
handler.NewCol(MilestoneColumnReachedDate, event.CreatedAt()),
|
||||||
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(MilestoneColumnInstanceID, event.Aggregate().InstanceID),
|
||||||
|
handler.NewCond(MilestoneColumnType, milestone.AuthenticationSucceededOnInstance),
|
||||||
|
handler.NewIsNullCond(MilestoneColumnReachedDate),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
// We ignore authentications without app, for example JWT profile or PAT
|
||||||
|
if e.ClientID != "" {
|
||||||
|
statements = append(statements, handler.AddUpdateStatement(
|
||||||
|
[]handler.Column{
|
||||||
|
handler.NewCol(MilestoneColumnReachedDate, event.CreatedAt()),
|
||||||
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(MilestoneColumnInstanceID, event.Aggregate().InstanceID),
|
||||||
|
handler.NewCond(MilestoneColumnType, milestone.AuthenticationSucceededOnApplication),
|
||||||
|
handler.Not(handler.NewTextArrayContainsCond(MilestoneColumnIgnoreClientIDs, e.ClientID)),
|
||||||
|
handler.NewIsNullCond(MilestoneColumnReachedDate),
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
return handler.NewMultiStatement(e, statements...), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *milestoneProjection) reduceInstanceRemoved(event eventstore.Event) (*handler.Statement, error) {
|
func (p *milestoneProjection) reduceInstanceRemoved(event eventstore.Event) (*handler.Statement, error) {
|
||||||
if _, err := assertEvent[*instance.InstanceRemovedEvent](event); err != nil {
|
if _, err := assertEvent[*instance.InstanceRemovedEvent](event); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
"github.com/zitadel/zitadel/internal/eventstore/handler/v2"
|
||||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||||
"github.com/zitadel/zitadel/internal/repository/milestone"
|
"github.com/zitadel/zitadel/internal/repository/milestone"
|
||||||
|
"github.com/zitadel/zitadel/internal/repository/oidcsession"
|
||||||
"github.com/zitadel/zitadel/internal/repository/project"
|
"github.com/zitadel/zitadel/internal/repository/project"
|
||||||
"github.com/zitadel/zitadel/internal/repository/user"
|
"github.com/zitadel/zitadel/internal/repository/user"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
@ -294,6 +295,43 @@ func TestMilestonesProjection_reduces(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "reduceOIDCSessionAdded",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(timedTestEvent(
|
||||||
|
oidcsession.AddedType,
|
||||||
|
oidcsession.AggregateType,
|
||||||
|
[]byte(`{"clientID": "client-id"}`),
|
||||||
|
now,
|
||||||
|
), eventstore.GenericEventMapper[oidcsession.AddedEvent]),
|
||||||
|
},
|
||||||
|
reduce: (&milestoneProjection{}).reduceOIDCSessionAdded,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("oidc_session"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.milestones SET reached_date = $1 WHERE (instance_id = $2) AND (type = $3) AND (reached_date IS NULL)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
now,
|
||||||
|
"instance-id",
|
||||||
|
milestone.AuthenticationSucceededOnInstance,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.milestones SET reached_date = $1 WHERE (instance_id = $2) AND (type = $3) AND (NOT (ignore_client_ids @> $4)) AND (reached_date IS NULL)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
now,
|
||||||
|
"instance-id",
|
||||||
|
milestone.AuthenticationSucceededOnApplication,
|
||||||
|
database.TextArray[string]{"client-id"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "reduceInstanceRemoved",
|
name: "reduceInstanceRemoved",
|
||||||
args: args{
|
args: args{
|
||||||
|
Loading…
Reference in New Issue
Block a user