mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:37:32 +00:00
fix: prevent intent token reuse and add expiry
(cherry picked from commit b1e60e7398
)
This commit is contained in:
@@ -354,7 +354,7 @@ func TestServer_CreateSession_successfulIntent(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, User.GetUserId())
|
||||
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId())
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId(), time.Now().Add(time.Hour))
|
||||
require.NoError(t, err)
|
||||
updateResp, err := Client.SetSession(LoginCTX, &session.SetSessionRequest{
|
||||
SessionId: createResp.GetSessionId(),
|
||||
@@ -372,7 +372,7 @@ func TestServer_CreateSession_successfulIntent(t *testing.T) {
|
||||
func TestServer_CreateSession_successfulIntent_instant(t *testing.T) {
|
||||
idpID := Instance.AddGenericOAuthProvider(IAMOwnerCTX, gofakeit.AppName()).GetId()
|
||||
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId())
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId(), time.Now().Add(time.Hour))
|
||||
require.NoError(t, err)
|
||||
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
|
||||
Checks: &session.Checks{
|
||||
@@ -396,7 +396,7 @@ func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
|
||||
|
||||
// successful intent without known / linked user
|
||||
idpUserID := "id"
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, idpUserID, "")
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, idpUserID, "", time.Now().Add(time.Hour))
|
||||
|
||||
// link the user (with info from intent)
|
||||
Instance.CreateUserIDPlink(CTX, User.GetUserId(), idpUserID, idpID, User.GetUserId())
|
||||
@@ -447,6 +447,80 @@ func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestServer_CreateSession_reuseIntent(t *testing.T) {
|
||||
idpID := Instance.AddGenericOAuthProvider(IAMOwnerCTX, gofakeit.AppName()).GetId()
|
||||
createResp, err := Client.CreateSession(LoginCTX, &session.CreateSessionRequest{
|
||||
Checks: &session.Checks{
|
||||
User: &session.CheckUser{
|
||||
Search: &session.CheckUser_UserId{
|
||||
UserId: User.GetUserId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, User.GetUserId())
|
||||
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId(), time.Now().Add(time.Hour))
|
||||
require.NoError(t, err)
|
||||
updateResp, err := Client.SetSession(LoginCTX, &session.SetSessionRequest{
|
||||
SessionId: createResp.GetSessionId(),
|
||||
Checks: &session.Checks{
|
||||
IdpIntent: &session.CheckIDPIntent{
|
||||
IdpIntentId: intentID,
|
||||
IdpIntentToken: token,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, User.GetUserId(), wantUserFactor, wantIntentFactor)
|
||||
|
||||
// the reuse of the intent token is not allowed, not even on the same session
|
||||
session2, err := Client.SetSession(LoginCTX, &session.SetSessionRequest{
|
||||
SessionId: createResp.GetSessionId(),
|
||||
Checks: &session.Checks{
|
||||
IdpIntent: &session.CheckIDPIntent{
|
||||
IdpIntentId: intentID,
|
||||
IdpIntentToken: token,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.Error(t, err)
|
||||
_ = session2
|
||||
}
|
||||
|
||||
func TestServer_CreateSession_expiredIntent(t *testing.T) {
|
||||
idpID := Instance.AddGenericOAuthProvider(IAMOwnerCTX, gofakeit.AppName()).GetId()
|
||||
createResp, err := Client.CreateSession(LoginCTX, &session.CreateSessionRequest{
|
||||
Checks: &session.Checks{
|
||||
User: &session.CheckUser{
|
||||
Search: &session.CheckUser_UserId{
|
||||
UserId: User.GetUserId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, User.GetUserId())
|
||||
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId(), time.Now().Add(time.Second))
|
||||
require.NoError(t, err)
|
||||
|
||||
// wait for the intent to expire
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
_, err = Client.SetSession(LoginCTX, &session.SetSessionRequest{
|
||||
SessionId: createResp.GetSessionId(),
|
||||
Checks: &session.Checks{
|
||||
IdpIntent: &session.CheckIDPIntent{
|
||||
IdpIntentId: intentID,
|
||||
IdpIntentToken: token,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func registerTOTP(ctx context.Context, t *testing.T, userID string) (secret string) {
|
||||
resp, err := Instance.Client.UserV2.RegisterTOTP(ctx, &user.RegisterTOTPRequest{
|
||||
UserId: userID,
|
||||
|
@@ -354,7 +354,7 @@ func TestServer_CreateSession_successfulIntent(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, User.GetUserId())
|
||||
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId())
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId(), time.Now().Add(time.Hour))
|
||||
require.NoError(t, err)
|
||||
updateResp, err := Client.SetSession(CTX, &session.SetSessionRequest{
|
||||
SessionId: createResp.GetSessionId(),
|
||||
@@ -372,7 +372,7 @@ func TestServer_CreateSession_successfulIntent(t *testing.T) {
|
||||
func TestServer_CreateSession_successfulIntent_instant(t *testing.T) {
|
||||
idpID := Instance.AddGenericOAuthProvider(IAMOwnerCTX, gofakeit.AppName()).GetId()
|
||||
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId())
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId(), time.Now().Add(time.Hour))
|
||||
require.NoError(t, err)
|
||||
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
|
||||
Checks: &session.Checks{
|
||||
@@ -396,7 +396,7 @@ func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
|
||||
|
||||
// successful intent without known / linked user
|
||||
idpUserID := "id"
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId())
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId(), time.Now().Add(time.Hour))
|
||||
require.NoError(t, err)
|
||||
|
||||
// link the user (with info from intent)
|
||||
@@ -448,6 +448,80 @@ func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) {
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestServer_CreateSession_reuseIntent(t *testing.T) {
|
||||
idpID := Instance.AddGenericOAuthProvider(IAMOwnerCTX, gofakeit.AppName()).GetId()
|
||||
createResp, err := Client.CreateSession(IAMOwnerCTX, &session.CreateSessionRequest{
|
||||
Checks: &session.Checks{
|
||||
User: &session.CheckUser{
|
||||
Search: &session.CheckUser_UserId{
|
||||
UserId: User.GetUserId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, User.GetUserId())
|
||||
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId(), time.Now().Add(time.Hour))
|
||||
require.NoError(t, err)
|
||||
updateResp, err := Client.SetSession(IAMOwnerCTX, &session.SetSessionRequest{
|
||||
SessionId: createResp.GetSessionId(),
|
||||
Checks: &session.Checks{
|
||||
IdpIntent: &session.CheckIDPIntent{
|
||||
IdpIntentId: intentID,
|
||||
IdpIntentToken: token,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, User.GetUserId(), wantUserFactor, wantIntentFactor)
|
||||
|
||||
// the reuse of the intent token is not allowed, not even on the same session
|
||||
session2, err := Client.SetSession(IAMOwnerCTX, &session.SetSessionRequest{
|
||||
SessionId: createResp.GetSessionId(),
|
||||
Checks: &session.Checks{
|
||||
IdpIntent: &session.CheckIDPIntent{
|
||||
IdpIntentId: intentID,
|
||||
IdpIntentToken: token,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.Error(t, err)
|
||||
_ = session2
|
||||
}
|
||||
|
||||
func TestServer_CreateSession_expiredIntent(t *testing.T) {
|
||||
idpID := Instance.AddGenericOAuthProvider(IAMOwnerCTX, gofakeit.AppName()).GetId()
|
||||
createResp, err := Client.CreateSession(IAMOwnerCTX, &session.CreateSessionRequest{
|
||||
Checks: &session.Checks{
|
||||
User: &session.CheckUser{
|
||||
Search: &session.CheckUser_UserId{
|
||||
UserId: User.GetUserId(),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, User.GetUserId())
|
||||
|
||||
intentID, token, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", User.GetUserId(), time.Now().Add(time.Second))
|
||||
require.NoError(t, err)
|
||||
|
||||
// wait for the intent to expire
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
_, err = Client.SetSession(IAMOwnerCTX, &session.SetSessionRequest{
|
||||
SessionId: createResp.GetSessionId(),
|
||||
Checks: &session.Checks{
|
||||
IdpIntent: &session.CheckIDPIntent{
|
||||
IdpIntentId: intentID,
|
||||
IdpIntentToken: token,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func registerTOTP(ctx context.Context, t *testing.T, userID string) (secret string) {
|
||||
resp, err := Instance.Client.UserV2.RegisterTOTP(ctx, &user.RegisterTOTPRequest{
|
||||
UserId: userID,
|
||||
|
@@ -20,7 +20,6 @@ import (
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/grpc"
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
"github.com/zitadel/zitadel/internal/integration/sink"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/auth"
|
||||
@@ -1307,7 +1306,6 @@ func TestServer_UpdateHumanUser_Permission(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
got, err := Client.UpdateHumanUser(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
@@ -2114,18 +2112,43 @@ func TestServer_StartIdentityProviderIntent(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
idpID := Instance.AddGenericOAuthProvider(IamCTX, gofakeit.AppName()).GetId()
|
||||
intentID := Instance.CreateIntent(CTX, idpID).GetIdpIntent().GetIdpIntentId()
|
||||
oauthIdpID := Instance.AddGenericOAuthProvider(IamCTX, gofakeit.AppName()).GetId()
|
||||
oidcIdpID := Instance.AddGenericOIDCProvider(IamCTX, gofakeit.AppName()).GetId()
|
||||
samlIdpID := Instance.AddSAMLPostProvider(IamCTX)
|
||||
ldapIdpID := Instance.AddLDAPProvider(IamCTX)
|
||||
authURL, err := url.Parse(Instance.CreateIntent(CTX, oauthIdpID).GetAuthUrl())
|
||||
require.NoError(t, err)
|
||||
intentID := authURL.Query().Get("state")
|
||||
expiry := time.Now().Add(1 * time.Hour)
|
||||
expiryFormatted := expiry.Round(time.Millisecond).UTC().Format("2006-01-02T15:04:05.999Z07:00")
|
||||
|
||||
successfulID, token, changeDate, sequence, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", "")
|
||||
intentUser := Instance.CreateHumanUser(IamCTX)
|
||||
_, err = Instance.CreateUserIDPlink(IamCTX, intentUser.GetUserId(), "idpUserID", oauthIdpID, "username")
|
||||
require.NoError(t, err)
|
||||
successfulWithUserID, withUsertoken, withUserchangeDate, withUsersequence, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", "user")
|
||||
|
||||
successfulID, token, changeDate, sequence, err := sink.SuccessfulOAuthIntent(Instance.ID(), oauthIdpID, "id", "", expiry)
|
||||
require.NoError(t, err)
|
||||
ldapSuccessfulID, ldapToken, ldapChangeDate, ldapSequence, err := sink.SuccessfulLDAPIntent(Instance.ID(), idpID, "id", "")
|
||||
successfulWithUserID, withUsertoken, withUserchangeDate, withUsersequence, err := sink.SuccessfulOAuthIntent(Instance.ID(), oauthIdpID, "id", "user", expiry)
|
||||
require.NoError(t, err)
|
||||
ldapSuccessfulWithUserID, ldapWithUserToken, ldapWithUserChangeDate, ldapWithUserSequence, err := sink.SuccessfulLDAPIntent(Instance.ID(), idpID, "id", "user")
|
||||
successfulExpiredID, expiredToken, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), oauthIdpID, "id", "user", time.Now().Add(time.Second))
|
||||
require.NoError(t, err)
|
||||
samlSuccessfulID, samlToken, samlChangeDate, samlSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), idpID, "id", "")
|
||||
// make sure the intent is expired
|
||||
time.Sleep(2 * time.Second)
|
||||
successfulConsumedID, consumedToken, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), oauthIdpID, "idpUserID", intentUser.GetUserId(), expiry)
|
||||
require.NoError(t, err)
|
||||
// make sure the intent is consumed
|
||||
Instance.CreateIntentSession(t, IamCTX, intentUser.GetUserId(), successfulConsumedID, consumedToken)
|
||||
oidcSuccessful, oidcToken, oidcChangeDate, oidcSequence, err := sink.SuccessfulOIDCIntent(Instance.ID(), oidcIdpID, "id", "", expiry)
|
||||
require.NoError(t, err)
|
||||
oidcSuccessfulWithUserID, oidcWithUserIDToken, oidcWithUserIDChangeDate, oidcWithUserIDSequence, err := sink.SuccessfulOIDCIntent(Instance.ID(), oidcIdpID, "id", "user", expiry)
|
||||
require.NoError(t, err)
|
||||
ldapSuccessfulID, ldapToken, ldapChangeDate, ldapSequence, err := sink.SuccessfulLDAPIntent(Instance.ID(), ldapIdpID, "id", "")
|
||||
require.NoError(t, err)
|
||||
ldapSuccessfulWithUserID, ldapWithUserToken, ldapWithUserChangeDate, ldapWithUserSequence, err := sink.SuccessfulLDAPIntent(Instance.ID(), ldapIdpID, "id", "user")
|
||||
require.NoError(t, err)
|
||||
samlSuccessfulID, samlToken, samlChangeDate, samlSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), samlIdpID, "id", "", expiry)
|
||||
require.NoError(t, err)
|
||||
samlSuccessfulWithUserID, samlWithUserToken, samlWithUserChangeDate, samlWithUserSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), samlIdpID, "id", "user", expiry)
|
||||
require.NoError(t, err)
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -2160,7 +2183,7 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "retrieve successful intent",
|
||||
name: "retrieve successful oauth intent",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.RetrieveIdentityProviderIntentRequest{
|
||||
@@ -2181,13 +2204,15 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
IdToken: gu.Ptr("idToken"),
|
||||
},
|
||||
},
|
||||
IdpId: idpID,
|
||||
IdpId: oauthIdpID,
|
||||
UserId: "id",
|
||||
UserName: "username",
|
||||
UserName: "",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
s, err := structpb.NewStruct(map[string]interface{}{
|
||||
"sub": "id",
|
||||
"preferred_username": "username",
|
||||
"RawInfo": map[string]interface{}{
|
||||
"id": "id",
|
||||
"preferred_username": "username",
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
@@ -2219,7 +2244,107 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
IdToken: gu.Ptr("idToken"),
|
||||
},
|
||||
},
|
||||
IdpId: idpID,
|
||||
IdpId: oauthIdpID,
|
||||
UserId: "id",
|
||||
UserName: "",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
s, err := structpb.NewStruct(map[string]interface{}{
|
||||
"RawInfo": map[string]interface{}{
|
||||
"id": "id",
|
||||
"preferred_username": "username",
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "retrieve successful expired intent",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.RetrieveIdentityProviderIntentRequest{
|
||||
IdpIntentId: successfulExpiredID,
|
||||
IdpIntentToken: expiredToken,
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "retrieve successful consumed intent",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.RetrieveIdentityProviderIntentRequest{
|
||||
IdpIntentId: successfulConsumedID,
|
||||
IdpIntentToken: consumedToken,
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "retrieve successful oidc intent",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.RetrieveIdentityProviderIntentRequest{
|
||||
IdpIntentId: oidcSuccessful,
|
||||
IdpIntentToken: oidcToken,
|
||||
},
|
||||
},
|
||||
want: &user.RetrieveIdentityProviderIntentResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.New(oidcChangeDate),
|
||||
ResourceOwner: Instance.ID(),
|
||||
Sequence: oidcSequence,
|
||||
},
|
||||
UserId: "",
|
||||
IdpInformation: &user.IDPInformation{
|
||||
Access: &user.IDPInformation_Oauth{
|
||||
Oauth: &user.IDPOAuthAccessInformation{
|
||||
AccessToken: "accessToken",
|
||||
IdToken: gu.Ptr("idToken"),
|
||||
},
|
||||
},
|
||||
IdpId: oidcIdpID,
|
||||
UserId: "id",
|
||||
UserName: "username",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
s, err := structpb.NewStruct(map[string]interface{}{
|
||||
"sub": "id",
|
||||
"preferred_username": "username",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "retrieve successful oidc intent with linked user",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.RetrieveIdentityProviderIntentRequest{
|
||||
IdpIntentId: oidcSuccessfulWithUserID,
|
||||
IdpIntentToken: oidcWithUserIDToken,
|
||||
},
|
||||
},
|
||||
want: &user.RetrieveIdentityProviderIntentResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.New(oidcWithUserIDChangeDate),
|
||||
ResourceOwner: Instance.ID(),
|
||||
Sequence: oidcWithUserIDSequence,
|
||||
},
|
||||
UserId: "user",
|
||||
IdpInformation: &user.IDPInformation{
|
||||
Access: &user.IDPInformation_Oauth{
|
||||
Oauth: &user.IDPOAuthAccessInformation{
|
||||
AccessToken: "accessToken",
|
||||
IdToken: gu.Ptr("idToken"),
|
||||
},
|
||||
},
|
||||
IdpId: oidcIdpID,
|
||||
UserId: "id",
|
||||
UserName: "username",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
@@ -2263,7 +2388,7 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
}(),
|
||||
},
|
||||
},
|
||||
IdpId: idpID,
|
||||
IdpId: ldapIdpID,
|
||||
UserId: "id",
|
||||
UserName: "username",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
@@ -2309,7 +2434,7 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
}(),
|
||||
},
|
||||
},
|
||||
IdpId: idpID,
|
||||
IdpId: ldapIdpID,
|
||||
UserId: "id",
|
||||
UserName: "username",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
@@ -2343,10 +2468,10 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
IdpInformation: &user.IDPInformation{
|
||||
Access: &user.IDPInformation_Saml{
|
||||
Saml: &user.IDPSAMLAccessInformation{
|
||||
Assertion: []byte("<Assertion xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"id\" IssueInstant=\"0001-01-01T00:00:00Z\" Version=\"\"><Issuer xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" NameQualifier=\"\" SPNameQualifier=\"\" Format=\"\" SPProvidedID=\"\"></Issuer></Assertion>"),
|
||||
Assertion: []byte(fmt.Sprintf(`<Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="id" IssueInstant="0001-01-01T00:00:00Z" Version=""><Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion" NameQualifier="" SPNameQualifier="" Format="" SPProvidedID=""></Issuer><Conditions NotBefore="0001-01-01T00:00:00Z" NotOnOrAfter="%s"></Conditions></Assertion>`, expiryFormatted)),
|
||||
},
|
||||
},
|
||||
IdpId: idpID,
|
||||
IdpId: samlIdpID,
|
||||
UserId: "id",
|
||||
UserName: "",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
@@ -2363,17 +2488,56 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "retrieve successful saml intent with linked user",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.RetrieveIdentityProviderIntentRequest{
|
||||
IdpIntentId: samlSuccessfulWithUserID,
|
||||
IdpIntentToken: samlWithUserToken,
|
||||
},
|
||||
},
|
||||
want: &user.RetrieveIdentityProviderIntentResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.New(samlWithUserChangeDate),
|
||||
ResourceOwner: Instance.ID(),
|
||||
Sequence: samlWithUserSequence,
|
||||
},
|
||||
IdpInformation: &user.IDPInformation{
|
||||
Access: &user.IDPInformation_Saml{
|
||||
Saml: &user.IDPSAMLAccessInformation{
|
||||
Assertion: []byte(fmt.Sprintf(`<Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="id" IssueInstant="0001-01-01T00:00:00Z" Version=""><Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion" NameQualifier="" SPNameQualifier="" Format="" SPProvidedID=""></Issuer><Conditions NotBefore="0001-01-01T00:00:00Z" NotOnOrAfter="%s"></Conditions></Assertion>`, expiryFormatted)),
|
||||
},
|
||||
},
|
||||
IdpId: samlIdpID,
|
||||
UserId: "id",
|
||||
UserName: "",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
s, err := structpb.NewStruct(map[string]interface{}{
|
||||
"id": "id",
|
||||
"attributes": map[string]interface{}{
|
||||
"attribute1": []interface{}{"value1"},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
UserId: "user",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := Client.RetrieveIdentityProviderIntent(tt.args.ctx, tt.args.req)
|
||||
if tt.wantErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
grpc.AllFieldsEqual(t, tt.want.ProtoReflect(), got.ProtoReflect(), grpc.CustomMappers)
|
||||
assert.EqualExportedValues(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2873,7 +3037,6 @@ func TestServer_ListAuthenticationFactors(t *testing.T) {
|
||||
|
||||
assert.ElementsMatch(t, tt.want.GetResult(), got.GetResult())
|
||||
}, retryDuration, tick, "timeout waiting for expected auth methods result")
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
@@ -396,14 +397,14 @@ func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredenti
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
externalUser, userID, attributes, err := s.ldapLogin(ctx, intentWriteModel.IDPID, ldapCredentials.GetUsername(), ldapCredentials.GetPassword())
|
||||
externalUser, userID, session, err := s.ldapLogin(ctx, intentWriteModel.IDPID, ldapCredentials.GetUsername(), ldapCredentials.GetPassword())
|
||||
if err != nil {
|
||||
if err := s.command.FailIDPIntent(ctx, intentWriteModel, err.Error()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
token, err := s.command.SucceedLDAPIDPIntent(ctx, intentWriteModel, externalUser, userID, attributes)
|
||||
token, err := s.command.SucceedLDAPIDPIntent(ctx, intentWriteModel, externalUser, userID, session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -441,7 +442,7 @@ func (s *Server) checkLinkedExternalUser(ctx context.Context, idpID, externalUse
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (s *Server) ldapLogin(ctx context.Context, idpID, username, password string) (idp.User, string, map[string][]string, error) {
|
||||
func (s *Server) ldapLogin(ctx context.Context, idpID, username, password string) (idp.User, string, *ldap.Session, error) {
|
||||
provider, err := s.command.GetProvider(ctx, idpID, "", "")
|
||||
if err != nil {
|
||||
return nil, "", nil, err
|
||||
@@ -462,12 +463,7 @@ func (s *Server) ldapLogin(ctx context.Context, idpID, username, password string
|
||||
if err != nil {
|
||||
return nil, "", nil, err
|
||||
}
|
||||
|
||||
attributes := make(map[string][]string, 0)
|
||||
for _, item := range session.Entry.Attributes {
|
||||
attributes[item.Name] = item.Values
|
||||
}
|
||||
return externalUser, userID, attributes, nil
|
||||
return externalUser, userID, session, nil
|
||||
}
|
||||
|
||||
func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.RetrieveIdentityProviderIntentRequest) (_ *user.RetrieveIdentityProviderIntentResponse, err error) {
|
||||
@@ -481,6 +477,9 @@ func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.R
|
||||
if intent.State != domain.IDPIntentStateSucceeded {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "IDP-nme4gszsvx", "Errors.Intent.NotSucceeded")
|
||||
}
|
||||
if time.Now().After(intent.ExpiresAt()) {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "IDP-SAf42", "Errors.Intent.Expired")
|
||||
}
|
||||
return idpIntentToIDPIntentPb(intent, s.idpAlg)
|
||||
}
|
||||
|
||||
|
@@ -2146,17 +2146,43 @@ func TestServer_StartIdentityProviderIntent(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
idpID := Instance.AddGenericOAuthProvider(IamCTX, gofakeit.AppName()).GetId()
|
||||
intentID := Instance.CreateIntent(CTX, idpID).GetIdpIntent().GetIdpIntentId()
|
||||
successfulID, token, changeDate, sequence, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", "")
|
||||
oauthIdpID := Instance.AddGenericOAuthProvider(IamCTX, gofakeit.AppName()).GetId()
|
||||
oidcIdpID := Instance.AddGenericOIDCProvider(IamCTX, gofakeit.AppName()).GetId()
|
||||
samlIdpID := Instance.AddSAMLPostProvider(IamCTX)
|
||||
ldapIdpID := Instance.AddLDAPProvider(IamCTX)
|
||||
authURL, err := url.Parse(Instance.CreateIntent(CTX, oauthIdpID).GetAuthUrl())
|
||||
require.NoError(t, err)
|
||||
successfulWithUserID, withUsertoken, withUserchangeDate, withUsersequence, err := sink.SuccessfulOAuthIntent(Instance.ID(), idpID, "id", "user")
|
||||
intentID := authURL.Query().Get("state")
|
||||
expiry := time.Now().Add(1 * time.Hour)
|
||||
expiryFormatted := expiry.Round(time.Millisecond).UTC().Format("2006-01-02T15:04:05.999Z07:00")
|
||||
|
||||
intentUser := Instance.CreateHumanUser(IamCTX)
|
||||
_, err = Instance.CreateUserIDPlink(IamCTX, intentUser.GetUserId(), "idpUserID", oauthIdpID, "username")
|
||||
require.NoError(t, err)
|
||||
ldapSuccessfulID, ldapToken, ldapChangeDate, ldapSequence, err := sink.SuccessfulLDAPIntent(Instance.ID(), idpID, "id", "")
|
||||
|
||||
successfulID, token, changeDate, sequence, err := sink.SuccessfulOAuthIntent(Instance.ID(), oauthIdpID, "id", "", expiry)
|
||||
require.NoError(t, err)
|
||||
ldapSuccessfulWithUserID, ldapWithUserToken, ldapWithUserChangeDate, ldapWithUserSequence, err := sink.SuccessfulLDAPIntent(Instance.ID(), idpID, "id", "user")
|
||||
successfulWithUserID, withUsertoken, withUserchangeDate, withUsersequence, err := sink.SuccessfulOAuthIntent(Instance.ID(), oauthIdpID, "id", "user", expiry)
|
||||
require.NoError(t, err)
|
||||
samlSuccessfulID, samlToken, samlChangeDate, samlSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), idpID, "id", "")
|
||||
successfulExpiredID, expiredToken, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), oauthIdpID, "id", "user", time.Now().Add(time.Second))
|
||||
require.NoError(t, err)
|
||||
// make sure the intent is expired
|
||||
time.Sleep(2 * time.Second)
|
||||
successfulConsumedID, consumedToken, _, _, err := sink.SuccessfulOAuthIntent(Instance.ID(), oauthIdpID, "idpUserID", intentUser.GetUserId(), expiry)
|
||||
require.NoError(t, err)
|
||||
// make sure the intent is consumed
|
||||
Instance.CreateIntentSession(t, IamCTX, intentUser.GetUserId(), successfulConsumedID, consumedToken)
|
||||
oidcSuccessful, oidcToken, oidcChangeDate, oidcSequence, err := sink.SuccessfulOIDCIntent(Instance.ID(), oidcIdpID, "id", "", expiry)
|
||||
require.NoError(t, err)
|
||||
oidcSuccessfulWithUserID, oidcWithUserIDToken, oidcWithUserIDChangeDate, oidcWithUserIDSequence, err := sink.SuccessfulOIDCIntent(Instance.ID(), oidcIdpID, "id", "user", expiry)
|
||||
require.NoError(t, err)
|
||||
ldapSuccessfulID, ldapToken, ldapChangeDate, ldapSequence, err := sink.SuccessfulLDAPIntent(Instance.ID(), ldapIdpID, "id", "")
|
||||
require.NoError(t, err)
|
||||
ldapSuccessfulWithUserID, ldapWithUserToken, ldapWithUserChangeDate, ldapWithUserSequence, err := sink.SuccessfulLDAPIntent(Instance.ID(), ldapIdpID, "id", "user")
|
||||
require.NoError(t, err)
|
||||
samlSuccessfulID, samlToken, samlChangeDate, samlSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), samlIdpID, "id", "", expiry)
|
||||
require.NoError(t, err)
|
||||
samlSuccessfulWithUserID, samlWithUserToken, samlWithUserChangeDate, samlWithUserSequence, err := sink.SuccessfulSAMLIntent(Instance.ID(), samlIdpID, "id", "user", expiry)
|
||||
require.NoError(t, err)
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -2191,7 +2217,7 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "retrieve successful intent",
|
||||
name: "retrieve successful oauth intent",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.RetrieveIdentityProviderIntentRequest{
|
||||
@@ -2212,13 +2238,15 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
IdToken: gu.Ptr("idToken"),
|
||||
},
|
||||
},
|
||||
IdpId: idpID,
|
||||
IdpId: oauthIdpID,
|
||||
UserId: "id",
|
||||
UserName: "username",
|
||||
UserName: "",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
s, err := structpb.NewStruct(map[string]interface{}{
|
||||
"sub": "id",
|
||||
"preferred_username": "username",
|
||||
"RawInfo": map[string]interface{}{
|
||||
"id": "id",
|
||||
"preferred_username": "username",
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
@@ -2250,7 +2278,107 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
IdToken: gu.Ptr("idToken"),
|
||||
},
|
||||
},
|
||||
IdpId: idpID,
|
||||
IdpId: oauthIdpID,
|
||||
UserId: "id",
|
||||
UserName: "",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
s, err := structpb.NewStruct(map[string]interface{}{
|
||||
"RawInfo": map[string]interface{}{
|
||||
"id": "id",
|
||||
"preferred_username": "username",
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "retrieve successful expired intent",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.RetrieveIdentityProviderIntentRequest{
|
||||
IdpIntentId: successfulExpiredID,
|
||||
IdpIntentToken: expiredToken,
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "retrieve successful consumed intent",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.RetrieveIdentityProviderIntentRequest{
|
||||
IdpIntentId: successfulConsumedID,
|
||||
IdpIntentToken: consumedToken,
|
||||
},
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "retrieve successful oidc intent",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.RetrieveIdentityProviderIntentRequest{
|
||||
IdpIntentId: oidcSuccessful,
|
||||
IdpIntentToken: oidcToken,
|
||||
},
|
||||
},
|
||||
want: &user.RetrieveIdentityProviderIntentResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.New(oidcChangeDate),
|
||||
ResourceOwner: Instance.ID(),
|
||||
Sequence: oidcSequence,
|
||||
},
|
||||
UserId: "",
|
||||
IdpInformation: &user.IDPInformation{
|
||||
Access: &user.IDPInformation_Oauth{
|
||||
Oauth: &user.IDPOAuthAccessInformation{
|
||||
AccessToken: "accessToken",
|
||||
IdToken: gu.Ptr("idToken"),
|
||||
},
|
||||
},
|
||||
IdpId: oidcIdpID,
|
||||
UserId: "id",
|
||||
UserName: "username",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
s, err := structpb.NewStruct(map[string]interface{}{
|
||||
"sub": "id",
|
||||
"preferred_username": "username",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "retrieve successful oidc intent with linked user",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.RetrieveIdentityProviderIntentRequest{
|
||||
IdpIntentId: oidcSuccessfulWithUserID,
|
||||
IdpIntentToken: oidcWithUserIDToken,
|
||||
},
|
||||
},
|
||||
want: &user.RetrieveIdentityProviderIntentResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.New(oidcWithUserIDChangeDate),
|
||||
ResourceOwner: Instance.ID(),
|
||||
Sequence: oidcWithUserIDSequence,
|
||||
},
|
||||
UserId: "user",
|
||||
IdpInformation: &user.IDPInformation{
|
||||
Access: &user.IDPInformation_Oauth{
|
||||
Oauth: &user.IDPOAuthAccessInformation{
|
||||
AccessToken: "accessToken",
|
||||
IdToken: gu.Ptr("idToken"),
|
||||
},
|
||||
},
|
||||
IdpId: oidcIdpID,
|
||||
UserId: "id",
|
||||
UserName: "username",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
@@ -2294,7 +2422,7 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
}(),
|
||||
},
|
||||
},
|
||||
IdpId: idpID,
|
||||
IdpId: ldapIdpID,
|
||||
UserId: "id",
|
||||
UserName: "username",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
@@ -2340,7 +2468,7 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
}(),
|
||||
},
|
||||
},
|
||||
IdpId: idpID,
|
||||
IdpId: ldapIdpID,
|
||||
UserId: "id",
|
||||
UserName: "username",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
@@ -2374,10 +2502,10 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
IdpInformation: &user.IDPInformation{
|
||||
Access: &user.IDPInformation_Saml{
|
||||
Saml: &user.IDPSAMLAccessInformation{
|
||||
Assertion: []byte("<Assertion xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\"id\" IssueInstant=\"0001-01-01T00:00:00Z\" Version=\"\"><Issuer xmlns=\"urn:oasis:names:tc:SAML:2.0:assertion\" NameQualifier=\"\" SPNameQualifier=\"\" Format=\"\" SPProvidedID=\"\"></Issuer></Assertion>"),
|
||||
Assertion: []byte(fmt.Sprintf(`<Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="id" IssueInstant="0001-01-01T00:00:00Z" Version=""><Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion" NameQualifier="" SPNameQualifier="" Format="" SPProvidedID=""></Issuer><Conditions NotBefore="0001-01-01T00:00:00Z" NotOnOrAfter="%s"></Conditions></Assertion>`, expiryFormatted)),
|
||||
},
|
||||
},
|
||||
IdpId: idpID,
|
||||
IdpId: samlIdpID,
|
||||
UserId: "id",
|
||||
UserName: "",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
@@ -2394,6 +2522,45 @@ func TestServer_RetrieveIdentityProviderIntent(t *testing.T) {
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "retrieve successful saml intent with linked user",
|
||||
args: args{
|
||||
CTX,
|
||||
&user.RetrieveIdentityProviderIntentRequest{
|
||||
IdpIntentId: samlSuccessfulWithUserID,
|
||||
IdpIntentToken: samlWithUserToken,
|
||||
},
|
||||
},
|
||||
want: &user.RetrieveIdentityProviderIntentResponse{
|
||||
Details: &object.Details{
|
||||
ChangeDate: timestamppb.New(samlWithUserChangeDate),
|
||||
ResourceOwner: Instance.ID(),
|
||||
Sequence: samlWithUserSequence,
|
||||
},
|
||||
IdpInformation: &user.IDPInformation{
|
||||
Access: &user.IDPInformation_Saml{
|
||||
Saml: &user.IDPSAMLAccessInformation{
|
||||
Assertion: []byte(fmt.Sprintf(`<Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="id" IssueInstant="0001-01-01T00:00:00Z" Version=""><Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion" NameQualifier="" SPNameQualifier="" Format="" SPProvidedID=""></Issuer><Conditions NotBefore="0001-01-01T00:00:00Z" NotOnOrAfter="%s"></Conditions></Assertion>`, expiryFormatted)),
|
||||
},
|
||||
},
|
||||
IdpId: samlIdpID,
|
||||
UserId: "id",
|
||||
UserName: "",
|
||||
RawInformation: func() *structpb.Struct {
|
||||
s, err := structpb.NewStruct(map[string]interface{}{
|
||||
"id": "id",
|
||||
"attributes": map[string]interface{}{
|
||||
"attribute1": []interface{}{"value1"},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return s
|
||||
}(),
|
||||
},
|
||||
UserId: "user",
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
@@ -399,14 +400,14 @@ func (s *Server) startLDAPIntent(ctx context.Context, idpID string, ldapCredenti
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
externalUser, userID, attributes, err := s.ldapLogin(ctx, intentWriteModel.IDPID, ldapCredentials.GetUsername(), ldapCredentials.GetPassword())
|
||||
externalUser, userID, session, err := s.ldapLogin(ctx, intentWriteModel.IDPID, ldapCredentials.GetUsername(), ldapCredentials.GetPassword())
|
||||
if err != nil {
|
||||
if err := s.command.FailIDPIntent(ctx, intentWriteModel, err.Error()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
token, err := s.command.SucceedLDAPIDPIntent(ctx, intentWriteModel, externalUser, userID, attributes)
|
||||
token, err := s.command.SucceedLDAPIDPIntent(ctx, intentWriteModel, externalUser, userID, session)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -444,7 +445,7 @@ func (s *Server) checkLinkedExternalUser(ctx context.Context, idpID, externalUse
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (s *Server) ldapLogin(ctx context.Context, idpID, username, password string) (idp.User, string, map[string][]string, error) {
|
||||
func (s *Server) ldapLogin(ctx context.Context, idpID, username, password string) (idp.User, string, *ldap.Session, error) {
|
||||
provider, err := s.command.GetProvider(ctx, idpID, "", "")
|
||||
if err != nil {
|
||||
return nil, "", nil, err
|
||||
@@ -470,7 +471,7 @@ func (s *Server) ldapLogin(ctx context.Context, idpID, username, password string
|
||||
for _, item := range session.Entry.Attributes {
|
||||
attributes[item.Name] = item.Values
|
||||
}
|
||||
return externalUser, userID, attributes, nil
|
||||
return externalUser, userID, session, nil
|
||||
}
|
||||
|
||||
func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.RetrieveIdentityProviderIntentRequest) (_ *user.RetrieveIdentityProviderIntentResponse, err error) {
|
||||
@@ -484,6 +485,9 @@ func (s *Server) RetrieveIdentityProviderIntent(ctx context.Context, req *user.R
|
||||
if intent.State != domain.IDPIntentStateSucceeded {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "IDP-nme4gszsvx", "Errors.Intent.NotSucceeded")
|
||||
}
|
||||
if time.Now().After(intent.ExpiresAt()) {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "IDP-Afb2s", "Errors.Intent.Expired")
|
||||
}
|
||||
return idpIntentToIDPIntentPb(intent, s.idpAlg)
|
||||
}
|
||||
|
||||
|
@@ -287,7 +287,7 @@ func (h *Handler) handleACS(w http.ResponseWriter, r *http.Request) {
|
||||
userID, err := h.checkExternalUser(ctx, intent.IDPID, idpUser.GetID())
|
||||
logging.WithFields("intent", intent.AggregateID).OnError(err).Error("could not check if idp user already exists")
|
||||
|
||||
token, err := h.commands.SucceedSAMLIDPIntent(ctx, intent, idpUser, userID, session.Assertion)
|
||||
token, err := h.commands.SucceedSAMLIDPIntent(ctx, intent, idpUser, userID, session)
|
||||
if err != nil {
|
||||
redirectToFailureURLErr(w, r, intent, zerrors.ThrowInternal(err, "IDP-JdD3g", "Errors.Intent.TokenCreationFailed"))
|
||||
return
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
@@ -14,11 +15,12 @@ import (
|
||||
|
||||
func Test_redirectToSuccessURL(t *testing.T) {
|
||||
type args struct {
|
||||
id string
|
||||
userID string
|
||||
token string
|
||||
failureURL string
|
||||
successURL string
|
||||
id string
|
||||
userID string
|
||||
token string
|
||||
failureURL string
|
||||
successURL string
|
||||
maxIdPIntentLifetime time.Duration
|
||||
}
|
||||
type res struct {
|
||||
want string
|
||||
@@ -59,7 +61,7 @@ func Test_redirectToSuccessURL(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "http://example.com", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
wm := command.NewIDPIntentWriteModel(tt.args.id, tt.args.id)
|
||||
wm := command.NewIDPIntentWriteModel(tt.args.id, tt.args.id, tt.args.maxIdPIntentLifetime)
|
||||
wm.FailureURL, _ = url.Parse(tt.args.failureURL)
|
||||
wm.SuccessURL, _ = url.Parse(tt.args.successURL)
|
||||
|
||||
@@ -71,11 +73,12 @@ func Test_redirectToSuccessURL(t *testing.T) {
|
||||
|
||||
func Test_redirectToFailureURL(t *testing.T) {
|
||||
type args struct {
|
||||
id string
|
||||
failureURL string
|
||||
successURL string
|
||||
err string
|
||||
desc string
|
||||
id string
|
||||
failureURL string
|
||||
successURL string
|
||||
err string
|
||||
desc string
|
||||
maxIdPIntentLifetime time.Duration
|
||||
}
|
||||
type res struct {
|
||||
want string
|
||||
@@ -115,7 +118,7 @@ func Test_redirectToFailureURL(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "http://example.com", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
wm := command.NewIDPIntentWriteModel(tt.args.id, tt.args.id)
|
||||
wm := command.NewIDPIntentWriteModel(tt.args.id, tt.args.id, tt.args.maxIdPIntentLifetime)
|
||||
wm.FailureURL, _ = url.Parse(tt.args.failureURL)
|
||||
wm.SuccessURL, _ = url.Parse(tt.args.successURL)
|
||||
|
||||
@@ -127,10 +130,11 @@ func Test_redirectToFailureURL(t *testing.T) {
|
||||
|
||||
func Test_redirectToFailureURLErr(t *testing.T) {
|
||||
type args struct {
|
||||
id string
|
||||
failureURL string
|
||||
successURL string
|
||||
err error
|
||||
id string
|
||||
failureURL string
|
||||
successURL string
|
||||
err error
|
||||
maxIdPIntentLifetime time.Duration
|
||||
}
|
||||
type res struct {
|
||||
want string
|
||||
@@ -158,7 +162,7 @@ func Test_redirectToFailureURLErr(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "http://example.com", nil)
|
||||
resp := httptest.NewRecorder()
|
||||
|
||||
wm := command.NewIDPIntentWriteModel(tt.args.id, tt.args.id)
|
||||
wm := command.NewIDPIntentWriteModel(tt.args.id, tt.args.id, tt.args.maxIdPIntentLifetime)
|
||||
wm.FailureURL, _ = url.Parse(tt.args.failureURL)
|
||||
wm.SuccessURL, _ = url.Parse(tt.args.successURL)
|
||||
|
||||
|
Reference in New Issue
Block a user