fix: allow start and retrieve IdP intents with IdPs from other organizations (#7871)

* fix: correct resourceowner of intent to instance

* fix: correct resourceowner of intent to instance

* fix: correct resourceowner of intent to instance

* fix: correct resourceowner of intent to instance

* fix: correct resourceowner of intent to instance

* docs: expand the login example with org specific parameters

* fix: existence of idp is not checked through resourceowner

* fix: existence of idp is not checked through resourceowner

* fix: existence of idp is not checked through resourceowner

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
Stefan Benz 2024-05-07 08:11:20 +02:00 committed by GitHub
parent 5bf195d374
commit 72c5b057f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 439 additions and 156 deletions

View File

@ -41,7 +41,7 @@ func TestMain(m *testing.M) {
} }
func TestServer_AddOrganization(t *testing.T) { func TestServer_AddOrganization(t *testing.T) {
idpID := Tester.AddGenericOAuthProvider(t) idpID := Tester.AddGenericOAuthProvider(t, CTX)
tests := []struct { tests := []struct {
name string name string

View File

@ -361,8 +361,7 @@ func TestServer_CreateSession_webauthn(t *testing.T) {
} }
func TestServer_CreateSession_successfulIntent(t *testing.T) { func TestServer_CreateSession_successfulIntent(t *testing.T) {
idpID := Tester.AddGenericOAuthProvider(t) idpID := Tester.AddGenericOAuthProvider(t, CTX)
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{ createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
Checks: &session.Checks{ Checks: &session.Checks{
User: &session.CheckUser{ User: &session.CheckUser{
@ -375,7 +374,7 @@ func TestServer_CreateSession_successfulIntent(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0) verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
intentID, token, _, _ := Tester.CreateSuccessfulOAuthIntent(t, idpID, User.GetUserId(), "id") intentID, token, _, _ := Tester.CreateSuccessfulOAuthIntent(t, CTX, idpID, User.GetUserId(), "id")
updateResp, err := Client.SetSession(CTX, &session.SetSessionRequest{ updateResp, err := Client.SetSession(CTX, &session.SetSessionRequest{
SessionId: createResp.GetSessionId(), SessionId: createResp.GetSessionId(),
SessionToken: createResp.GetSessionToken(), SessionToken: createResp.GetSessionToken(),
@ -391,9 +390,9 @@ func TestServer_CreateSession_successfulIntent(t *testing.T) {
} }
func TestServer_CreateSession_successfulIntent_instant(t *testing.T) { func TestServer_CreateSession_successfulIntent_instant(t *testing.T) {
idpID := Tester.AddGenericOAuthProvider(t) idpID := Tester.AddGenericOAuthProvider(t, CTX)
intentID, token, _, _ := Tester.CreateSuccessfulOAuthIntent(t, idpID, User.GetUserId(), "id") intentID, token, _, _ := Tester.CreateSuccessfulOAuthIntent(t, CTX, idpID, User.GetUserId(), "id")
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{ createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
Checks: &session.Checks{ Checks: &session.Checks{
User: &session.CheckUser{ User: &session.CheckUser{
@ -412,7 +411,7 @@ func TestServer_CreateSession_successfulIntent_instant(t *testing.T) {
} }
func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) { func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
idpID := Tester.AddGenericOAuthProvider(t) idpID := Tester.AddGenericOAuthProvider(t, CTX)
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{ createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
Checks: &session.Checks{ Checks: &session.Checks{
@ -427,7 +426,7 @@ func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0) verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
idpUserID := "id" idpUserID := "id"
intentID, token, _, _ := Tester.CreateSuccessfulOAuthIntent(t, idpID, "", idpUserID) intentID, token, _, _ := Tester.CreateSuccessfulOAuthIntent(t, CTX, idpID, "", idpUserID)
updateResp, err := Client.SetSession(CTX, &session.SetSessionRequest{ updateResp, err := Client.SetSession(CTX, &session.SetSessionRequest{
SessionId: createResp.GetSessionId(), SessionId: createResp.GetSessionId(),
SessionToken: createResp.GetSessionToken(), SessionToken: createResp.GetSessionToken(),
@ -440,6 +439,7 @@ func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
}) })
require.Error(t, err) require.Error(t, err)
Tester.CreateUserIDPlink(CTX, User.GetUserId(), idpUserID, idpID, User.GetUserId()) Tester.CreateUserIDPlink(CTX, User.GetUserId(), idpUserID, idpID, User.GetUserId())
intentID, token, _, _ = Tester.CreateSuccessfulOAuthIntent(t, CTX, idpID, User.GetUserId(), idpUserID)
updateResp, err = Client.SetSession(CTX, &session.SetSessionRequest{ updateResp, err = Client.SetSession(CTX, &session.SetSessionRequest{
SessionId: createResp.GetSessionId(), SessionId: createResp.GetSessionId(),
SessionToken: createResp.GetSessionToken(), SessionToken: createResp.GetSessionToken(),
@ -455,7 +455,7 @@ func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
} }
func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) { func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) {
idpID := Tester.AddGenericOAuthProvider(t) idpID := Tester.AddGenericOAuthProvider(t, CTX)
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{ createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
Checks: &session.Checks{ Checks: &session.Checks{
@ -469,7 +469,7 @@ func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0) verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
intentID := Tester.CreateIntent(t, idpID) intentID := Tester.CreateIntent(t, CTX, idpID)
_, err = Client.SetSession(CTX, &session.SetSessionRequest{ _, err = Client.SetSession(CTX, &session.SetSessionRequest{
SessionId: createResp.GetSessionId(), SessionId: createResp.GetSessionId(),
SessionToken: createResp.GetSessionToken(), SessionToken: createResp.GetSessionToken(),

View File

@ -370,7 +370,7 @@ func (s *Server) StartIdentityProviderIntent(ctx context.Context, req *user.Star
} }
func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.RedirectURLs) (*user.StartIdentityProviderIntentResponse, error) { func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.RedirectURLs) (*user.StartIdentityProviderIntentResponse, error) {
intentWriteModel, details, err := s.command.CreateIntent(ctx, idpID, urls.GetSuccessUrl(), urls.GetFailureUrl(), authz.GetCtxData(ctx).OrgID) intentWriteModel, details, err := s.command.CreateIntent(ctx, idpID, urls.GetSuccessUrl(), urls.GetFailureUrl(), authz.GetInstance(ctx).InstanceID())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -394,7 +394,7 @@ func (s *Server) startIDPIntent(ctx context.Context, idpID string, urls *user.Re
} }
func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredentials *user.LDAPCredentials) (*user.StartIdentityProviderIntentResponse, error) { func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredentials *user.LDAPCredentials) (*user.StartIdentityProviderIntentResponse, error) {
intentWriteModel, details, err := s.command.CreateIntent(ctx, idpID, "", "", authz.GetCtxData(ctx).OrgID) intentWriteModel, details, err := s.command.CreateIntent(ctx, idpID, "", "", authz.GetInstance(ctx).InstanceID())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -473,7 +473,7 @@ func (s *Server) ldapLogin(ctx context.Context, idpID, username, password string
} }
func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.RetrieveIdentityProviderIntentRequest) (_ *user.RetrieveIdentityProviderIntentResponse, err error) { func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.RetrieveIdentityProviderIntentRequest) (_ *user.RetrieveIdentityProviderIntentResponse, err error) {
intent, err := s.command.GetIntentWriteModel(ctx, req.GetIdpIntentId(), authz.GetCtxData(ctx).OrgID) intent, err := s.command.GetIntentWriteModel(ctx, req.GetIdpIntentId(), "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -481,7 +481,7 @@ func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.R
return nil, err return nil, err
} }
if intent.State != domain.IDPIntentStateSucceeded { if intent.State != domain.IDPIntentStateSucceeded {
return nil, zerrors.ThrowPreconditionFailed(nil, "IDP-Hk38e", "Errors.Intent.NotSucceeded") return nil, zerrors.ThrowPreconditionFailed(nil, "IDP-nme4gszsvx", "Errors.Intent.NotSucceeded")
} }
return idpIntentToIDPIntentPb(intent, s.idpAlg) return idpIntentToIDPIntentPb(intent, s.idpAlg)
} }

View File

@ -54,7 +54,7 @@ func TestMain(m *testing.M) {
} }
func TestServer_AddHumanUser(t *testing.T) { func TestServer_AddHumanUser(t *testing.T) {
idpID := Tester.AddGenericOAuthProvider(t) idpID := Tester.AddGenericOAuthProvider(t, CTX)
type args struct { type args struct {
ctx context.Context ctx context.Context
req *user.AddHumanUserRequest req *user.AddHumanUserRequest
@ -1752,7 +1752,7 @@ func TestServer_DeleteUser(t *testing.T) {
} }
func TestServer_AddIDPLink(t *testing.T) { func TestServer_AddIDPLink(t *testing.T) {
idpID := Tester.AddGenericOAuthProvider(t) idpID := Tester.AddGenericOAuthProvider(t, CTX)
type args struct { type args struct {
ctx context.Context ctx context.Context
req *user.AddIDPLinkRequest req *user.AddIDPLinkRequest
@ -1832,10 +1832,13 @@ func TestServer_AddIDPLink(t *testing.T) {
} }
func TestServer_StartIdentityProviderIntent(t *testing.T) { func TestServer_StartIdentityProviderIntent(t *testing.T) {
idpID := Tester.AddGenericOAuthProvider(t) idpID := Tester.AddGenericOAuthProvider(t, CTX)
samlIdpID := Tester.AddSAMLProvider(t) orgIdpID := Tester.AddOrgGenericOAuthProvider(t, CTX, Tester.Organisation.ID)
samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t) orgResp := Tester.CreateOrganization(IamCTX, fmt.Sprintf("NotDefaultOrg%d", time.Now().UnixNano()), fmt.Sprintf("%d@mouse.com", time.Now().UnixNano()))
samlPostIdpID := Tester.AddSAMLPostProvider(t) notDefaultOrgIdpID := Tester.AddOrgGenericOAuthProvider(t, CTX, orgResp.OrganizationId)
samlIdpID := Tester.AddSAMLProvider(t, CTX)
samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t, CTX)
samlPostIdpID := Tester.AddSAMLPostProvider(t, CTX)
type args struct { type args struct {
ctx context.Context ctx context.Context
req *user.StartIdentityProviderIntentRequest req *user.StartIdentityProviderIntentRequest
@ -1880,7 +1883,100 @@ func TestServer_StartIdentityProviderIntent(t *testing.T) {
want: want{ want: want{
details: &object.Details{ details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Organisation.ID, ResourceOwner: Tester.Instance.InstanceID(),
},
url: "https://example.com/oauth/v2/authorize",
parametersEqual: map[string]string{
"client_id": "clientID",
"prompt": "select_account",
"redirect_uri": "http://" + Tester.Config.ExternalDomain + ":8080/idps/callback",
"response_type": "code",
"scope": "openid profile email",
},
parametersExisting: []string{"state"},
},
wantErr: false,
},
{
name: "next step oauth auth url, default org",
args: args{
CTX,
&user.StartIdentityProviderIntentRequest{
IdpId: orgIdpID,
Content: &user.StartIdentityProviderIntentRequest_Urls{
Urls: &user.RedirectURLs{
SuccessUrl: "https://example.com/success",
FailureUrl: "https://example.com/failure",
},
},
},
},
want: want{
details: &object.Details{
ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(),
},
url: "https://example.com/oauth/v2/authorize",
parametersEqual: map[string]string{
"client_id": "clientID",
"prompt": "select_account",
"redirect_uri": "http://" + Tester.Config.ExternalDomain + ":8080/idps/callback",
"response_type": "code",
"scope": "openid profile email",
},
parametersExisting: []string{"state"},
},
wantErr: false,
},
{
name: "next step oauth auth url, default org",
args: args{
CTX,
&user.StartIdentityProviderIntentRequest{
IdpId: notDefaultOrgIdpID,
Content: &user.StartIdentityProviderIntentRequest_Urls{
Urls: &user.RedirectURLs{
SuccessUrl: "https://example.com/success",
FailureUrl: "https://example.com/failure",
},
},
},
},
want: want{
details: &object.Details{
ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(),
},
url: "https://example.com/oauth/v2/authorize",
parametersEqual: map[string]string{
"client_id": "clientID",
"prompt": "select_account",
"redirect_uri": "http://" + Tester.Config.ExternalDomain + ":8080/idps/callback",
"response_type": "code",
"scope": "openid profile email",
},
parametersExisting: []string{"state"},
},
wantErr: false,
},
{
name: "next step oauth auth url org",
args: args{
CTX,
&user.StartIdentityProviderIntentRequest{
IdpId: orgIdpID,
Content: &user.StartIdentityProviderIntentRequest_Urls{
Urls: &user.RedirectURLs{
SuccessUrl: "https://example.com/success",
FailureUrl: "https://example.com/failure",
},
},
},
},
want: want{
details: &object.Details{
ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Instance.InstanceID(),
}, },
url: "https://example.com/oauth/v2/authorize", url: "https://example.com/oauth/v2/authorize",
parametersEqual: map[string]string{ parametersEqual: map[string]string{
@ -1911,7 +2007,7 @@ func TestServer_StartIdentityProviderIntent(t *testing.T) {
want: want{ want: want{
details: &object.Details{ details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Organisation.ID, ResourceOwner: Tester.Instance.InstanceID(),
}, },
url: "http://" + Tester.Config.ExternalDomain + ":8000/sso", url: "http://" + Tester.Config.ExternalDomain + ":8000/sso",
parametersExisting: []string{"RelayState", "SAMLRequest"}, parametersExisting: []string{"RelayState", "SAMLRequest"},
@ -1935,7 +2031,7 @@ func TestServer_StartIdentityProviderIntent(t *testing.T) {
want: want{ want: want{
details: &object.Details{ details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Organisation.ID, ResourceOwner: Tester.Instance.InstanceID(),
}, },
url: "http://" + Tester.Config.ExternalDomain + ":8000/sso", url: "http://" + Tester.Config.ExternalDomain + ":8000/sso",
parametersExisting: []string{"RelayState", "SAMLRequest"}, parametersExisting: []string{"RelayState", "SAMLRequest"},
@ -1959,7 +2055,7 @@ func TestServer_StartIdentityProviderIntent(t *testing.T) {
want: want{ want: want{
details: &object.Details{ details: &object.Details{
ChangeDate: timestamppb.Now(), ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Organisation.ID, ResourceOwner: Tester.Instance.InstanceID(),
}, },
postForm: true, postForm: true,
}, },
@ -1999,13 +2095,13 @@ func TestServer_StartIdentityProviderIntent(t *testing.T) {
} }
func TestServer_RetrieveIdentityProviderIntent(t *testing.T) { func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
idpID := Tester.AddGenericOAuthProvider(t) idpID := Tester.AddGenericOAuthProvider(t, CTX)
intentID := Tester.CreateIntent(t, idpID) intentID := Tester.CreateIntent(t, CTX, idpID)
successfulID, token, changeDate, sequence := Tester.CreateSuccessfulOAuthIntent(t, idpID, "", "id") successfulID, token, changeDate, sequence := Tester.CreateSuccessfulOAuthIntent(t, CTX, idpID, "", "id")
successfulWithUserID, WithUsertoken, WithUserchangeDate, WithUsersequence := Tester.CreateSuccessfulOAuthIntent(t, idpID, "user", "id") successfulWithUserID, withUsertoken, withUserchangeDate, withUsersequence := Tester.CreateSuccessfulOAuthIntent(t, CTX, idpID, "user", "id")
ldapSuccessfulID, ldapToken, ldapChangeDate, ldapSequence := Tester.CreateSuccessfulLDAPIntent(t, idpID, "", "id") ldapSuccessfulID, ldapToken, ldapChangeDate, ldapSequence := Tester.CreateSuccessfulLDAPIntent(t, CTX, idpID, "", "id")
ldapSuccessfulWithUserID, ldapWithUserToken, ldapWithUserChangeDate, ldapWithUserSequence := Tester.CreateSuccessfulLDAPIntent(t, idpID, "user", "id") ldapSuccessfulWithUserID, ldapWithUserToken, ldapWithUserChangeDate, ldapWithUserSequence := Tester.CreateSuccessfulLDAPIntent(t, CTX, idpID, "user", "id")
samlSuccessfulID, samlToken, samlChangeDate, samlSequence := Tester.CreateSuccessfulSAMLIntent(t, idpID, "", "id") samlSuccessfulID, samlToken, samlChangeDate, samlSequence := Tester.CreateSuccessfulSAMLIntent(t, CTX, idpID, "", "id")
type args struct { type args struct {
ctx context.Context ctx context.Context
req *user.RetrieveIdentityProviderIntentRequest req *user.RetrieveIdentityProviderIntentRequest
@ -2050,7 +2146,7 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
want: &user.RetrieveIdentityProviderIntentResponse{ want: &user.RetrieveIdentityProviderIntentResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.New(changeDate), ChangeDate: timestamppb.New(changeDate),
ResourceOwner: Tester.Organisation.ID, ResourceOwner: Tester.Instance.InstanceID(),
Sequence: sequence, Sequence: sequence,
}, },
IdpInformation: &user.IDPInformation{ IdpInformation: &user.IDPInformation{
@ -2081,14 +2177,14 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
CTX, CTX,
&user.RetrieveIdentityProviderIntentRequest{ &user.RetrieveIdentityProviderIntentRequest{
IdpIntentId: successfulWithUserID, IdpIntentId: successfulWithUserID,
IdpIntentToken: WithUsertoken, IdpIntentToken: withUsertoken,
}, },
}, },
want: &user.RetrieveIdentityProviderIntentResponse{ want: &user.RetrieveIdentityProviderIntentResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.New(WithUserchangeDate), ChangeDate: timestamppb.New(withUserchangeDate),
ResourceOwner: Tester.Organisation.ID, ResourceOwner: Tester.Instance.InstanceID(),
Sequence: WithUsersequence, Sequence: withUsersequence,
}, },
UserId: "user", UserId: "user",
IdpInformation: &user.IDPInformation{ IdpInformation: &user.IDPInformation{
@ -2125,7 +2221,7 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
want: &user.RetrieveIdentityProviderIntentResponse{ want: &user.RetrieveIdentityProviderIntentResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.New(ldapChangeDate), ChangeDate: timestamppb.New(ldapChangeDate),
ResourceOwner: Tester.Organisation.ID, ResourceOwner: Tester.Instance.InstanceID(),
Sequence: ldapSequence, Sequence: ldapSequence,
}, },
IdpInformation: &user.IDPInformation{ IdpInformation: &user.IDPInformation{
@ -2170,7 +2266,7 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
want: &user.RetrieveIdentityProviderIntentResponse{ want: &user.RetrieveIdentityProviderIntentResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.New(ldapWithUserChangeDate), ChangeDate: timestamppb.New(ldapWithUserChangeDate),
ResourceOwner: Tester.Organisation.ID, ResourceOwner: Tester.Instance.InstanceID(),
Sequence: ldapWithUserSequence, Sequence: ldapWithUserSequence,
}, },
UserId: "user", UserId: "user",
@ -2216,7 +2312,7 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
want: &user.RetrieveIdentityProviderIntentResponse{ want: &user.RetrieveIdentityProviderIntentResponse{
Details: &object.Details{ Details: &object.Details{
ChangeDate: timestamppb.New(samlChangeDate), ChangeDate: timestamppb.New(samlChangeDate),
ResourceOwner: Tester.Organisation.ID, ResourceOwner: Tester.Instance.InstanceID(),
Sequence: samlSequence, Sequence: samlSequence,
}, },
IdpInformation: &user.IDPInformation{ IdpInformation: &user.IDPInformation{

View File

@ -52,8 +52,8 @@ func TestMain(m *testing.M) {
} }
func TestServer_SAMLCertificate(t *testing.T) { func TestServer_SAMLCertificate(t *testing.T) {
samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t) samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t, CTX)
oauthIdpID := Tester.AddGenericOAuthProvider(t) oauthIdpID := Tester.AddGenericOAuthProvider(t, CTX)
type args struct { type args struct {
ctx context.Context ctx context.Context
@ -109,8 +109,8 @@ func TestServer_SAMLCertificate(t *testing.T) {
} }
func TestServer_SAMLMetadata(t *testing.T) { func TestServer_SAMLMetadata(t *testing.T) {
samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t) samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t, CTX)
oauthIdpID := Tester.AddGenericOAuthProvider(t) oauthIdpID := Tester.AddGenericOAuthProvider(t, CTX)
type args struct { type args struct {
ctx context.Context ctx context.Context
@ -167,7 +167,7 @@ func TestServer_SAMLMetadata(t *testing.T) {
func TestServer_SAMLACS(t *testing.T) { func TestServer_SAMLACS(t *testing.T) {
userHuman := Tester.CreateHumanUser(CTX) userHuman := Tester.CreateHumanUser(CTX)
samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t) samlRedirectIdpID := Tester.AddSAMLRedirectProvider(t, CTX)
externalUserID := "test1" externalUserID := "test1"
linkedExternalUserID := "test2" linkedExternalUserID := "test2"
Tester.CreateUserIDPlink(CTX, userHuman.UserId, linkedExternalUserID, samlRedirectIdpID, linkedExternalUserID) Tester.CreateUserIDPlink(CTX, userHuman.UserId, linkedExternalUserID, samlRedirectIdpID, linkedExternalUserID)

View File

@ -4,7 +4,6 @@ import (
"context" "context"
"time" "time"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/command/preparation" "github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/repository/idp" "github.com/zitadel/zitadel/internal/repository/idp"
"github.com/zitadel/zitadel/internal/zerrors" "github.com/zitadel/zitadel/internal/zerrors"
@ -129,7 +128,8 @@ type AppleProvider struct {
IDPOptions idp.Options IDPOptions idp.Options
} }
func ExistsIDP(ctx context.Context, filter preparation.FilterToQueryReducer, id, orgID string) (exists bool, err error) { // ExistsIDPOnOrgOrInstance query first org level IDPs and then instance level IDPs, no check if the IDP is active
func ExistsIDPOnOrgOrInstance(ctx context.Context, filter preparation.FilterToQueryReducer, instanceID, orgID, id string) (exists bool, err error) {
writeModel := NewOrgIDPRemoveWriteModel(orgID, id) writeModel := NewOrgIDPRemoveWriteModel(orgID, id)
events, err := filter(ctx, writeModel.Query()) events, err := filter(ctx, writeModel.Query())
if err != nil { if err != nil {
@ -144,7 +144,7 @@ func ExistsIDP(ctx context.Context, filter preparation.FilterToQueryReducer, id,
return writeModel.State.Exists(), nil return writeModel.State.Exists(), nil
} }
instanceWriteModel := NewInstanceIDPRemoveWriteModel(authz.GetInstance(ctx).InstanceID(), id) instanceWriteModel := NewInstanceIDPRemoveWriteModel(instanceID, id)
events, err = filter(ctx, instanceWriteModel.Query()) events, err = filter(ctx, instanceWriteModel.Query())
if err != nil { if err != nil {
return false, err return false, err
@ -160,6 +160,23 @@ func ExistsIDP(ctx context.Context, filter preparation.FilterToQueryReducer, id,
return instanceWriteModel.State.Exists(), nil return instanceWriteModel.State.Exists(), nil
} }
// ExistsIDP query IDPs only with the ID, no check if the IDP is active
func ExistsIDP(ctx context.Context, filter preparation.FilterToQueryReducer, id string) (exists bool, err error) {
writeModel := NewIDPTypeWriteModel(id)
events, err := filter(ctx, writeModel.Query())
if err != nil {
return false, err
}
if len(events) == 0 {
return false, nil
}
writeModel.AppendEvents(events...)
if err := writeModel.Reduce(); err != nil {
return false, err
}
return writeModel.State.Exists(), nil
}
func IDPProviderWriteModel(ctx context.Context, filter preparation.FilterToQueryReducer, id string) (_ *AllIDPWriteModel, err error) { func IDPProviderWriteModel(ctx context.Context, filter preparation.FilterToQueryReducer, id string) (_ *AllIDPWriteModel, err error) {
writeModel := NewIDPTypeWriteModel(id) writeModel := NewIDPTypeWriteModel(id)
events, err := filter(ctx, writeModel.Query()) events, err := filter(ctx, writeModel.Query())

View File

@ -25,7 +25,7 @@ import (
"github.com/zitadel/zitadel/internal/zerrors" "github.com/zitadel/zitadel/internal/zerrors"
) )
func (c *Commands) prepareCreateIntent(writeModel *IDPIntentWriteModel, idpID string, successURL, failureURL string) preparation.Validation { func (c *Commands) prepareCreateIntent(writeModel *IDPIntentWriteModel, idpID, successURL, failureURL string) preparation.Validation {
return func() (_ preparation.CreateCommands, err error) { return func() (_ preparation.CreateCommands, err error) {
if idpID == "" { if idpID == "" {
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-x8j2bk", "Errors.Intent.IDPMissing") return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-x8j2bk", "Errors.Intent.IDPMissing")
@ -43,12 +43,17 @@ func (c *Commands) prepareCreateIntent(writeModel *IDPIntentWriteModel, idpID st
if err != nil { if err != nil {
return nil, err return nil, err
} }
exists, err := ExistsIDP(ctx, filter, idpID, writeModel.ResourceOwner) exists, err := ExistsIDP(ctx, filter, idpID)
if !exists || err != nil { if !exists || err != nil {
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-39n221fs", "Errors.IDPConfig.NotExisting") return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-39n221fs", "Errors.IDPConfig.NotExisting")
} }
return []eventstore.Command{ return []eventstore.Command{
idpintent.NewStartedEvent(ctx, writeModel.aggregate, successURL, failureURL, idpID), idpintent.NewStartedEvent(ctx,
IDPIntentAggregateFromWriteModel(&writeModel.WriteModel),
successURL,
failureURL,
idpID,
),
}, nil }, nil
}, nil }, nil
} }
@ -64,6 +69,7 @@ func (c *Commands) CreateIntent(ctx context.Context, idpID, successURL, failureU
return nil, nil, err return nil, nil, err
} }
//nolint: staticcheck
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareCreateIntent(writeModel, idpID, successURL, failureURL)) cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, c.prepareCreateIntent(writeModel, idpID, successURL, failureURL))
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -117,7 +123,7 @@ func (c *Commands) GetActiveIntent(ctx context.Context, intentID string) (*IDPIn
return nil, err return nil, err
} }
if intent.State == domain.IDPIntentStateUnspecified { if intent.State == domain.IDPIntentStateUnspecified {
return nil, zerrors.ThrowNotFound(nil, "IDP-Hk38e", "Errors.Intent.NotStarted") return nil, zerrors.ThrowNotFound(nil, "IDP-gy3ctgkqe7", "Errors.Intent.NotStarted")
} }
if intent.State != domain.IDPIntentStateStarted { if intent.State != domain.IDPIntentStateStarted {
return nil, zerrors.ThrowInvalidArgument(nil, "IDP-Sfrgs", "Errors.Intent.NotStarted") return nil, zerrors.ThrowInvalidArgument(nil, "IDP-Sfrgs", "Errors.Intent.NotStarted")
@ -166,7 +172,7 @@ func (c *Commands) SucceedIDPIntent(ctx context.Context, writeModel *IDPIntentWr
} }
cmd := idpintent.NewSucceededEvent( cmd := idpintent.NewSucceededEvent(
ctx, ctx,
&idpintent.NewAggregate(writeModel.AggregateID, writeModel.ResourceOwner).Aggregate, IDPIntentAggregateFromWriteModel(&writeModel.WriteModel),
idpInfo, idpInfo,
idpUser.GetID(), idpUser.GetID(),
idpUser.GetPreferredUsername(), idpUser.GetPreferredUsername(),
@ -200,7 +206,7 @@ func (c *Commands) SucceedSAMLIDPIntent(ctx context.Context, writeModel *IDPInte
} }
cmd := idpintent.NewSAMLSucceededEvent( cmd := idpintent.NewSAMLSucceededEvent(
ctx, ctx,
&idpintent.NewAggregate(writeModel.AggregateID, writeModel.ResourceOwner).Aggregate, IDPIntentAggregateFromWriteModel(&writeModel.WriteModel),
idpInfo, idpInfo,
idpUser.GetID(), idpUser.GetID(),
idpUser.GetPreferredUsername(), idpUser.GetPreferredUsername(),
@ -217,7 +223,7 @@ func (c *Commands) SucceedSAMLIDPIntent(ctx context.Context, writeModel *IDPInte
func (c *Commands) RequestSAMLIDPIntent(ctx context.Context, writeModel *IDPIntentWriteModel, requestID string) error { func (c *Commands) RequestSAMLIDPIntent(ctx context.Context, writeModel *IDPIntentWriteModel, requestID string) error {
return c.pushAppendAndReduce(ctx, writeModel, idpintent.NewSAMLRequestEvent( return c.pushAppendAndReduce(ctx, writeModel, idpintent.NewSAMLRequestEvent(
ctx, ctx,
&idpintent.NewAggregate(writeModel.AggregateID, writeModel.ResourceOwner).Aggregate, IDPIntentAggregateFromWriteModel(&writeModel.WriteModel),
requestID, requestID,
)) ))
} }
@ -241,7 +247,7 @@ func (c *Commands) SucceedLDAPIDPIntent(ctx context.Context, writeModel *IDPInte
} }
cmd := idpintent.NewLDAPSucceededEvent( cmd := idpintent.NewLDAPSucceededEvent(
ctx, ctx,
&idpintent.NewAggregate(writeModel.AggregateID, writeModel.ResourceOwner).Aggregate, IDPIntentAggregateFromWriteModel(&writeModel.WriteModel),
idpInfo, idpInfo,
idpUser.GetID(), idpUser.GetID(),
idpUser.GetPreferredUsername(), idpUser.GetPreferredUsername(),
@ -258,7 +264,7 @@ func (c *Commands) SucceedLDAPIDPIntent(ctx context.Context, writeModel *IDPInte
func (c *Commands) FailIDPIntent(ctx context.Context, writeModel *IDPIntentWriteModel, reason string) error { func (c *Commands) FailIDPIntent(ctx context.Context, writeModel *IDPIntentWriteModel, reason string) error {
cmd := idpintent.NewFailedEvent( cmd := idpintent.NewFailedEvent(
ctx, ctx,
&idpintent.NewAggregate(writeModel.AggregateID, writeModel.ResourceOwner).Aggregate, IDPIntentAggregateFromWriteModel(&writeModel.WriteModel),
reason, reason,
) )
_, err := c.eventstore.Push(ctx, cmd) _, err := c.eventstore.Push(ctx, cmd)

View File

@ -28,8 +28,7 @@ type IDPIntentWriteModel struct {
RequestID string RequestID string
Assertion *crypto.CryptoValue Assertion *crypto.CryptoValue
State domain.IDPIntentState State domain.IDPIntentState
aggregate *eventstore.Aggregate
} }
func NewIDPIntentWriteModel(id, resourceOwner string) *IDPIntentWriteModel { func NewIDPIntentWriteModel(id, resourceOwner string) *IDPIntentWriteModel {
@ -38,7 +37,6 @@ func NewIDPIntentWriteModel(id, resourceOwner string) *IDPIntentWriteModel {
AggregateID: id, AggregateID: id,
ResourceOwner: resourceOwner, ResourceOwner: resourceOwner,
}, },
aggregate: &idpintent.NewAggregate(id, resourceOwner).Aggregate,
} }
} }
@ -121,3 +119,13 @@ func (wm *IDPIntentWriteModel) reduceSAMLRequestEvent(e *idpintent.SAMLRequestEv
func (wm *IDPIntentWriteModel) reduceFailedEvent(e *idpintent.FailedEvent) { func (wm *IDPIntentWriteModel) reduceFailedEvent(e *idpintent.FailedEvent) {
wm.State = domain.IDPIntentStateFailed wm.State = domain.IDPIntentStateFailed
} }
func IDPIntentAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate {
return &eventstore.Aggregate{
Type: idpintent.AggregateType,
Version: idpintent.AggregateVersion,
ID: wm.AggregateID,
ResourceOwner: wm.ResourceOwner,
InstanceID: wm.InstanceID,
}
}

View File

@ -28,20 +28,21 @@ import (
rep_idp "github.com/zitadel/zitadel/internal/repository/idp" rep_idp "github.com/zitadel/zitadel/internal/repository/idp"
"github.com/zitadel/zitadel/internal/repository/idpintent" "github.com/zitadel/zitadel/internal/repository/idpintent"
"github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/repository/instance"
"github.com/zitadel/zitadel/internal/repository/org"
"github.com/zitadel/zitadel/internal/zerrors" "github.com/zitadel/zitadel/internal/zerrors"
) )
func TestCommands_CreateIntent(t *testing.T) { func TestCommands_CreateIntent(t *testing.T) {
type fields struct { type fields struct {
eventstore *eventstore.Eventstore eventstore func(t *testing.T) *eventstore.Eventstore
idGenerator id.Generator idGenerator id.Generator
} }
type args struct { type args struct {
ctx context.Context ctx context.Context
idpID string idpID string
successURL string successURL string
failureURL string failureURL string
resourceOwner string instanceID string
} }
type res struct { type res struct {
intentID string intentID string
@ -57,11 +58,11 @@ func TestCommands_CreateIntent(t *testing.T) {
{ {
"error no id generator", "error no id generator",
fields{ fields{
eventstore: eventstoreExpect(t), eventstore: expectEventstore(),
idGenerator: mock.NewIDGeneratorExpectError(t, zerrors.ThrowInternal(nil, "", "error id")), idGenerator: mock.NewIDGeneratorExpectError(t, zerrors.ThrowInternal(nil, "", "error id")),
}, },
args{ args{
ctx: authz.SetCtxData(context.Background(), authz.CtxData{OrgID: "ro"}), ctx: context.Background(),
idpID: "", idpID: "",
successURL: "https://success.url", successURL: "https://success.url",
failureURL: "https://failure.url", failureURL: "https://failure.url",
@ -73,11 +74,11 @@ func TestCommands_CreateIntent(t *testing.T) {
{ {
"error no idpID", "error no idpID",
fields{ fields{
eventstore: eventstoreExpect(t), eventstore: expectEventstore(),
idGenerator: mock.ExpectID(t, "id"), idGenerator: mock.ExpectID(t, "id"),
}, },
args{ args{
ctx: authz.SetCtxData(context.Background(), authz.CtxData{OrgID: "ro"}), ctx: context.Background(),
idpID: "", idpID: "",
successURL: "https://success.url", successURL: "https://success.url",
failureURL: "https://failure.url", failureURL: "https://failure.url",
@ -89,11 +90,11 @@ func TestCommands_CreateIntent(t *testing.T) {
{ {
"error no successURL", "error no successURL",
fields{ fields{
eventstore: eventstoreExpect(t), eventstore: expectEventstore(),
idGenerator: mock.ExpectID(t, "id"), idGenerator: mock.ExpectID(t, "id"),
}, },
args{ args{
ctx: authz.SetCtxData(context.Background(), authz.CtxData{OrgID: "ro"}), ctx: context.Background(),
idpID: "idp", idpID: "idp",
successURL: ":", successURL: ":",
failureURL: "https://failure.url", failureURL: "https://failure.url",
@ -105,11 +106,11 @@ func TestCommands_CreateIntent(t *testing.T) {
{ {
"error no failureURL", "error no failureURL",
fields{ fields{
eventstore: eventstoreExpect(t), eventstore: expectEventstore(),
idGenerator: mock.ExpectID(t, "id"), idGenerator: mock.ExpectID(t, "id"),
}, },
args{ args{
ctx: authz.SetCtxData(context.Background(), authz.CtxData{OrgID: "ro"}), ctx: context.Background(),
idpID: "idp", idpID: "idp",
successURL: "https://success.url", successURL: "https://success.url",
failureURL: ":", failureURL: ":",
@ -119,18 +120,18 @@ func TestCommands_CreateIntent(t *testing.T) {
}, },
}, },
{ {
"error idp not existing", "error idp not existing org",
fields{ fields{
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectFilter(),
expectFilter(), expectFilter(),
expectFilter(), expectFilter(),
), ),
idGenerator: mock.ExpectID(t, "id"), idGenerator: mock.ExpectID(t, "id"),
}, },
args{ args{
ctx: authz.SetCtxData(context.Background(), authz.CtxData{OrgID: "ro"}), ctx: context.Background(),
idpID: "idp", idpID: "idp",
instanceID: "instance",
successURL: "https://success.url", successURL: "https://success.url",
failureURL: "https://failure.url", failureURL: "https://failure.url",
}, },
@ -139,14 +140,33 @@ func TestCommands_CreateIntent(t *testing.T) {
}, },
}, },
{ {
"push", "error idp not existing instance",
fields{ fields{
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectFilter(), expectFilter(),
expectFilter(), expectFilter(),
),
idGenerator: mock.ExpectID(t, "id"),
},
args{
ctx: context.Background(),
idpID: "idp",
instanceID: "instance",
successURL: "https://success.url",
failureURL: "https://failure.url",
},
res{
err: zerrors.ThrowPreconditionFailed(nil, "COMMAND-39n221fs", "Errors.IDPConfig.NotExisting"),
},
},
{
"push, org",
fields{
eventstore: expectEventstore(
expectFilter(),
expectFilter( expectFilter(
eventFromEventPusher( eventFromEventPusher(
instance.NewOAuthIDPAddedEvent(context.Background(), &instance.NewAggregate("ro").Aggregate, org.NewOAuthIDPAddedEvent(context.Background(), &org.NewAggregate("org").Aggregate,
"idp", "idp",
"name", "name",
"clientID", "clientID",
@ -170,7 +190,7 @@ func TestCommands_CreateIntent(t *testing.T) {
failure, _ := url.Parse("https://failure.url") failure, _ := url.Parse("https://failure.url")
return idpintent.NewStartedEvent( return idpintent.NewStartedEvent(
context.Background(), context.Background(),
&idpintent.NewAggregate("id", "ro").Aggregate, &idpintent.NewAggregate("id", "instance").Aggregate,
success, success,
failure, failure,
"idp", "idp",
@ -181,25 +201,131 @@ func TestCommands_CreateIntent(t *testing.T) {
idGenerator: mock.ExpectID(t, "id"), idGenerator: mock.ExpectID(t, "id"),
}, },
args{ args{
ctx: context.Background(), ctx: context.Background(),
resourceOwner: "ro", instanceID: "instance",
idpID: "idp", idpID: "idp",
successURL: "https://success.url", successURL: "https://success.url",
failureURL: "https://failure.url", failureURL: "https://failure.url",
}, },
res{ res{
intentID: "id", intentID: "id",
details: &domain.ObjectDetails{ResourceOwner: "ro"}, details: &domain.ObjectDetails{ResourceOwner: "instance"},
},
},
{
"push, instance",
fields{
eventstore: expectEventstore(
expectFilter(),
expectFilter(
eventFromEventPusher(
instance.NewOAuthIDPAddedEvent(context.Background(), &instance.NewAggregate("instance").Aggregate,
"idp",
"name",
"clientID",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("clientSecret"),
},
"auth",
"token",
"user",
"idAttribute",
nil,
rep_idp.Options{},
)),
),
expectPush(
func() eventstore.Command {
success, _ := url.Parse("https://success.url")
failure, _ := url.Parse("https://failure.url")
return idpintent.NewStartedEvent(
context.Background(),
&idpintent.NewAggregate("id", "instance").Aggregate,
success,
failure,
"idp",
)
}(),
),
),
idGenerator: mock.ExpectID(t, "id"),
},
args{
ctx: context.Background(),
instanceID: "instance",
idpID: "idp",
successURL: "https://success.url",
failureURL: "https://failure.url",
},
res{
intentID: "id",
details: &domain.ObjectDetails{ResourceOwner: "instance"},
},
},
{
"push, instance without org",
fields{
eventstore: expectEventstore(
expectFilter(),
expectFilter(
eventFromEventPusher(
instance.NewOAuthIDPAddedEvent(context.Background(), &instance.NewAggregate("instance").Aggregate,
"idp",
"name",
"clientID",
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "enc",
KeyID: "id",
Crypted: []byte("clientSecret"),
},
"auth",
"token",
"user",
"idAttribute",
nil,
rep_idp.Options{},
)),
),
expectPush(
func() eventstore.Command {
success, _ := url.Parse("https://success.url")
failure, _ := url.Parse("https://failure.url")
return idpintent.NewStartedEvent(
context.Background(),
&idpintent.NewAggregate("id", "instance").Aggregate,
success,
failure,
"idp",
)
}(),
),
),
idGenerator: mock.ExpectID(t, "id"),
},
args{
ctx: context.Background(),
instanceID: "instance",
idpID: "idp",
successURL: "https://success.url",
failureURL: "https://failure.url",
},
res{
intentID: "id",
details: &domain.ObjectDetails{ResourceOwner: "instance"},
}, },
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &Commands{ c := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore(t),
idGenerator: tt.fields.idGenerator, idGenerator: tt.fields.idGenerator,
} }
intentWriteModel, details, err := c.CreateIntent(tt.args.ctx, tt.args.idpID, tt.args.successURL, tt.args.failureURL, tt.args.resourceOwner) intentWriteModel, details, err := c.CreateIntent(tt.args.ctx, tt.args.idpID, tt.args.successURL, tt.args.failureURL, tt.args.instanceID)
require.ErrorIs(t, err, tt.res.err) require.ErrorIs(t, err, tt.res.err)
if intentWriteModel != nil { if intentWriteModel != nil {
assert.Equal(t, tt.res.intentID, intentWriteModel.AggregateID) assert.Equal(t, tt.res.intentID, intentWriteModel.AggregateID)
@ -213,7 +339,7 @@ func TestCommands_CreateIntent(t *testing.T) {
func TestCommands_AuthFromProvider(t *testing.T) { func TestCommands_AuthFromProvider(t *testing.T) {
type fields struct { type fields struct {
eventstore *eventstore.Eventstore eventstore func(t *testing.T) *eventstore.Eventstore
secretCrypto crypto.EncryptionAlgorithm secretCrypto crypto.EncryptionAlgorithm
} }
type args struct { type args struct {
@ -238,7 +364,7 @@ func TestCommands_AuthFromProvider(t *testing.T) {
"idp not existing", "idp not existing",
fields{ fields{
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectFilter(), expectFilter(),
), ),
}, },
@ -256,7 +382,7 @@ func TestCommands_AuthFromProvider(t *testing.T) {
"idp removed", "idp removed",
fields{ fields{
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectFilter( expectFilter(
eventFromEventPusherWithInstanceID( eventFromEventPusherWithInstanceID(
"instance", "instance",
@ -300,7 +426,7 @@ func TestCommands_AuthFromProvider(t *testing.T) {
"oauth auth redirect", "oauth auth redirect",
fields{ fields{
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectFilter( expectFilter(
eventFromEventPusherWithInstanceID( eventFromEventPusherWithInstanceID(
"instance", "instance",
@ -360,7 +486,7 @@ func TestCommands_AuthFromProvider(t *testing.T) {
"migrated and push", "migrated and push",
fields{ fields{
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectFilter( expectFilter(
eventFromEventPusherWithInstanceID( eventFromEventPusherWithInstanceID(
"instance", "instance",
@ -450,7 +576,7 @@ func TestCommands_AuthFromProvider(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &Commands{ c := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore(t),
idpConfigEncryption: tt.fields.secretCrypto, idpConfigEncryption: tt.fields.secretCrypto,
} }
content, redirect, err := c.AuthFromProvider(tt.args.ctx, tt.args.idpID, tt.args.state, tt.args.callbackURL, tt.args.samlRootURL) content, redirect, err := c.AuthFromProvider(tt.args.ctx, tt.args.idpID, tt.args.state, tt.args.callbackURL, tt.args.samlRootURL)
@ -463,7 +589,7 @@ func TestCommands_AuthFromProvider(t *testing.T) {
func TestCommands_AuthFromProvider_SAML(t *testing.T) { func TestCommands_AuthFromProvider_SAML(t *testing.T) {
type fields struct { type fields struct {
eventstore *eventstore.Eventstore eventstore func(t *testing.T) *eventstore.Eventstore
secretCrypto crypto.EncryptionAlgorithm secretCrypto crypto.EncryptionAlgorithm
} }
type args struct { type args struct {
@ -488,7 +614,7 @@ func TestCommands_AuthFromProvider_SAML(t *testing.T) {
"saml auth default redirect", "saml auth default redirect",
fields{ fields{
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectFilter( expectFilter(
eventFromEventPusherWithInstanceID( eventFromEventPusherWithInstanceID(
"instance", "instance",
@ -534,7 +660,7 @@ func TestCommands_AuthFromProvider_SAML(t *testing.T) {
failure, _ := url.Parse("https://failure.url") failure, _ := url.Parse("https://failure.url")
return idpintent.NewStartedEvent( return idpintent.NewStartedEvent(
context.Background(), context.Background(),
&idpintent.NewAggregate("id", "ro").Aggregate, &idpintent.NewAggregate("id", "instance").Aggregate,
success, success,
failure, failure,
"idp", "idp",
@ -546,7 +672,7 @@ func TestCommands_AuthFromProvider_SAML(t *testing.T) {
[]eventstore.Command{ []eventstore.Command{
idpintent.NewSAMLRequestEvent( idpintent.NewSAMLRequestEvent(
context.Background(), context.Background(),
&idpintent.NewAggregate("id", "ro").Aggregate, &idpintent.NewAggregate("id", "instance").Aggregate,
"request", "request",
), ),
}, },
@ -572,7 +698,7 @@ func TestCommands_AuthFromProvider_SAML(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &Commands{ c := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore(t),
idpConfigEncryption: tt.fields.secretCrypto, idpConfigEncryption: tt.fields.secretCrypto,
} }
content, _, err := c.AuthFromProvider(tt.args.ctx, tt.args.idpID, tt.args.state, tt.args.callbackURL, tt.args.samlRootURL) content, _, err := c.AuthFromProvider(tt.args.ctx, tt.args.idpID, tt.args.state, tt.args.callbackURL, tt.args.samlRootURL)
@ -595,7 +721,7 @@ func TestCommands_AuthFromProvider_SAML(t *testing.T) {
func TestCommands_SucceedIDPIntent(t *testing.T) { func TestCommands_SucceedIDPIntent(t *testing.T) {
type fields struct { type fields struct {
eventstore *eventstore.Eventstore eventstore func(t *testing.T) *eventstore.Eventstore
idpConfigEncryption crypto.EncryptionAlgorithm idpConfigEncryption crypto.EncryptionAlgorithm
} }
type args struct { type args struct {
@ -623,6 +749,7 @@ func TestCommands_SucceedIDPIntent(t *testing.T) {
m.EXPECT().Encrypt(gomock.Any()).Return(nil, zerrors.ThrowInternal(nil, "id", "encryption failed")) m.EXPECT().Encrypt(gomock.Any()).Return(nil, zerrors.ThrowInternal(nil, "id", "encryption failed"))
return m return m
}(), }(),
eventstore: expectEventstore(),
}, },
args{ args{
ctx: context.Background(), ctx: context.Background(),
@ -643,6 +770,7 @@ func TestCommands_SucceedIDPIntent(t *testing.T) {
m.EXPECT().Encrypt(gomock.Any()).Return(nil, zerrors.ThrowInternal(nil, "id", "encryption failed")) m.EXPECT().Encrypt(gomock.Any()).Return(nil, zerrors.ThrowInternal(nil, "id", "encryption failed"))
return m return m
}(), }(),
eventstore: expectEventstore(),
}, },
args{ args{
ctx: context.Background(), ctx: context.Background(),
@ -663,12 +791,12 @@ func TestCommands_SucceedIDPIntent(t *testing.T) {
"push", "push",
fields{ fields{
idpConfigEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), idpConfigEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectPush( expectPush(
func() eventstore.Command { func() eventstore.Command {
event := idpintent.NewSucceededEvent( event := idpintent.NewSucceededEvent(
context.Background(), context.Background(),
&idpintent.NewAggregate("id", "ro").Aggregate, &idpintent.NewAggregate("id", "instance").Aggregate,
[]byte(`{"sub":"id","preferred_username":"username"}`), []byte(`{"sub":"id","preferred_username":"username"}`),
"id", "id",
"username", "username",
@ -688,7 +816,7 @@ func TestCommands_SucceedIDPIntent(t *testing.T) {
}, },
args{ args{
ctx: context.Background(), ctx: context.Background(),
writeModel: NewIDPIntentWriteModel("id", "ro"), writeModel: NewIDPIntentWriteModel("id", "instance"),
idpSession: &openid.Session{ idpSession: &openid.Session{
Tokens: &oidc.Tokens[*oidc.IDTokenClaims]{ Tokens: &oidc.Tokens[*oidc.IDTokenClaims]{
Token: &oauth2.Token{ Token: &oauth2.Token{
@ -712,7 +840,7 @@ func TestCommands_SucceedIDPIntent(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &Commands{ c := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore(t),
idpConfigEncryption: tt.fields.idpConfigEncryption, idpConfigEncryption: tt.fields.idpConfigEncryption,
} }
got, err := c.SucceedIDPIntent(tt.args.ctx, tt.args.writeModel, tt.args.idpUser, tt.args.idpSession, tt.args.userID) got, err := c.SucceedIDPIntent(tt.args.ctx, tt.args.writeModel, tt.args.idpUser, tt.args.idpSession, tt.args.userID)
@ -724,7 +852,7 @@ func TestCommands_SucceedIDPIntent(t *testing.T) {
func TestCommands_SucceedSAMLIDPIntent(t *testing.T) { func TestCommands_SucceedSAMLIDPIntent(t *testing.T) {
type fields struct { type fields struct {
eventstore *eventstore.Eventstore eventstore func(t *testing.T) *eventstore.Eventstore
idpConfigEncryption crypto.EncryptionAlgorithm idpConfigEncryption crypto.EncryptionAlgorithm
} }
type args struct { type args struct {
@ -752,6 +880,7 @@ func TestCommands_SucceedSAMLIDPIntent(t *testing.T) {
m.EXPECT().Encrypt(gomock.Any()).Return(nil, zerrors.ThrowInternal(nil, "id", "encryption failed")) m.EXPECT().Encrypt(gomock.Any()).Return(nil, zerrors.ThrowInternal(nil, "id", "encryption failed"))
return m return m
}(), }(),
eventstore: expectEventstore(),
}, },
args{ args{
ctx: context.Background(), ctx: context.Background(),
@ -765,11 +894,11 @@ func TestCommands_SucceedSAMLIDPIntent(t *testing.T) {
"push", "push",
fields{ fields{
idpConfigEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), idpConfigEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectPush( expectPush(
idpintent.NewSAMLSucceededEvent( idpintent.NewSAMLSucceededEvent(
context.Background(), context.Background(),
&idpintent.NewAggregate("id", "ro").Aggregate, &idpintent.NewAggregate("id", "instance").Aggregate,
[]byte(`{"sub":"id","preferred_username":"username"}`), []byte(`{"sub":"id","preferred_username":"username"}`),
"id", "id",
"username", "username",
@ -786,7 +915,7 @@ func TestCommands_SucceedSAMLIDPIntent(t *testing.T) {
}, },
args{ args{
ctx: context.Background(), ctx: context.Background(),
writeModel: NewIDPIntentWriteModel("id", "ro"), writeModel: NewIDPIntentWriteModel("id", "instance"),
assertion: &saml.Assertion{ID: "id"}, assertion: &saml.Assertion{ID: "id"},
idpUser: openid.NewUser(&oidc.UserInfo{ idpUser: openid.NewUser(&oidc.UserInfo{
Subject: "id", Subject: "id",
@ -803,11 +932,11 @@ func TestCommands_SucceedSAMLIDPIntent(t *testing.T) {
"push with userID", "push with userID",
fields{ fields{
idpConfigEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), idpConfigEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectPush( expectPush(
idpintent.NewSAMLSucceededEvent( idpintent.NewSAMLSucceededEvent(
context.Background(), context.Background(),
&idpintent.NewAggregate("id", "ro").Aggregate, &idpintent.NewAggregate("id", "instance").Aggregate,
[]byte(`{"sub":"id","preferred_username":"username"}`), []byte(`{"sub":"id","preferred_username":"username"}`),
"id", "id",
"username", "username",
@ -824,7 +953,7 @@ func TestCommands_SucceedSAMLIDPIntent(t *testing.T) {
}, },
args{ args{
ctx: context.Background(), ctx: context.Background(),
writeModel: NewIDPIntentWriteModel("id", "ro"), writeModel: NewIDPIntentWriteModel("id", "instance"),
assertion: &saml.Assertion{ID: "id"}, assertion: &saml.Assertion{ID: "id"},
idpUser: openid.NewUser(&oidc.UserInfo{ idpUser: openid.NewUser(&oidc.UserInfo{
Subject: "id", Subject: "id",
@ -842,7 +971,7 @@ func TestCommands_SucceedSAMLIDPIntent(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &Commands{ c := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore(t),
idpConfigEncryption: tt.fields.idpConfigEncryption, idpConfigEncryption: tt.fields.idpConfigEncryption,
} }
got, err := c.SucceedSAMLIDPIntent(tt.args.ctx, tt.args.writeModel, tt.args.idpUser, tt.args.userID, tt.args.assertion) got, err := c.SucceedSAMLIDPIntent(tt.args.ctx, tt.args.writeModel, tt.args.idpUser, tt.args.userID, tt.args.assertion)
@ -854,7 +983,7 @@ func TestCommands_SucceedSAMLIDPIntent(t *testing.T) {
func TestCommands_RequestSAMLIDPIntent(t *testing.T) { func TestCommands_RequestSAMLIDPIntent(t *testing.T) {
type fields struct { type fields struct {
eventstore *eventstore.Eventstore eventstore func(t *testing.T) *eventstore.Eventstore
} }
type args struct { type args struct {
ctx context.Context ctx context.Context
@ -873,11 +1002,11 @@ func TestCommands_RequestSAMLIDPIntent(t *testing.T) {
{ {
"push", "push",
fields{ fields{
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectPush( expectPush(
idpintent.NewSAMLRequestEvent( idpintent.NewSAMLRequestEvent(
context.Background(), context.Background(),
&idpintent.NewAggregate("id", "ro").Aggregate, &idpintent.NewAggregate("id", "instance").Aggregate,
"request", "request",
), ),
), ),
@ -885,7 +1014,7 @@ func TestCommands_RequestSAMLIDPIntent(t *testing.T) {
}, },
args{ args{
ctx: context.Background(), ctx: context.Background(),
writeModel: NewIDPIntentWriteModel("id", "ro"), writeModel: NewIDPIntentWriteModel("id", "instance"),
request: "request", request: "request",
}, },
res{}, res{},
@ -894,7 +1023,7 @@ func TestCommands_RequestSAMLIDPIntent(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &Commands{ c := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore(t),
} }
err := c.RequestSAMLIDPIntent(tt.args.ctx, tt.args.writeModel, tt.args.request) err := c.RequestSAMLIDPIntent(tt.args.ctx, tt.args.writeModel, tt.args.request)
require.ErrorIs(t, err, tt.res.err) require.ErrorIs(t, err, tt.res.err)
@ -905,7 +1034,7 @@ func TestCommands_RequestSAMLIDPIntent(t *testing.T) {
func TestCommands_SucceedLDAPIDPIntent(t *testing.T) { func TestCommands_SucceedLDAPIDPIntent(t *testing.T) {
type fields struct { type fields struct {
eventstore *eventstore.Eventstore eventstore func(t *testing.T) *eventstore.Eventstore
idpConfigEncryption crypto.EncryptionAlgorithm idpConfigEncryption crypto.EncryptionAlgorithm
} }
type args struct { type args struct {
@ -933,10 +1062,11 @@ func TestCommands_SucceedLDAPIDPIntent(t *testing.T) {
m.EXPECT().Encrypt(gomock.Any()).Return(nil, zerrors.ThrowInternal(nil, "id", "encryption failed")) m.EXPECT().Encrypt(gomock.Any()).Return(nil, zerrors.ThrowInternal(nil, "id", "encryption failed"))
return m return m
}(), }(),
eventstore: expectEventstore(),
}, },
args{ args{
ctx: context.Background(), ctx: context.Background(),
writeModel: NewIDPIntentWriteModel("id", "ro"), writeModel: NewIDPIntentWriteModel("id", "instance"),
}, },
res{ res{
err: zerrors.ThrowInternal(nil, "id", "encryption failed"), err: zerrors.ThrowInternal(nil, "id", "encryption failed"),
@ -946,11 +1076,11 @@ func TestCommands_SucceedLDAPIDPIntent(t *testing.T) {
"push", "push",
fields{ fields{
idpConfigEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), idpConfigEncryption: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectPush( expectPush(
idpintent.NewLDAPSucceededEvent( idpintent.NewLDAPSucceededEvent(
context.Background(), context.Background(),
&idpintent.NewAggregate("id", "ro").Aggregate, &idpintent.NewAggregate("id", "instance").Aggregate,
[]byte(`{"id":"id","preferredUsername":"username","preferredLanguage":"und"}`), []byte(`{"id":"id","preferredUsername":"username","preferredLanguage":"und"}`),
"id", "id",
"username", "username",
@ -962,7 +1092,7 @@ func TestCommands_SucceedLDAPIDPIntent(t *testing.T) {
}, },
args{ args{
ctx: context.Background(), ctx: context.Background(),
writeModel: NewIDPIntentWriteModel("id", "ro"), writeModel: NewIDPIntentWriteModel("id", "instance"),
attributes: map[string][]string{"id": {"id"}}, attributes: map[string][]string{"id": {"id"}},
idpUser: ldap.NewUser( idpUser: ldap.NewUser(
"id", "id",
@ -988,7 +1118,7 @@ func TestCommands_SucceedLDAPIDPIntent(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &Commands{ c := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore(t),
idpConfigEncryption: tt.fields.idpConfigEncryption, idpConfigEncryption: tt.fields.idpConfigEncryption,
} }
got, err := c.SucceedLDAPIDPIntent(tt.args.ctx, tt.args.writeModel, tt.args.idpUser, tt.args.userID, tt.args.attributes) got, err := c.SucceedLDAPIDPIntent(tt.args.ctx, tt.args.writeModel, tt.args.idpUser, tt.args.userID, tt.args.attributes)
@ -1000,7 +1130,7 @@ func TestCommands_SucceedLDAPIDPIntent(t *testing.T) {
func TestCommands_FailIDPIntent(t *testing.T) { func TestCommands_FailIDPIntent(t *testing.T) {
type fields struct { type fields struct {
eventstore *eventstore.Eventstore eventstore func(t *testing.T) *eventstore.Eventstore
} }
type args struct { type args struct {
ctx context.Context ctx context.Context
@ -1019,11 +1149,11 @@ func TestCommands_FailIDPIntent(t *testing.T) {
{ {
"push", "push",
fields{ fields{
eventstore: eventstoreExpect(t, eventstore: expectEventstore(
expectPush( expectPush(
idpintent.NewFailedEvent( idpintent.NewFailedEvent(
context.Background(), context.Background(),
&idpintent.NewAggregate("id", "ro").Aggregate, &idpintent.NewAggregate("id", "instance").Aggregate,
"reason", "reason",
), ),
), ),
@ -1031,7 +1161,7 @@ func TestCommands_FailIDPIntent(t *testing.T) {
}, },
args{ args{
ctx: context.Background(), ctx: context.Background(),
writeModel: NewIDPIntentWriteModel("id", "ro"), writeModel: NewIDPIntentWriteModel("id", "instance"),
reason: "reason", reason: "reason",
}, },
res{ res{
@ -1042,7 +1172,7 @@ func TestCommands_FailIDPIntent(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
c := &Commands{ c := &Commands{
eventstore: tt.fields.eventstore, eventstore: tt.fields.eventstore(t),
} }
err := c.FailIDPIntent(tt.args.ctx, tt.args.writeModel, tt.args.reason) err := c.FailIDPIntent(tt.args.ctx, tt.args.writeModel, tt.args.reason)
require.ErrorIs(t, err, tt.res.err) require.ErrorIs(t, err, tt.res.err)

View File

@ -416,7 +416,7 @@ func prepareAddLoginPolicy(a *org.Aggregate, policy *AddLoginPolicy) preparation
return nil, zerrors.ThrowAlreadyExists(nil, "Org-Dgfb2", "Errors.Org.LoginPolicy.AlreadyExists") return nil, zerrors.ThrowAlreadyExists(nil, "Org-Dgfb2", "Errors.Org.LoginPolicy.AlreadyExists")
} }
for _, idp := range policy.IDPProviders { for _, idp := range policy.IDPProviders {
exists, err := ExistsIDP(ctx, filter, idp.ConfigID, authz.GetCtxData(ctx).OrgID) exists, err := ExistsIDPOnOrgOrInstance(ctx, filter, authz.GetInstance(ctx).InstanceID(), a.ResourceOwner, idp.ConfigID)
if !exists || err != nil { if !exists || err != nil {
return nil, zerrors.ThrowPreconditionFailed(err, "Org-FEd32", "Errors.IDPConfig.NotExisting") return nil, zerrors.ThrowPreconditionFailed(err, "Org-FEd32", "Errors.IDPConfig.NotExisting")
} }

View File

@ -683,7 +683,8 @@ func TestCommands_updateSession(t *testing.T) {
"username", "", "", "", "", language.English, domain.GenderUnspecified, "", false), "username", "", "", "", "", language.English, domain.GenderUnspecified, "", false),
), ),
eventFromEventPusher( eventFromEventPusher(
idpintent.NewSucceededEvent(context.Background(), &idpintent.NewAggregate("intent", "org1").Aggregate, idpintent.NewSucceededEvent(context.Background(),
&idpintent.NewAggregate("id", "instance1").Aggregate,
nil, nil,
"idpUserID", "idpUserID",
"idpUserName", "idpUserName",
@ -775,7 +776,8 @@ func TestCommands_updateSession(t *testing.T) {
"username", "", "", "", "", language.English, domain.GenderUnspecified, "", false), "username", "", "", "", "", language.English, domain.GenderUnspecified, "", false),
), ),
eventFromEventPusher( eventFromEventPusher(
idpintent.NewSucceededEvent(context.Background(), &idpintent.NewAggregate("intent", "org1").Aggregate, idpintent.NewSucceededEvent(context.Background(),
&idpintent.NewAggregate("id", "instance1").Aggregate,
nil, nil,
"idpUserID", "idpUserID",
"idpUsername", "idpUsername",

View File

@ -6,6 +6,7 @@ import (
"golang.org/x/text/language" "golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/command/preparation" "github.com/zitadel/zitadel/internal/command/preparation"
"github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/domain"
@ -294,7 +295,7 @@ func (c *Commands) addHumanCommandEmail(ctx context.Context, filter preparation.
} }
func addLink(ctx context.Context, filter preparation.FilterToQueryReducer, a *user.Aggregate, link *AddLink) (eventstore.Command, error) { func addLink(ctx context.Context, filter preparation.FilterToQueryReducer, a *user.Aggregate, link *AddLink) (eventstore.Command, error) {
exists, err := ExistsIDP(ctx, filter, link.IDPID, a.ResourceOwner) exists, err := ExistsIDPOnOrgOrInstance(ctx, filter, authz.GetInstance(ctx).InstanceID(), a.ResourceOwner, link.IDPID)
if !exists || err != nil { if !exists || err != nil {
return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-39nf2", "Errors.IDPConfig.NotExisting") return nil, zerrors.ThrowPreconditionFailed(err, "COMMAND-39nf2", "Errors.IDPConfig.NotExisting")
} }

View File

@ -288,8 +288,8 @@ func (s *Tester) SetUserPassword(ctx context.Context, userID, password string, c
logging.OnError(err).Fatal("set user password") logging.OnError(err).Fatal("set user password")
} }
func (s *Tester) AddGenericOAuthProvider(t *testing.T) string { func (s *Tester) AddGenericOAuthProvider(t *testing.T, ctx context.Context) string {
ctx := authz.WithInstance(context.Background(), s.Instance) ctx = authz.WithInstance(ctx, s.Instance)
id, _, err := s.Commands.AddInstanceGenericOAuthProvider(ctx, command.GenericOAuthProvider{ id, _, err := s.Commands.AddInstanceGenericOAuthProvider(ctx, command.GenericOAuthProvider{
Name: "idp", Name: "idp",
ClientID: "clientID", ClientID: "clientID",
@ -310,8 +310,31 @@ func (s *Tester) AddGenericOAuthProvider(t *testing.T) string {
return id return id
} }
func (s *Tester) AddSAMLProvider(t *testing.T) string { func (s *Tester) AddOrgGenericOAuthProvider(t *testing.T, ctx context.Context, orgID string) string {
ctx := authz.WithInstance(context.Background(), s.Instance) ctx = authz.WithInstance(ctx, s.Instance)
id, _, err := s.Commands.AddOrgGenericOAuthProvider(ctx, orgID,
command.GenericOAuthProvider{
Name: "idp",
ClientID: "clientID",
ClientSecret: "clientSecret",
AuthorizationEndpoint: "https://example.com/oauth/v2/authorize",
TokenEndpoint: "https://example.com/oauth/v2/token",
UserEndpoint: "https://api.example.com/user",
Scopes: []string{"openid", "profile", "email"},
IDAttribute: "id",
IDPOptions: idp.Options{
IsLinkingAllowed: true,
IsCreationAllowed: true,
IsAutoCreation: true,
IsAutoUpdate: true,
},
})
require.NoError(t, err)
return id
}
func (s *Tester) AddSAMLProvider(t *testing.T, ctx context.Context) string {
ctx = authz.WithInstance(ctx, s.Instance)
id, _, err := s.Server.Commands.AddInstanceSAMLProvider(ctx, command.SAMLProvider{ id, _, err := s.Server.Commands.AddInstanceSAMLProvider(ctx, command.SAMLProvider{
Name: "saml-idp", Name: "saml-idp",
Metadata: []byte("<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" validUntil=\"2023-09-16T09:00:32.986Z\" cacheDuration=\"PT48H\" entityID=\"http://localhost:8000/metadata\">\n <IDPSSODescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n <KeyDescriptor use=\"signing\">\n <KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Data xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Certificate xmlns=\"http://www.w3.org/2000/09/xmldsig#\">MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=</X509Certificate>\n </X509Data>\n </KeyInfo>\n </KeyDescriptor>\n <KeyDescriptor use=\"encryption\">\n <KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Data xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Certificate xmlns=\"http://www.w3.org/2000/09/xmldsig#\">MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=</X509Certificate>\n </X509Data>\n </KeyInfo>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes128-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes192-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes256-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p\"></EncryptionMethod>\n </KeyDescriptor>\n <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>\n <SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"http://localhost:8000/sso\"></SingleSignOnService>\n <SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"http://localhost:8000/sso\"></SingleSignOnService>\n </IDPSSODescriptor>\n</EntityDescriptor>"), Metadata: []byte("<EntityDescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" validUntil=\"2023-09-16T09:00:32.986Z\" cacheDuration=\"PT48H\" entityID=\"http://localhost:8000/metadata\">\n <IDPSSODescriptor xmlns=\"urn:oasis:names:tc:SAML:2.0:metadata\" protocolSupportEnumeration=\"urn:oasis:names:tc:SAML:2.0:protocol\">\n <KeyDescriptor use=\"signing\">\n <KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Data xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Certificate xmlns=\"http://www.w3.org/2000/09/xmldsig#\">MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=</X509Certificate>\n </X509Data>\n </KeyInfo>\n </KeyDescriptor>\n <KeyDescriptor use=\"encryption\">\n <KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Data xmlns=\"http://www.w3.org/2000/09/xmldsig#\">\n <X509Certificate xmlns=\"http://www.w3.org/2000/09/xmldsig#\">MIIDBzCCAe+gAwIBAgIJAPr/Mrlc8EGhMA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNTEyMjgxOTE5NDVaFw0yNTEyMjUxOTE5NDVaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANDoWzLos4LWxTn8Gyu2lEbl4WcelUbgLN5zYm4ron8Ahs+rvcsu2zkdD/s6jdGJI8WqJKhYK2u61ygnXgAZqC6ggtFPnBpizcDzjgND2g+aucSoUODHt67f0fQuAmupN/zp5MZysJ6IHLJnYLNpfJYk96lRz9ODnO1Mpqtr9PWxm+pz7nzq5F0vRepkgpcRxv6ufQBjlrFytccyEVdXrvFtkjXcnhVVNSR4kHuOOMS6D7pebSJ1mrCmshbD5SX1jXPBKFPAjozYX6PxqLxUx1Y4faFEf4MBBVcInyB4oURNB2s59hEEi2jq9izNE7EbEK6BY5sEhoCPl9m32zE6ljkCAwEAAaNQME4wHQYDVR0OBBYEFB9ZklC1Ork2zl56zg08ei7ss/+iMB8GA1UdIwQYMBaAFB9ZklC1Ork2zl56zg08ei7ss/+iMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAVoTSQ5pAirw8OR9FZ1bRSuTDhY9uxzl/OL7lUmsv2cMNeCB3BRZqm3mFt+cwN8GsH6f3uvNONIhgFpTGN5LEcXQz89zJEzB+qaHqmbFpHQl/sx2B8ezNgT/882H2IH00dXESEfy/+1gHg2pxjGnhRBN6el/gSaDiySIMKbilDrffuvxiCfbpPN0NRRiPJhd2ay9KuL/RxQRl1gl9cHaWiouWWba1bSBb2ZPhv2rPMUsFo98ntkGCObDX6Y1SpkqmoTbrsbGFsTG2DLxnvr4GdN1BSr0Uu/KV3adj47WkXVPeMYQti/bQmxQB8tRFhrw80qakTLUzreO96WzlBBMtY=</X509Certificate>\n </X509Data>\n </KeyInfo>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes128-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes192-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#aes256-cbc\"></EncryptionMethod>\n <EncryptionMethod Algorithm=\"http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p\"></EncryptionMethod>\n </KeyDescriptor>\n <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>\n <SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect\" Location=\"http://localhost:8000/sso\"></SingleSignOnService>\n <SingleSignOnService Binding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" Location=\"http://localhost:8000/sso\"></SingleSignOnService>\n </IDPSSODescriptor>\n</EntityDescriptor>"),
@ -326,8 +349,8 @@ func (s *Tester) AddSAMLProvider(t *testing.T) string {
return id return id
} }
func (s *Tester) AddSAMLRedirectProvider(t *testing.T) string { func (s *Tester) AddSAMLRedirectProvider(t *testing.T, ctx context.Context) string {
ctx := authz.WithInstance(context.Background(), s.Instance) ctx = authz.WithInstance(ctx, s.Instance)
id, _, err := s.Server.Commands.AddInstanceSAMLProvider(ctx, command.SAMLProvider{ id, _, err := s.Server.Commands.AddInstanceSAMLProvider(ctx, command.SAMLProvider{
Name: "saml-idp-redirect", Name: "saml-idp-redirect",
Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect", Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
@ -343,8 +366,8 @@ func (s *Tester) AddSAMLRedirectProvider(t *testing.T) string {
return id return id
} }
func (s *Tester) AddSAMLPostProvider(t *testing.T) string { func (s *Tester) AddSAMLPostProvider(t *testing.T, ctx context.Context) string {
ctx := authz.WithInstance(context.Background(), s.Instance) ctx = authz.WithInstance(ctx, s.Instance)
id, _, err := s.Server.Commands.AddInstanceSAMLProvider(ctx, command.SAMLProvider{ id, _, err := s.Server.Commands.AddInstanceSAMLProvider(ctx, command.SAMLProvider{
Name: "saml-idp-post", Name: "saml-idp-post",
Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST", Binding: "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
@ -360,17 +383,17 @@ func (s *Tester) AddSAMLPostProvider(t *testing.T) string {
return id return id
} }
func (s *Tester) CreateIntent(t *testing.T, idpID string) string { func (s *Tester) CreateIntent(t *testing.T, ctx context.Context, idpID string) string {
ctx := authz.WithInstance(context.Background(), s.Instance) ctx = authz.WithInstance(context.WithoutCancel(ctx), s.Instance)
writeModel, _, err := s.Commands.CreateIntent(ctx, idpID, "https://example.com/success", "https://example.com/failure", s.Organisation.ID) writeModel, _, err := s.Commands.CreateIntent(ctx, idpID, "https://example.com/success", "https://example.com/failure", s.Instance.InstanceID())
require.NoError(t, err) require.NoError(t, err)
return writeModel.AggregateID return writeModel.AggregateID
} }
func (s *Tester) CreateSuccessfulOAuthIntent(t *testing.T, idpID, userID, idpUserID string) (string, string, time.Time, uint64) { func (s *Tester) CreateSuccessfulOAuthIntent(t *testing.T, ctx context.Context, idpID, userID, idpUserID string) (string, string, time.Time, uint64) {
ctx := authz.WithInstance(context.Background(), s.Instance) ctx = authz.WithInstance(context.WithoutCancel(ctx), s.Instance)
intentID := s.CreateIntent(t, idpID) intentID := s.CreateIntent(t, ctx, idpID)
writeModel, err := s.Commands.GetIntentWriteModel(ctx, intentID, s.Organisation.ID) writeModel, err := s.Commands.GetIntentWriteModel(ctx, intentID, s.Instance.InstanceID())
require.NoError(t, err) require.NoError(t, err)
idpUser := openid.NewUser( idpUser := openid.NewUser(
&oidc.UserInfo{ &oidc.UserInfo{
@ -393,10 +416,10 @@ func (s *Tester) CreateSuccessfulOAuthIntent(t *testing.T, idpID, userID, idpUse
return intentID, token, writeModel.ChangeDate, writeModel.ProcessedSequence return intentID, token, writeModel.ChangeDate, writeModel.ProcessedSequence
} }
func (s *Tester) CreateSuccessfulLDAPIntent(t *testing.T, idpID, userID, idpUserID string) (string, string, time.Time, uint64) { func (s *Tester) CreateSuccessfulLDAPIntent(t *testing.T, ctx context.Context, idpID, userID, idpUserID string) (string, string, time.Time, uint64) {
ctx := authz.WithInstance(context.Background(), s.Instance) ctx = authz.WithInstance(context.WithoutCancel(ctx), s.Instance)
intentID := s.CreateIntent(t, idpID) intentID := s.CreateIntent(t, ctx, idpID)
writeModel, err := s.Commands.GetIntentWriteModel(ctx, intentID, s.Organisation.ID) writeModel, err := s.Commands.GetIntentWriteModel(ctx, intentID, s.Instance.InstanceID())
require.NoError(t, err) require.NoError(t, err)
username := "username" username := "username"
lang := language.Make("en") lang := language.Make("en")
@ -421,10 +444,10 @@ func (s *Tester) CreateSuccessfulLDAPIntent(t *testing.T, idpID, userID, idpUser
return intentID, token, writeModel.ChangeDate, writeModel.ProcessedSequence return intentID, token, writeModel.ChangeDate, writeModel.ProcessedSequence
} }
func (s *Tester) CreateSuccessfulSAMLIntent(t *testing.T, idpID, userID, idpUserID string) (string, string, time.Time, uint64) { func (s *Tester) CreateSuccessfulSAMLIntent(t *testing.T, ctx context.Context, idpID, userID, idpUserID string) (string, string, time.Time, uint64) {
ctx := authz.WithInstance(context.Background(), s.Instance) ctx = authz.WithInstance(context.WithoutCancel(ctx), s.Instance)
intentID := s.CreateIntent(t, idpID) intentID := s.CreateIntent(t, ctx, idpID)
writeModel, err := s.Server.Commands.GetIntentWriteModel(ctx, intentID, s.Organisation.ID) writeModel, err := s.Server.Commands.GetIntentWriteModel(ctx, intentID, s.Instance.InstanceID())
require.NoError(t, err) require.NoError(t, err)
idpUser := &saml.UserMapper{ idpUser := &saml.UserMapper{