mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 20:57:24 +00:00
feat: add possibility to set an expiration to a session (#6851)
* add lifetime to session api * extend session with lifetime * check session token expiration * fix typo * integration test to check session token expiration * integration test to check session token expiration * i18n * cleanup * improve tests * prevent negative lifetime * fix error message * fix lifetime check
This commit is contained in:
parent
ce322323aa
commit
f3b8a3aece
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"google.golang.org/protobuf/types/known/structpb"
|
"google.golang.org/protobuf/types/known/structpb"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
@ -46,7 +47,7 @@ func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequ
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRequest) (*session.CreateSessionResponse, error) {
|
func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRequest) (*session.CreateSessionResponse, error) {
|
||||||
checks, metadata, userAgent, err := s.createSessionRequestToCommand(ctx, req)
|
checks, metadata, userAgent, lifetime, err := s.createSessionRequestToCommand(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -55,7 +56,7 @@ func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRe
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
set, err := s.command.CreateSession(ctx, cmds, metadata, userAgent)
|
set, err := s.command.CreateSession(ctx, cmds, metadata, userAgent, lifetime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -78,7 +79,7 @@ func (s *Server) SetSession(ctx context.Context, req *session.SetSessionRequest)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
set, err := s.command.UpdateSession(ctx, req.GetSessionId(), req.GetSessionToken(), cmds, req.GetMetadata())
|
set, err := s.command.UpdateSession(ctx, req.GetSessionId(), req.GetSessionToken(), cmds, req.GetMetadata(), req.GetLifetime().AsDuration())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -113,13 +114,14 @@ func sessionsToPb(sessions []*query.Session) []*session.Session {
|
|||||||
|
|
||||||
func sessionToPb(s *query.Session) *session.Session {
|
func sessionToPb(s *query.Session) *session.Session {
|
||||||
return &session.Session{
|
return &session.Session{
|
||||||
Id: s.ID,
|
Id: s.ID,
|
||||||
CreationDate: timestamppb.New(s.CreationDate),
|
CreationDate: timestamppb.New(s.CreationDate),
|
||||||
ChangeDate: timestamppb.New(s.ChangeDate),
|
ChangeDate: timestamppb.New(s.ChangeDate),
|
||||||
Sequence: s.Sequence,
|
Sequence: s.Sequence,
|
||||||
Factors: factorsToPb(s),
|
Factors: factorsToPb(s),
|
||||||
Metadata: s.Metadata,
|
Metadata: s.Metadata,
|
||||||
UserAgent: userAgentToPb(s.UserAgent),
|
UserAgent: userAgentToPb(s.UserAgent),
|
||||||
|
ExpirationDate: expirationToPb(s.Expiration),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +149,13 @@ func userAgentToPb(ua domain.UserAgent) *session.UserAgent {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func expirationToPb(expiration time.Time) *timestamppb.Timestamp {
|
||||||
|
if expiration.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return timestamppb.New(expiration)
|
||||||
|
}
|
||||||
|
|
||||||
func factorsToPb(s *query.Session) *session.Factors {
|
func factorsToPb(s *query.Session) *session.Factors {
|
||||||
user := userFactorToPb(s.UserFactor)
|
user := userFactorToPb(s.UserFactor)
|
||||||
if user == nil {
|
if user == nil {
|
||||||
@ -268,12 +277,12 @@ func idsQueryToQuery(q *session.IDsQuery) (query.SearchQuery, error) {
|
|||||||
return query.NewSessionIDsSearchQuery(q.Ids)
|
return query.NewSessionIDsSearchQuery(q.Ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) createSessionRequestToCommand(ctx context.Context, req *session.CreateSessionRequest) ([]command.SessionCommand, map[string][]byte, *domain.UserAgent, error) {
|
func (s *Server) createSessionRequestToCommand(ctx context.Context, req *session.CreateSessionRequest) ([]command.SessionCommand, map[string][]byte, *domain.UserAgent, time.Duration, error) {
|
||||||
checks, err := s.checksToCommand(ctx, req.Checks)
|
checks, err := s.checksToCommand(ctx, req.Checks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, 0, err
|
||||||
}
|
}
|
||||||
return checks, req.GetMetadata(), userAgentToCommand(req.GetUserAgent()), nil
|
return checks, req.GetMetadata(), userAgentToCommand(req.GetUserAgent()), req.GetLifetime().AsDuration(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func userAgentToCommand(userAgent *session.UserAgent) *domain.UserAgent {
|
func userAgentToCommand(userAgent *session.UserAgent) *domain.UserAgent {
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/integration"
|
"github.com/zitadel/zitadel/internal/integration"
|
||||||
object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
|
object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
|
||||||
@ -54,7 +55,7 @@ func TestMain(m *testing.M) {
|
|||||||
}())
|
}())
|
||||||
}
|
}
|
||||||
|
|
||||||
func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, window time.Duration, metadata map[string][]byte, userAgent *session.UserAgent, factors ...wantFactor) *session.Session {
|
func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, window time.Duration, metadata map[string][]byte, userAgent *session.UserAgent, expirationWindow time.Duration, factors ...wantFactor) *session.Session {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
require.NotEmpty(t, id)
|
require.NotEmpty(t, id)
|
||||||
require.NotEmpty(t, token)
|
require.NotEmpty(t, token)
|
||||||
@ -75,6 +76,11 @@ func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, windo
|
|||||||
if !proto.Equal(userAgent, s.GetUserAgent()) {
|
if !proto.Equal(userAgent, s.GetUserAgent()) {
|
||||||
t.Errorf("user agent =\n%v\nwant\n%v", s.GetUserAgent(), userAgent)
|
t.Errorf("user agent =\n%v\nwant\n%v", s.GetUserAgent(), userAgent)
|
||||||
}
|
}
|
||||||
|
if expirationWindow == 0 {
|
||||||
|
assert.Nil(t, s.GetExpirationDate())
|
||||||
|
} else {
|
||||||
|
assert.WithinRange(t, s.GetExpirationDate().AsTime(), time.Now().Add(-expirationWindow), time.Now().Add(expirationWindow))
|
||||||
|
}
|
||||||
|
|
||||||
verifyFactors(t, s.GetFactors(), window, factors)
|
verifyFactors(t, s.GetFactors(), window, factors)
|
||||||
return s
|
return s
|
||||||
@ -137,12 +143,13 @@ func verifyFactors(t testing.TB, factors *session.Factors, window time.Duration,
|
|||||||
|
|
||||||
func TestServer_CreateSession(t *testing.T) {
|
func TestServer_CreateSession(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
req *session.CreateSessionRequest
|
req *session.CreateSessionRequest
|
||||||
want *session.CreateSessionResponse
|
want *session.CreateSessionResponse
|
||||||
wantErr bool
|
wantErr bool
|
||||||
wantFactors []wantFactor
|
wantFactors []wantFactor
|
||||||
wantUserAgent *session.UserAgent
|
wantUserAgent *session.UserAgent
|
||||||
|
wantExpirationWindow time.Duration
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty session",
|
name: "empty session",
|
||||||
@ -182,6 +189,27 @@ func TestServer_CreateSession(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "negative lifetime",
|
||||||
|
req: &session.CreateSessionRequest{
|
||||||
|
Metadata: map[string][]byte{"foo": []byte("bar")},
|
||||||
|
Lifetime: durationpb.New(-5 * time.Minute),
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "lifetime",
|
||||||
|
req: &session.CreateSessionRequest{
|
||||||
|
Metadata: map[string][]byte{"foo": []byte("bar")},
|
||||||
|
Lifetime: durationpb.New(5 * time.Minute),
|
||||||
|
},
|
||||||
|
want: &session.CreateSessionResponse{
|
||||||
|
Details: &object.Details{
|
||||||
|
ResourceOwner: Tester.Organisation.ID,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantExpirationWindow: 5 * time.Minute,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "with user",
|
name: "with user",
|
||||||
req: &session.CreateSessionRequest{
|
req: &session.CreateSessionRequest{
|
||||||
@ -253,7 +281,7 @@ func TestServer_CreateSession(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
integration.AssertDetails(t, tt.want, got)
|
integration.AssertDetails(t, tt.want, got)
|
||||||
|
|
||||||
verifyCurrentSession(t, got.GetSessionId(), got.GetSessionToken(), got.GetDetails().GetSequence(), time.Minute, tt.req.GetMetadata(), tt.wantUserAgent, tt.wantFactors...)
|
verifyCurrentSession(t, got.GetSessionId(), got.GetSessionToken(), got.GetDetails().GetSequence(), time.Minute, tt.req.GetMetadata(), tt.wantUserAgent, tt.wantExpirationWindow, tt.wantFactors...)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -276,7 +304,7 @@ func TestServer_CreateSession_webauthn(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||||
|
|
||||||
assertionData, err := Tester.WebAuthN.CreateAssertionResponse(createResp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), true)
|
assertionData, err := Tester.WebAuthN.CreateAssertionResponse(createResp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -292,7 +320,7 @@ func TestServer_CreateSession_webauthn(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactorUserVerified)
|
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantWebAuthNFactorUserVerified)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServer_CreateSession_successfulIntent(t *testing.T) {
|
func TestServer_CreateSession_successfulIntent(t *testing.T) {
|
||||||
@ -308,7 +336,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)
|
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, idpID, User.GetUserId(), "id")
|
||||||
updateResp, err := Client.SetSession(CTX, &session.SetSessionRequest{
|
updateResp, err := Client.SetSession(CTX, &session.SetSessionRequest{
|
||||||
@ -322,7 +350,7 @@ func TestServer_CreateSession_successfulIntent(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantIntentFactor)
|
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantIntentFactor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
|
func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
|
||||||
@ -338,7 +366,7 @@ func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
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, idpID, "", idpUserID)
|
||||||
@ -365,7 +393,7 @@ func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantIntentFactor)
|
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantIntentFactor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) {
|
func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) {
|
||||||
@ -381,7 +409,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)
|
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||||
|
|
||||||
intentID := Tester.CreateIntent(t, idpID)
|
intentID := Tester.CreateIntent(t, idpID)
|
||||||
_, err = Client.SetSession(CTX, &session.SetSessionRequest{
|
_, err = Client.SetSession(CTX, &session.SetSessionRequest{
|
||||||
@ -433,7 +461,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
|||||||
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{})
|
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
sessionToken := createResp.GetSessionToken()
|
sessionToken := createResp.GetSessionToken()
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, createResp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||||
|
|
||||||
t.Run("check user", func(t *testing.T) {
|
t.Run("check user", func(t *testing.T) {
|
||||||
resp, err := Client.SetSession(CTX, &session.SetSessionRequest{
|
resp, err := Client.SetSession(CTX, &session.SetSessionRequest{
|
||||||
@ -449,7 +477,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
sessionToken = resp.GetSessionToken()
|
sessionToken = resp.GetSessionToken()
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor)
|
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("check webauthn, user verified (passkey)", func(t *testing.T) {
|
t.Run("check webauthn, user verified (passkey)", func(t *testing.T) {
|
||||||
@ -464,7 +492,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||||
sessionToken = resp.GetSessionToken()
|
sessionToken = resp.GetSessionToken()
|
||||||
|
|
||||||
assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), true)
|
assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), true)
|
||||||
@ -481,7 +509,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
sessionToken = resp.GetSessionToken()
|
sessionToken = resp.GetSessionToken()
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactorUserVerified)
|
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantWebAuthNFactorUserVerified)
|
||||||
})
|
})
|
||||||
|
|
||||||
userAuthCtx := Tester.WithAuthorizationToken(CTX, sessionToken)
|
userAuthCtx := Tester.WithAuthorizationToken(CTX, sessionToken)
|
||||||
@ -508,7 +536,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||||
sessionToken = resp.GetSessionToken()
|
sessionToken = resp.GetSessionToken()
|
||||||
|
|
||||||
assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), false)
|
assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), false)
|
||||||
@ -525,7 +553,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
sessionToken = resp.GetSessionToken()
|
sessionToken = resp.GetSessionToken()
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactor)
|
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantWebAuthNFactor)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -544,7 +572,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
sessionToken = resp.GetSessionToken()
|
sessionToken = resp.GetSessionToken()
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactor, wantTOTPFactor)
|
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantWebAuthNFactor, wantTOTPFactor)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("check OTP SMS", func(t *testing.T) {
|
t.Run("check OTP SMS", func(t *testing.T) {
|
||||||
@ -556,7 +584,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||||
sessionToken = resp.GetSessionToken()
|
sessionToken = resp.GetSessionToken()
|
||||||
|
|
||||||
otp := resp.GetChallenges().GetOtpSms()
|
otp := resp.GetChallenges().GetOtpSms()
|
||||||
@ -573,7 +601,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
sessionToken = resp.GetSessionToken()
|
sessionToken = resp.GetSessionToken()
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactor, wantOTPSMSFactor)
|
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantWebAuthNFactor, wantOTPSMSFactor)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("check OTP Email", func(t *testing.T) {
|
t.Run("check OTP Email", func(t *testing.T) {
|
||||||
@ -587,7 +615,7 @@ func TestServer_SetSession_flow(t *testing.T) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil)
|
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0)
|
||||||
sessionToken = resp.GetSessionToken()
|
sessionToken = resp.GetSessionToken()
|
||||||
|
|
||||||
otp := resp.GetChallenges().GetOtpEmail()
|
otp := resp.GetChallenges().GetOtpEmail()
|
||||||
@ -604,10 +632,34 @@ func TestServer_SetSession_flow(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
sessionToken = resp.GetSessionToken()
|
sessionToken = resp.GetSessionToken()
|
||||||
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactor, wantOTPEmailFactor)
|
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, 0, wantUserFactor, wantWebAuthNFactor, wantOTPEmailFactor)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServer_SetSession_expired(t *testing.T) {
|
||||||
|
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
|
||||||
|
Lifetime: durationpb.New(20 * time.Second),
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// test session token works
|
||||||
|
sessionResp, err := Tester.Client.SessionV2.SetSession(CTX, &session.SetSessionRequest{
|
||||||
|
SessionId: createResp.GetSessionId(),
|
||||||
|
SessionToken: createResp.GetSessionToken(),
|
||||||
|
Lifetime: durationpb.New(20 * time.Second),
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// ensure session expires and does not work anymore
|
||||||
|
time.Sleep(20 * time.Second)
|
||||||
|
_, err = Tester.Client.SessionV2.SetSession(CTX, &session.SetSessionRequest{
|
||||||
|
SessionId: createResp.GetSessionId(),
|
||||||
|
SessionToken: sessionResp.GetSessionToken(),
|
||||||
|
Lifetime: durationpb.New(20 * time.Second),
|
||||||
|
})
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func Test_ZITADEL_API_missing_authentication(t *testing.T) {
|
func Test_ZITADEL_API_missing_authentication(t *testing.T) {
|
||||||
// create new, empty session
|
// create new, empty session
|
||||||
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{})
|
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{})
|
||||||
@ -629,7 +681,7 @@ func Test_ZITADEL_API_missing_mfa(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_ZITADEL_API_success(t *testing.T) {
|
func Test_ZITADEL_API_success(t *testing.T) {
|
||||||
id, token, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, User.GetUserId())
|
id, token, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, User.GetUserId())
|
||||||
|
|
||||||
ctx := Tester.WithAuthorizationToken(context.Background(), token)
|
ctx := Tester.WithAuthorizationToken(context.Background(), token)
|
||||||
sessionResp, err := Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id})
|
sessionResp, err := Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id})
|
||||||
@ -641,7 +693,7 @@ func Test_ZITADEL_API_success(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_ZITADEL_API_session_not_found(t *testing.T) {
|
func Test_ZITADEL_API_session_not_found(t *testing.T) {
|
||||||
id, token, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, User.GetUserId())
|
id, token, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, User.GetUserId())
|
||||||
|
|
||||||
// test session token works
|
// test session token works
|
||||||
ctx := Tester.WithAuthorizationToken(context.Background(), token)
|
ctx := Tester.WithAuthorizationToken(context.Background(), token)
|
||||||
@ -658,3 +710,18 @@ func Test_ZITADEL_API_session_not_found(t *testing.T) {
|
|||||||
_, err = Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id})
|
_, err = Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_ZITADEL_API_session_expired(t *testing.T) {
|
||||||
|
id, token, _, _ := Tester.CreateVerifiedWebAuthNSessionWithLifetime(t, CTX, User.GetUserId(), 20*time.Second)
|
||||||
|
|
||||||
|
// test session token works
|
||||||
|
ctx := Tester.WithAuthorizationToken(context.Background(), token)
|
||||||
|
_, err := Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// ensure session expires and does not work anymore
|
||||||
|
time.Sleep(20 * time.Second)
|
||||||
|
sessionResp, err := Tester.Client.SessionV2.GetSession(ctx, &session.GetSessionRequest{SessionId: id})
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Nil(t, sessionResp)
|
||||||
|
}
|
||||||
|
@ -27,7 +27,7 @@ func Test_sessionsToPb(t *testing.T) {
|
|||||||
past := now.Add(-time.Hour)
|
past := now.Add(-time.Hour)
|
||||||
|
|
||||||
sessions := []*query.Session{
|
sessions := []*query.Session{
|
||||||
{ // no factor, with user agent
|
{ // no factor, with user agent and expiration
|
||||||
ID: "999",
|
ID: "999",
|
||||||
CreationDate: now,
|
CreationDate: now,
|
||||||
ChangeDate: now,
|
ChangeDate: now,
|
||||||
@ -42,6 +42,7 @@ func Test_sessionsToPb(t *testing.T) {
|
|||||||
IP: net.IPv4(1, 2, 3, 4),
|
IP: net.IPv4(1, 2, 3, 4),
|
||||||
Header: http.Header{"foo": []string{"foo", "bar"}},
|
Header: http.Header{"foo": []string{"foo", "bar"}},
|
||||||
},
|
},
|
||||||
|
Expiration: now,
|
||||||
},
|
},
|
||||||
{ // user factor
|
{ // user factor
|
||||||
ID: "999",
|
ID: "999",
|
||||||
@ -124,7 +125,7 @@ func Test_sessionsToPb(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
want := []*session.Session{
|
want := []*session.Session{
|
||||||
{ // no factor, with user agent
|
{ // no factor, with user agent and expiration
|
||||||
Id: "999",
|
Id: "999",
|
||||||
CreationDate: timestamppb.New(now),
|
CreationDate: timestamppb.New(now),
|
||||||
ChangeDate: timestamppb.New(now),
|
ChangeDate: timestamppb.New(now),
|
||||||
@ -139,6 +140,7 @@ func Test_sessionsToPb(t *testing.T) {
|
|||||||
"foo": {Values: []string{"foo", "bar"}},
|
"foo": {Values: []string{"foo", "bar"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ExpirationDate: timestamppb.New(now),
|
||||||
},
|
},
|
||||||
{ // user factor
|
{ // user factor
|
||||||
Id: "999",
|
Id: "999",
|
||||||
|
@ -16,13 +16,13 @@ import (
|
|||||||
func TestServer_AddOTPSMS(t *testing.T) {
|
func TestServer_AddOTPSMS(t *testing.T) {
|
||||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||||
Tester.RegisterUserPasskey(CTX, userID)
|
Tester.RegisterUserPasskey(CTX, userID)
|
||||||
_, sessionToken, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userID)
|
_, sessionToken, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userID)
|
||||||
|
|
||||||
// TODO: add when phone can be added to user
|
// TODO: add when phone can be added to user
|
||||||
/*
|
/*
|
||||||
userIDPhone := Tester.CreateHumanUser(CTX).GetUserId()
|
userIDPhone := Tester.CreateHumanUser(CTX).GetUserId()
|
||||||
Tester.RegisterUserPasskey(CTX, userIDPhone)
|
Tester.RegisterUserPasskey(CTX, userIDPhone)
|
||||||
_, sessionTokenPhone, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userIDPhone)
|
_, sessionTokenPhone, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userIDPhone)
|
||||||
*/
|
*/
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@ -99,7 +99,7 @@ func TestServer_RemoveOTPSMS(t *testing.T) {
|
|||||||
/*
|
/*
|
||||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||||
Tester.RegisterUserPasskey(CTX, userID)
|
Tester.RegisterUserPasskey(CTX, userID)
|
||||||
_, sessionToken, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userID)
|
_, sessionToken, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userID)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
@ -157,7 +157,7 @@ func TestServer_RemoveOTPSMS(t *testing.T) {
|
|||||||
func TestServer_AddOTPEmail(t *testing.T) {
|
func TestServer_AddOTPEmail(t *testing.T) {
|
||||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||||
Tester.RegisterUserPasskey(CTX, userID)
|
Tester.RegisterUserPasskey(CTX, userID)
|
||||||
_, sessionToken, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userID)
|
_, sessionToken, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userID)
|
||||||
|
|
||||||
userVerified := Tester.CreateHumanUser(CTX)
|
userVerified := Tester.CreateHumanUser(CTX)
|
||||||
_, err := Tester.Client.UserV2.VerifyEmail(CTX, &user.VerifyEmailRequest{
|
_, err := Tester.Client.UserV2.VerifyEmail(CTX, &user.VerifyEmailRequest{
|
||||||
@ -166,7 +166,7 @@ func TestServer_AddOTPEmail(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
Tester.RegisterUserPasskey(CTX, userVerified.GetUserId())
|
Tester.RegisterUserPasskey(CTX, userVerified.GetUserId())
|
||||||
_, sessionTokenVerified, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userVerified.GetUserId())
|
_, sessionTokenVerified, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userVerified.GetUserId())
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@ -238,11 +238,11 @@ func TestServer_AddOTPEmail(t *testing.T) {
|
|||||||
func TestServer_RemoveOTPEmail(t *testing.T) {
|
func TestServer_RemoveOTPEmail(t *testing.T) {
|
||||||
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
userID := Tester.CreateHumanUser(CTX).GetUserId()
|
||||||
Tester.RegisterUserPasskey(CTX, userID)
|
Tester.RegisterUserPasskey(CTX, userID)
|
||||||
_, sessionToken, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userID)
|
_, sessionToken, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userID)
|
||||||
|
|
||||||
userVerified := Tester.CreateHumanUser(CTX)
|
userVerified := Tester.CreateHumanUser(CTX)
|
||||||
Tester.RegisterUserPasskey(CTX, userVerified.GetUserId())
|
Tester.RegisterUserPasskey(CTX, userVerified.GetUserId())
|
||||||
_, sessionTokenVerified, _, _ := Tester.CreateVerfiedWebAuthNSession(t, CTX, userVerified.GetUserId())
|
_, sessionTokenVerified, _, _ := Tester.CreateVerifiedWebAuthNSession(t, CTX, userVerified.GetUserId())
|
||||||
userVerifiedCtx := Tester.WithAuthorizationToken(context.Background(), sessionTokenVerified)
|
userVerifiedCtx := Tester.WithAuthorizationToken(context.Background(), sessionTokenVerified)
|
||||||
_, err := Tester.Client.UserV2.VerifyEmail(userVerifiedCtx, &user.VerifyEmailRequest{
|
_, err := Tester.Client.UserV2.VerifyEmail(userVerifiedCtx, &user.VerifyEmailRequest{
|
||||||
UserId: userVerified.GetUserId(),
|
UserId: userVerified.GetUserId(),
|
||||||
|
@ -36,7 +36,7 @@ func TestOPStorage_CreateAuthRequest(t *testing.T) {
|
|||||||
func TestOPStorage_CreateAccessToken_code(t *testing.T) {
|
func TestOPStorage_CreateAccessToken_code(t *testing.T) {
|
||||||
clientID := createClient(t)
|
clientID := createClient(t)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI)
|
authRequestID := createAuthRequest(t, clientID, redirectURI)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -75,7 +75,7 @@ func TestOPStorage_CreateAccessToken_code(t *testing.T) {
|
|||||||
func TestOPStorage_CreateAccessToken_implicit(t *testing.T) {
|
func TestOPStorage_CreateAccessToken_implicit(t *testing.T) {
|
||||||
clientID := createImplicitClient(t)
|
clientID := createImplicitClient(t)
|
||||||
authRequestID := createAuthRequestImplicit(t, clientID, redirectURIImplicit)
|
authRequestID := createAuthRequestImplicit(t, clientID, redirectURIImplicit)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -125,7 +125,7 @@ func TestOPStorage_CreateAccessToken_implicit(t *testing.T) {
|
|||||||
func TestOPStorage_CreateAccessAndRefreshTokens_code(t *testing.T) {
|
func TestOPStorage_CreateAccessAndRefreshTokens_code(t *testing.T) {
|
||||||
clientID := createClient(t)
|
clientID := createClient(t)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -150,7 +150,7 @@ func TestOPStorage_CreateAccessAndRefreshTokens_refresh(t *testing.T) {
|
|||||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -186,7 +186,7 @@ func TestOPStorage_RevokeToken_access_token(t *testing.T) {
|
|||||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -229,7 +229,7 @@ func TestOPStorage_RevokeToken_access_token_invalid_token_hint_type(t *testing.T
|
|||||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -266,7 +266,7 @@ func TestOPStorage_RevokeToken_refresh_token(t *testing.T) {
|
|||||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -309,7 +309,7 @@ func TestOPStorage_RevokeToken_refresh_token_invalid_token_type_hint(t *testing.
|
|||||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -344,7 +344,7 @@ func TestOPStorage_RevokeToken_refresh_token_invalid_token_type_hint(t *testing.
|
|||||||
func TestOPStorage_RevokeToken_invalid_client(t *testing.T) {
|
func TestOPStorage_RevokeToken_invalid_client(t *testing.T) {
|
||||||
clientID := createClient(t)
|
clientID := createClient(t)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -376,7 +376,7 @@ func TestOPStorage_TerminateSession(t *testing.T) {
|
|||||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI)
|
authRequestID := createAuthRequest(t, clientID, redirectURI)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -413,7 +413,7 @@ func TestOPStorage_TerminateSession_refresh_grant(t *testing.T) {
|
|||||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -457,7 +457,7 @@ func TestOPStorage_TerminateSession_empty_id_token_hint(t *testing.T) {
|
|||||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI)
|
authRequestID := createAuthRequest(t, clientID, redirectURI)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
func TestOPStorage_SetUserinfoFromToken(t *testing.T) {
|
func TestOPStorage_SetUserinfoFromToken(t *testing.T) {
|
||||||
clientID := createClient(t)
|
clientID := createClient(t)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -67,7 +67,7 @@ func TestOPStorage_SetIntrospectionFromToken(t *testing.T) {
|
|||||||
|
|
||||||
scope := []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess}
|
scope := []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopeOfflineAccess}
|
||||||
authRequestID := createAuthRequest(t, app.GetClientId(), redirectURI, scope...)
|
authRequestID := createAuthRequest(t, app.GetClientId(), redirectURI, scope...)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
|
@ -57,7 +57,7 @@ func TestMain(m *testing.M) {
|
|||||||
func Test_ZITADEL_API_missing_audience_scope(t *testing.T) {
|
func Test_ZITADEL_API_missing_audience_scope(t *testing.T) {
|
||||||
clientID := createClient(t)
|
clientID := createClient(t)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -148,7 +148,7 @@ func Test_ZITADEL_API_missing_mfa(t *testing.T) {
|
|||||||
func Test_ZITADEL_API_success(t *testing.T) {
|
func Test_ZITADEL_API_success(t *testing.T) {
|
||||||
clientID := createClient(t)
|
clientID := createClient(t)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, zitadelAudienceScope)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, zitadelAudienceScope)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -177,7 +177,7 @@ func Test_ZITADEL_API_success(t *testing.T) {
|
|||||||
func Test_ZITADEL_API_inactive_access_token(t *testing.T) {
|
func Test_ZITADEL_API_inactive_access_token(t *testing.T) {
|
||||||
clientID := createClient(t)
|
clientID := createClient(t)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
@ -219,7 +219,7 @@ func Test_ZITADEL_API_terminated_session(t *testing.T) {
|
|||||||
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
provider, err := Tester.CreateRelyingParty(CTX, clientID, redirectURI)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope)
|
authRequestID := createAuthRequest(t, clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess, zitadelAudienceScope)
|
||||||
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerfiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
sessionID, sessionToken, startTime, changeTime := Tester.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
|
||||||
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
linkResp, err := Tester.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
|
||||||
AuthRequestId: authRequestID,
|
AuthRequestId: authRequestID,
|
||||||
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
|
||||||
|
@ -153,6 +153,9 @@ func (repo *TokenVerifierRepo) verifySessionToken(ctx context.Context, sessionID
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", "", err
|
return "", "", "", err
|
||||||
}
|
}
|
||||||
|
if !session.Expiration.IsZero() && session.Expiration.Before(time.Now()) {
|
||||||
|
return "", "", "", caos_errs.ThrowPermissionDenied(nil, "AUTHZ-EGDo3", "session expired")
|
||||||
|
}
|
||||||
if err = repo.checkAuthentication(ctx, authMethodsFromSession(session), session.UserFactor.UserID); err != nil {
|
if err = repo.checkAuthentication(ctx, authMethodsFromSession(session), session.UserFactor.UserID); err != nil {
|
||||||
return "", "", "", err
|
return "", "", "", err
|
||||||
}
|
}
|
||||||
|
@ -95,8 +95,8 @@ func (c *Commands) LinkSessionToAuthRequest(ctx context.Context, id, sessionID,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if sessionWriteModel.State == domain.SessionStateUnspecified {
|
if err = sessionWriteModel.CheckIsActive(); err != nil {
|
||||||
return nil, nil, errors.ThrowNotFound(nil, "COMMAND-x0099887", "Errors.Session.NotExisting")
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if err := c.sessionPermission(ctx, sessionWriteModel, sessionToken, domain.PermissionSessionWrite); err != nil {
|
if err := c.sessionPermission(ctx, sessionWriteModel, sessionToken, domain.PermissionSessionWrite); err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
@ -327,7 +327,67 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
|||||||
sessionID: "sessionID",
|
sessionID: "sessionID",
|
||||||
},
|
},
|
||||||
res{
|
res{
|
||||||
wantErr: caos_errs.ThrowNotFound(nil, "COMMAND-x0099887", "Errors.Session.NotExisting"),
|
wantErr: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Flk38", "Errors.Session.NotExisting"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"session expired",
|
||||||
|
fields{
|
||||||
|
eventstore: eventstoreExpect(t,
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
authrequest.NewAddedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate,
|
||||||
|
"loginClient",
|
||||||
|
"clientID",
|
||||||
|
"redirectURI",
|
||||||
|
"state",
|
||||||
|
"nonce",
|
||||||
|
[]string{"openid"},
|
||||||
|
[]string{"audience"},
|
||||||
|
domain.OIDCResponseTypeCode,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
expectFilter(
|
||||||
|
eventFromEventPusher(
|
||||||
|
session.NewAddedEvent(mockCtx,
|
||||||
|
&session.NewAggregate("sessionID", "org1").Aggregate,
|
||||||
|
&domain.UserAgent{
|
||||||
|
FingerprintID: gu.Ptr("fp1"),
|
||||||
|
IP: net.ParseIP("1.2.3.4"),
|
||||||
|
Description: gu.Ptr("firefox"),
|
||||||
|
Header: http.Header{"foo": []string{"bar"}},
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
eventFromEventPusher(
|
||||||
|
session.NewUserCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate,
|
||||||
|
"userID", testNow.Add(-5*time.Minute)),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
session.NewPasswordCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate,
|
||||||
|
testNow.Add(-5*time.Minute)),
|
||||||
|
),
|
||||||
|
eventFromEventPusher(
|
||||||
|
session.NewLifetimeSetEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate,
|
||||||
|
2*time.Minute),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
ctx: mockCtx,
|
||||||
|
id: "V2_id",
|
||||||
|
sessionID: "sessionID",
|
||||||
|
sessionToken: "token",
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
wantErr: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Hkl3d", "Errors.Session.Expired"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -475,6 +535,10 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
|||||||
session.NewPasswordCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate,
|
session.NewPasswordCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate,
|
||||||
testNow),
|
testNow),
|
||||||
),
|
),
|
||||||
|
eventFromEventPusherWithCreationDateNow(
|
||||||
|
session.NewLifetimeSetEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate,
|
||||||
|
2*time.Minute),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
expectPush(
|
expectPush(
|
||||||
authrequest.NewSessionLinkedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate,
|
authrequest.NewSessionLinkedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate,
|
||||||
@ -559,6 +623,10 @@ func TestCommands_LinkSessionToAuthRequest(t *testing.T) {
|
|||||||
session.NewPasswordCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate,
|
session.NewPasswordCheckedEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate,
|
||||||
testNow),
|
testNow),
|
||||||
),
|
),
|
||||||
|
eventFromEventPusherWithCreationDateNow(
|
||||||
|
session.NewLifetimeSetEvent(mockCtx, &session.NewAggregate("sessionID", "org1").Aggregate,
|
||||||
|
2*time.Minute),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
expectPush(
|
expectPush(
|
||||||
authrequest.NewSessionLinkedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate,
|
authrequest.NewSessionLinkedEvent(mockCtx, &authrequest.NewAggregate("V2_id", "instanceID").Aggregate,
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
"github.com/zitadel/zitadel/internal/id"
|
"github.com/zitadel/zitadel/internal/id"
|
||||||
@ -159,8 +158,8 @@ func (c *Commands) newOIDCSessionAddEvents(ctx context.Context, authRequestID st
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if sessionWriteModel.State != domain.SessionStateActive {
|
if err = sessionWriteModel.CheckIsActive(); err != nil {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "OIDCS-sjkl3", "Errors.Session.Terminated")
|
return nil, err
|
||||||
}
|
}
|
||||||
resourceOwner, err := c.getResourceOwnerOfSessionUser(ctx, sessionWriteModel.UserID, sessionWriteModel.InstanceID)
|
resourceOwner, err := c.getResourceOwnerOfSessionUser(ctx, sessionWriteModel.UserID, sessionWriteModel.InstanceID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -119,7 +119,7 @@ func TestCommands_AddOIDCSessionAccessToken(t *testing.T) {
|
|||||||
authRequestID: "V2_authRequestID",
|
authRequestID: "V2_authRequestID",
|
||||||
},
|
},
|
||||||
res{
|
res{
|
||||||
err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-sjkl3", "Errors.Session.Terminated"),
|
err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Flk38", "Errors.Session.NotExisting"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -320,7 +320,7 @@ func TestCommands_AddOIDCSessionRefreshAndAccessToken(t *testing.T) {
|
|||||||
authRequestID: "V2_authRequestID",
|
authRequestID: "V2_authRequestID",
|
||||||
},
|
},
|
||||||
res{
|
res{
|
||||||
err: caos_errs.ThrowPreconditionFailed(nil, "OIDCS-sjkl3", "Errors.Session.Terminated"),
|
err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Flk38", "Errors.Session.NotExisting"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -252,6 +252,17 @@ func (s *SessionCommands) ChangeMetadata(ctx context.Context, metadata map[strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SessionCommands) SetLifetime(ctx context.Context, lifetime time.Duration) error {
|
||||||
|
if lifetime < 0 {
|
||||||
|
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-asEG4", "Errors.Session.PositiveLifetime")
|
||||||
|
}
|
||||||
|
if lifetime == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
s.eventCommands = append(s.eventCommands, session.NewLifetimeSetEvent(ctx, s.sessionWriteModel.aggregate, lifetime))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SessionCommands) gethumanWriteModel(ctx context.Context) (*HumanWriteModel, error) {
|
func (s *SessionCommands) gethumanWriteModel(ctx context.Context) (*HumanWriteModel, error) {
|
||||||
if s.sessionWriteModel.UserID == "" {
|
if s.sessionWriteModel.UserID == "" {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-eeR2e", "Errors.User.UserIDMissing")
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-eeR2e", "Errors.User.UserIDMissing")
|
||||||
@ -280,7 +291,7 @@ func (s *SessionCommands) commands(ctx context.Context) (string, []eventstore.Co
|
|||||||
return token, s.eventCommands, nil
|
return token, s.eventCommands, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) CreateSession(ctx context.Context, cmds []SessionCommand, metadata map[string][]byte, userAgent *domain.UserAgent) (set *SessionChanged, err error) {
|
func (c *Commands) CreateSession(ctx context.Context, cmds []SessionCommand, metadata map[string][]byte, userAgent *domain.UserAgent, lifetime time.Duration) (set *SessionChanged, err error) {
|
||||||
sessionID, err := c.idGenerator.Next()
|
sessionID, err := c.idGenerator.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -292,10 +303,10 @@ func (c *Commands) CreateSession(ctx context.Context, cmds []SessionCommand, met
|
|||||||
}
|
}
|
||||||
cmd := c.NewSessionCommands(cmds, sessionWriteModel)
|
cmd := c.NewSessionCommands(cmds, sessionWriteModel)
|
||||||
cmd.Start(ctx, userAgent)
|
cmd.Start(ctx, userAgent)
|
||||||
return c.updateSession(ctx, cmd, metadata)
|
return c.updateSession(ctx, cmd, metadata, lifetime)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) UpdateSession(ctx context.Context, sessionID, sessionToken string, cmds []SessionCommand, metadata map[string][]byte) (set *SessionChanged, err error) {
|
func (c *Commands) UpdateSession(ctx context.Context, sessionID, sessionToken string, cmds []SessionCommand, metadata map[string][]byte, lifetime time.Duration) (set *SessionChanged, err error) {
|
||||||
sessionWriteModel := NewSessionWriteModel(sessionID, authz.GetCtxData(ctx).OrgID)
|
sessionWriteModel := NewSessionWriteModel(sessionID, authz.GetCtxData(ctx).OrgID)
|
||||||
err = c.eventstore.FilterToQueryReducer(ctx, sessionWriteModel)
|
err = c.eventstore.FilterToQueryReducer(ctx, sessionWriteModel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -305,7 +316,7 @@ func (c *Commands) UpdateSession(ctx context.Context, sessionID, sessionToken st
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cmd := c.NewSessionCommands(cmds, sessionWriteModel)
|
cmd := c.NewSessionCommands(cmds, sessionWriteModel)
|
||||||
return c.updateSession(ctx, cmd, metadata)
|
return c.updateSession(ctx, cmd, metadata, lifetime)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) TerminateSession(ctx context.Context, sessionID string, sessionToken string) (*domain.ObjectDetails, error) {
|
func (c *Commands) TerminateSession(ctx context.Context, sessionID string, sessionToken string) (*domain.ObjectDetails, error) {
|
||||||
@ -326,7 +337,7 @@ func (c *Commands) terminateSession(ctx context.Context, sessionID, sessionToken
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if sessionWriteModel.State != domain.SessionStateActive {
|
if sessionWriteModel.CheckIsActive() != nil {
|
||||||
return writeModelToObjectDetails(&sessionWriteModel.WriteModel), nil
|
return writeModelToObjectDetails(&sessionWriteModel.WriteModel), nil
|
||||||
}
|
}
|
||||||
terminate := session.NewTerminateEvent(ctx, &session.NewAggregate(sessionWriteModel.AggregateID, sessionWriteModel.ResourceOwner).Aggregate)
|
terminate := session.NewTerminateEvent(ctx, &session.NewAggregate(sessionWriteModel.AggregateID, sessionWriteModel.ResourceOwner).Aggregate)
|
||||||
@ -342,15 +353,19 @@ func (c *Commands) terminateSession(ctx context.Context, sessionID, sessionToken
|
|||||||
}
|
}
|
||||||
|
|
||||||
// updateSession execute the [SessionCommands] where new events will be created and as well as for metadata (changes)
|
// updateSession execute the [SessionCommands] where new events will be created and as well as for metadata (changes)
|
||||||
func (c *Commands) updateSession(ctx context.Context, checks *SessionCommands, metadata map[string][]byte) (set *SessionChanged, err error) {
|
func (c *Commands) updateSession(ctx context.Context, checks *SessionCommands, metadata map[string][]byte, lifetime time.Duration) (set *SessionChanged, err error) {
|
||||||
if checks.sessionWriteModel.State == domain.SessionStateTerminated {
|
if err = checks.sessionWriteModel.CheckNotInvalidated(); err != nil {
|
||||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMAND-SAjeh", "Errors.Session.Terminated")
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := checks.Exec(ctx); err != nil {
|
if err := checks.Exec(ctx); err != nil {
|
||||||
// TODO: how to handle failed checks (e.g. pw wrong) https://github.com/zitadel/zitadel/issues/5807
|
// TODO: how to handle failed checks (e.g. pw wrong) https://github.com/zitadel/zitadel/issues/5807
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
checks.ChangeMetadata(ctx, metadata)
|
checks.ChangeMetadata(ctx, metadata)
|
||||||
|
err = checks.SetLifetime(ctx, lifetime)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
sessionToken, cmds, err := checks.commands(ctx)
|
sessionToken, cmds, err := checks.commands(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/crypto"
|
"github.com/zitadel/zitadel/internal/crypto"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
|
"github.com/zitadel/zitadel/internal/errors"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
"github.com/zitadel/zitadel/internal/repository/session"
|
"github.com/zitadel/zitadel/internal/repository/session"
|
||||||
)
|
)
|
||||||
@ -48,6 +49,7 @@ type SessionWriteModel struct {
|
|||||||
WebAuthNUserVerified bool
|
WebAuthNUserVerified bool
|
||||||
Metadata map[string][]byte
|
Metadata map[string][]byte
|
||||||
State domain.SessionState
|
State domain.SessionState
|
||||||
|
Expiration time.Time
|
||||||
|
|
||||||
WebAuthNChallenge *WebAuthNChallengeModel
|
WebAuthNChallenge *WebAuthNChallengeModel
|
||||||
OTPSMSCodeChallenge *OTPCode
|
OTPSMSCodeChallenge *OTPCode
|
||||||
@ -94,6 +96,8 @@ func (wm *SessionWriteModel) Reduce() error {
|
|||||||
wm.reduceOTPEmailChecked(e)
|
wm.reduceOTPEmailChecked(e)
|
||||||
case *session.TokenSetEvent:
|
case *session.TokenSetEvent:
|
||||||
wm.reduceTokenSet(e)
|
wm.reduceTokenSet(e)
|
||||||
|
case *session.LifetimeSetEvent:
|
||||||
|
wm.reduceLifetimeSet(e)
|
||||||
case *session.TerminateEvent:
|
case *session.TerminateEvent:
|
||||||
wm.reduceTerminate()
|
wm.reduceTerminate()
|
||||||
}
|
}
|
||||||
@ -120,6 +124,7 @@ func (wm *SessionWriteModel) Query() *eventstore.SearchQueryBuilder {
|
|||||||
session.OTPEmailCheckedType,
|
session.OTPEmailCheckedType,
|
||||||
session.TokenSetType,
|
session.TokenSetType,
|
||||||
session.MetadataSetType,
|
session.MetadataSetType,
|
||||||
|
session.LifetimeSetType,
|
||||||
session.TerminateType,
|
session.TerminateType,
|
||||||
).
|
).
|
||||||
Builder()
|
Builder()
|
||||||
@ -196,6 +201,10 @@ func (wm *SessionWriteModel) reduceTokenSet(e *session.TokenSetEvent) {
|
|||||||
wm.TokenID = e.TokenID
|
wm.TokenID = e.TokenID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (wm *SessionWriteModel) reduceLifetimeSet(e *session.LifetimeSetEvent) {
|
||||||
|
wm.Expiration = e.CreationDate().Add(e.Lifetime)
|
||||||
|
}
|
||||||
|
|
||||||
func (wm *SessionWriteModel) reduceTerminate() {
|
func (wm *SessionWriteModel) reduceTerminate() {
|
||||||
wm.State = domain.SessionStateTerminated
|
wm.State = domain.SessionStateTerminated
|
||||||
}
|
}
|
||||||
@ -245,3 +254,23 @@ func (wm *SessionWriteModel) AuthMethodTypes() []domain.UserAuthMethodType {
|
|||||||
}
|
}
|
||||||
return types
|
return types
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckNotInvalidated checks that the session was not invalidated either manually ([session.TerminateType])
|
||||||
|
// or automatically (expired).
|
||||||
|
func (wm *SessionWriteModel) CheckNotInvalidated() error {
|
||||||
|
if wm.State == domain.SessionStateTerminated {
|
||||||
|
return errors.ThrowPreconditionFailed(nil, "COMMAND-Hewfq", "Errors.Session.Terminated")
|
||||||
|
}
|
||||||
|
if !wm.Expiration.IsZero() && wm.Expiration.Before(time.Now()) {
|
||||||
|
return errors.ThrowPreconditionFailed(nil, "COMMAND-Hkl3d", "Errors.Session.Expired")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckIsActive checks that the session was not invalidated ([CheckNotInvalidated]) and actually already exists.
|
||||||
|
func (wm *SessionWriteModel) CheckIsActive() error {
|
||||||
|
if wm.State == domain.SessionStateUnspecified {
|
||||||
|
return errors.ThrowPreconditionFailed(nil, "COMMAND-Flk38", "Errors.Session.NotExisting")
|
||||||
|
}
|
||||||
|
return wm.CheckNotInvalidated()
|
||||||
|
}
|
||||||
|
@ -152,6 +152,7 @@ func TestCommands_CreateSession(t *testing.T) {
|
|||||||
checks []SessionCommand
|
checks []SessionCommand
|
||||||
metadata map[string][]byte
|
metadata map[string][]byte
|
||||||
userAgent *domain.UserAgent
|
userAgent *domain.UserAgent
|
||||||
|
lifetime time.Duration
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *SessionChanged
|
want *SessionChanged
|
||||||
@ -192,6 +193,33 @@ func TestCommands_CreateSession(t *testing.T) {
|
|||||||
err: caos_errs.ThrowInternal(nil, "id", "filter failed"),
|
err: caos_errs.ThrowInternal(nil, "id", "filter failed"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"negative lifetime",
|
||||||
|
fields{
|
||||||
|
idGenerator: mock.NewIDGeneratorExpectIDs(t, "sessionID"),
|
||||||
|
tokenCreator: func(sessionID string) (string, string, error) {
|
||||||
|
return "tokenID",
|
||||||
|
"token",
|
||||||
|
nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
ctx: authz.NewMockContext("", "org1", ""),
|
||||||
|
userAgent: &domain.UserAgent{
|
||||||
|
FingerprintID: gu.Ptr("fp1"),
|
||||||
|
IP: net.ParseIP("1.2.3.4"),
|
||||||
|
Description: gu.Ptr("firefox"),
|
||||||
|
Header: http.Header{"foo": []string{"bar"}},
|
||||||
|
},
|
||||||
|
lifetime: -10 * time.Minute,
|
||||||
|
},
|
||||||
|
[]expect{
|
||||||
|
expectFilter(),
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
err: caos_errs.ThrowInvalidArgument(nil, "COMMAND-asEG4", "Errors.Session.PositiveLifetime"),
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"empty session",
|
"empty session",
|
||||||
fields{
|
fields{
|
||||||
@ -210,6 +238,7 @@ func TestCommands_CreateSession(t *testing.T) {
|
|||||||
Description: gu.Ptr("firefox"),
|
Description: gu.Ptr("firefox"),
|
||||||
Header: http.Header{"foo": []string{"bar"}},
|
Header: http.Header{"foo": []string{"bar"}},
|
||||||
},
|
},
|
||||||
|
lifetime: 10 * time.Minute,
|
||||||
},
|
},
|
||||||
[]expect{
|
[]expect{
|
||||||
expectFilter(),
|
expectFilter(),
|
||||||
@ -223,6 +252,7 @@ func TestCommands_CreateSession(t *testing.T) {
|
|||||||
Header: http.Header{"foo": []string{"bar"}},
|
Header: http.Header{"foo": []string{"bar"}},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
session.NewLifetimeSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate, 10*time.Minute),
|
||||||
session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate,
|
session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate,
|
||||||
"tokenID",
|
"tokenID",
|
||||||
),
|
),
|
||||||
@ -245,7 +275,7 @@ func TestCommands_CreateSession(t *testing.T) {
|
|||||||
idGenerator: tt.fields.idGenerator,
|
idGenerator: tt.fields.idGenerator,
|
||||||
sessionTokenCreator: tt.fields.tokenCreator,
|
sessionTokenCreator: tt.fields.tokenCreator,
|
||||||
}
|
}
|
||||||
got, err := c.CreateSession(tt.args.ctx, tt.args.checks, tt.args.metadata, tt.args.userAgent)
|
got, err := c.CreateSession(tt.args.ctx, tt.args.checks, tt.args.metadata, tt.args.userAgent, tt.args.lifetime)
|
||||||
require.ErrorIs(t, err, tt.res.err)
|
require.ErrorIs(t, err, tt.res.err)
|
||||||
assert.Equal(t, tt.res.want, got)
|
assert.Equal(t, tt.res.want, got)
|
||||||
})
|
})
|
||||||
@ -263,6 +293,7 @@ func TestCommands_UpdateSession(t *testing.T) {
|
|||||||
sessionToken string
|
sessionToken string
|
||||||
checks []SessionCommand
|
checks []SessionCommand
|
||||||
metadata map[string][]byte
|
metadata map[string][]byte
|
||||||
|
lifetime time.Duration
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *SessionChanged
|
want *SessionChanged
|
||||||
@ -368,7 +399,7 @@ func TestCommands_UpdateSession(t *testing.T) {
|
|||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
sessionTokenVerifier: tt.fields.tokenVerifier,
|
sessionTokenVerifier: tt.fields.tokenVerifier,
|
||||||
}
|
}
|
||||||
got, err := c.UpdateSession(tt.args.ctx, tt.args.sessionID, tt.args.sessionToken, tt.args.checks, tt.args.metadata)
|
got, err := c.UpdateSession(tt.args.ctx, tt.args.sessionID, tt.args.sessionToken, tt.args.checks, tt.args.metadata, tt.args.lifetime)
|
||||||
require.ErrorIs(t, err, tt.res.err)
|
require.ErrorIs(t, err, tt.res.err)
|
||||||
assert.Equal(t, tt.res.want, got)
|
assert.Equal(t, tt.res.want, got)
|
||||||
})
|
})
|
||||||
@ -397,6 +428,7 @@ func TestCommands_updateSession(t *testing.T) {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
checks *SessionCommands
|
checks *SessionCommands
|
||||||
metadata map[string][]byte
|
metadata map[string][]byte
|
||||||
|
lifetime time.Duration
|
||||||
}
|
}
|
||||||
type res struct {
|
type res struct {
|
||||||
want *SessionChanged
|
want *SessionChanged
|
||||||
@ -420,7 +452,7 @@ func TestCommands_updateSession(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
res{
|
res{
|
||||||
err: caos_errs.ThrowPreconditionFailed(nil, "COMAND-SAjeh", "Errors.Session.Terminated"),
|
err: caos_errs.ThrowPreconditionFailed(nil, "COMMAND-Hewfq", "Errors.Session.Terminated"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -465,6 +497,73 @@ func TestCommands_updateSession(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"negative lifetime",
|
||||||
|
fields{
|
||||||
|
eventstore: eventstoreExpect(t),
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
checks: &SessionCommands{
|
||||||
|
sessionWriteModel: NewSessionWriteModel("sessionID", "org1"),
|
||||||
|
sessionCommands: []SessionCommand{},
|
||||||
|
eventstore: eventstoreExpect(t),
|
||||||
|
createToken: func(sessionID string) (string, string, error) {
|
||||||
|
return "tokenID",
|
||||||
|
"token",
|
||||||
|
nil
|
||||||
|
},
|
||||||
|
now: func() time.Time {
|
||||||
|
return testNow
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lifetime: -10 * time.Minute,
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
err: caos_errs.ThrowInvalidArgument(nil, "COMMAND-asEG4", "Errors.Session.PositiveLifetime"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lifetime set",
|
||||||
|
fields{
|
||||||
|
eventstore: eventstoreExpect(t,
|
||||||
|
expectPush(
|
||||||
|
session.NewLifetimeSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate,
|
||||||
|
10*time.Minute,
|
||||||
|
),
|
||||||
|
session.NewTokenSetEvent(context.Background(), &session.NewAggregate("sessionID", "org1").Aggregate,
|
||||||
|
"tokenID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
args{
|
||||||
|
ctx: context.Background(),
|
||||||
|
checks: &SessionCommands{
|
||||||
|
sessionWriteModel: NewSessionWriteModel("sessionID", "org1"),
|
||||||
|
sessionCommands: []SessionCommand{},
|
||||||
|
eventstore: eventstoreExpect(t),
|
||||||
|
createToken: func(sessionID string) (string, string, error) {
|
||||||
|
return "tokenID",
|
||||||
|
"token",
|
||||||
|
nil
|
||||||
|
},
|
||||||
|
now: func() time.Time {
|
||||||
|
return testNow
|
||||||
|
},
|
||||||
|
},
|
||||||
|
lifetime: 10 * time.Minute,
|
||||||
|
},
|
||||||
|
res{
|
||||||
|
want: &SessionChanged{
|
||||||
|
ObjectDetails: &domain.ObjectDetails{
|
||||||
|
ResourceOwner: "org1",
|
||||||
|
},
|
||||||
|
ID: "sessionID",
|
||||||
|
NewToken: "token",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"set user, password, metadata and token",
|
"set user, password, metadata and token",
|
||||||
fields{
|
fields{
|
||||||
@ -721,7 +820,7 @@ func TestCommands_updateSession(t *testing.T) {
|
|||||||
c := &Commands{
|
c := &Commands{
|
||||||
eventstore: tt.fields.eventstore,
|
eventstore: tt.fields.eventstore,
|
||||||
}
|
}
|
||||||
got, err := c.updateSession(tt.args.ctx, tt.args.checks, tt.args.metadata)
|
got, err := c.updateSession(tt.args.ctx, tt.args.checks, tt.args.metadata, tt.args.lifetime)
|
||||||
require.ErrorIs(t, err, tt.res.err)
|
require.ErrorIs(t, err, tt.res.err)
|
||||||
assert.Equal(t, tt.res.want, got)
|
assert.Equal(t, tt.res.want, got)
|
||||||
})
|
})
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/command"
|
"github.com/zitadel/zitadel/internal/command"
|
||||||
@ -324,7 +325,15 @@ func (s *Tester) CreateSuccessfulSAMLIntent(t *testing.T, idpID, userID, idpUser
|
|||||||
return intentID, token, writeModel.ChangeDate, writeModel.ProcessedSequence
|
return intentID, token, writeModel.ChangeDate, writeModel.ProcessedSequence
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Tester) CreateVerfiedWebAuthNSession(t *testing.T, ctx context.Context, userID string) (id, token string, start, change time.Time) {
|
func (s *Tester) CreateVerifiedWebAuthNSession(t *testing.T, ctx context.Context, userID string) (id, token string, start, change time.Time) {
|
||||||
|
return s.CreateVerifiedWebAuthNSessionWithLifetime(t, ctx, userID, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Tester) CreateVerifiedWebAuthNSessionWithLifetime(t *testing.T, ctx context.Context, userID string, lifetime time.Duration) (id, token string, start, change time.Time) {
|
||||||
|
var sessionLifetime *durationpb.Duration
|
||||||
|
if lifetime > 0 {
|
||||||
|
sessionLifetime = durationpb.New(lifetime)
|
||||||
|
}
|
||||||
createResp, err := s.Client.SessionV2.CreateSession(ctx, &session.CreateSessionRequest{
|
createResp, err := s.Client.SessionV2.CreateSession(ctx, &session.CreateSessionRequest{
|
||||||
Checks: &session.Checks{
|
Checks: &session.Checks{
|
||||||
User: &session.CheckUser{
|
User: &session.CheckUser{
|
||||||
@ -337,6 +346,7 @@ func (s *Tester) CreateVerfiedWebAuthNSession(t *testing.T, ctx context.Context,
|
|||||||
UserVerificationRequirement: session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_REQUIRED,
|
UserVerificationRequirement: session.UserVerificationRequirement_USER_VERIFICATION_REQUIREMENT_REQUIRED,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Lifetime: sessionLifetime,
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SessionsProjectionTable = "projections.sessions6"
|
SessionsProjectionTable = "projections.sessions7"
|
||||||
|
|
||||||
SessionColumnID = "id"
|
SessionColumnID = "id"
|
||||||
SessionColumnCreationDate = "creation_date"
|
SessionColumnCreationDate = "creation_date"
|
||||||
@ -39,6 +39,7 @@ const (
|
|||||||
SessionColumnUserAgentIP = "user_agent_ip"
|
SessionColumnUserAgentIP = "user_agent_ip"
|
||||||
SessionColumnUserAgentDescription = "user_agent_description"
|
SessionColumnUserAgentDescription = "user_agent_description"
|
||||||
SessionColumnUserAgentHeader = "user_agent_header"
|
SessionColumnUserAgentHeader = "user_agent_header"
|
||||||
|
SessionColumnExpiration = "expiration"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sessionProjection struct{}
|
type sessionProjection struct{}
|
||||||
@ -77,6 +78,7 @@ func (*sessionProjection) Init() *old_handler.Check {
|
|||||||
handler.NewColumn(SessionColumnUserAgentIP, handler.ColumnTypeText, handler.Nullable()),
|
handler.NewColumn(SessionColumnUserAgentIP, handler.ColumnTypeText, handler.Nullable()),
|
||||||
handler.NewColumn(SessionColumnUserAgentDescription, handler.ColumnTypeText, handler.Nullable()),
|
handler.NewColumn(SessionColumnUserAgentDescription, handler.ColumnTypeText, handler.Nullable()),
|
||||||
handler.NewColumn(SessionColumnUserAgentHeader, handler.ColumnTypeJSONB, handler.Nullable()),
|
handler.NewColumn(SessionColumnUserAgentHeader, handler.ColumnTypeJSONB, handler.Nullable()),
|
||||||
|
handler.NewColumn(SessionColumnExpiration, handler.ColumnTypeTimestamp, handler.Nullable()),
|
||||||
},
|
},
|
||||||
handler.NewPrimaryKey(SessionColumnInstanceID, SessionColumnID),
|
handler.NewPrimaryKey(SessionColumnInstanceID, SessionColumnID),
|
||||||
handler.WithIndex(handler.NewIndex(
|
handler.WithIndex(handler.NewIndex(
|
||||||
@ -132,6 +134,10 @@ func (p *sessionProjection) Reducers() []handler.AggregateReducer {
|
|||||||
Event: session.MetadataSetType,
|
Event: session.MetadataSetType,
|
||||||
Reduce: p.reduceMetadataSet,
|
Reduce: p.reduceMetadataSet,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Event: session.LifetimeSetType,
|
||||||
|
Reduce: p.reduceLifetimeSet,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Event: session.TerminateType,
|
Event: session.TerminateType,
|
||||||
Reduce: p.reduceSessionTerminated,
|
Reduce: p.reduceSessionTerminated,
|
||||||
@ -376,6 +382,26 @@ func (p *sessionProjection) reduceMetadataSet(event eventstore.Event) (*handler.
|
|||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *sessionProjection) reduceLifetimeSet(event eventstore.Event) (*handler.Statement, error) {
|
||||||
|
e, err := assertEvent[*session.LifetimeSetEvent](event)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler.NewUpdateStatement(
|
||||||
|
e,
|
||||||
|
[]handler.Column{
|
||||||
|
handler.NewCol(SessionColumnChangeDate, e.CreationDate()),
|
||||||
|
handler.NewCol(SessionColumnSequence, e.Sequence()),
|
||||||
|
handler.NewCol(SessionColumnExpiration, e.CreationDate().Add(e.Lifetime)),
|
||||||
|
},
|
||||||
|
[]handler.Condition{
|
||||||
|
handler.NewCond(SessionColumnID, e.Aggregate().ID),
|
||||||
|
handler.NewCond(SessionColumnInstanceID, e.Aggregate().InstanceID),
|
||||||
|
},
|
||||||
|
), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *sessionProjection) reduceSessionTerminated(event eventstore.Event) (*handler.Statement, error) {
|
func (p *sessionProjection) reduceSessionTerminated(event eventstore.Event) (*handler.Statement, error) {
|
||||||
e, ok := event.(*session.TerminateEvent)
|
e, ok := event.(*session.TerminateEvent)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -51,7 +51,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "INSERT INTO projections.sessions6 (id, instance_id, creation_date, change_date, resource_owner, state, sequence, creator, user_agent_fingerprint_id, user_agent_description, user_agent_ip, user_agent_header) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
expectedStmt: "INSERT INTO projections.sessions7 (id, instance_id, creation_date, change_date, resource_owner, state, sequence, creator, user_agent_fingerprint_id, user_agent_description, user_agent_ip, user_agent_header) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"agg-id",
|
"agg-id",
|
||||||
"instance-id",
|
"instance-id",
|
||||||
@ -90,7 +90,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, user_id, user_checked_at) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)",
|
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, user_id, user_checked_at) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -122,7 +122,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, password_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, password_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -154,7 +154,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, webauthn_checked_at, webauthn_user_verified) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)",
|
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, webauthn_checked_at, webauthn_user_verified) = ($1, $2, $3, $4) WHERE (id = $5) AND (instance_id = $6)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -186,7 +186,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, intent_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, intent_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -217,7 +217,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, totp_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, totp_checked_at) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -248,7 +248,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, token_id) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, token_id) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -281,7 +281,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.sessions6 SET (change_date, sequence, metadata) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, metadata) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
anyArg{},
|
anyArg{},
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -296,6 +296,37 @@ func TestSessionProjection_reduces(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "instance reduceLifetimeSet",
|
||||||
|
args: args{
|
||||||
|
event: getEvent(testEvent(
|
||||||
|
session.MetadataSetType,
|
||||||
|
session.AggregateType,
|
||||||
|
[]byte(`{
|
||||||
|
"lifetime": 600000000000
|
||||||
|
}`),
|
||||||
|
), eventstore.GenericEventMapper[session.LifetimeSetEvent]),
|
||||||
|
},
|
||||||
|
reduce: (&sessionProjection{}).reduceLifetimeSet,
|
||||||
|
want: wantReduce{
|
||||||
|
aggregateType: eventstore.AggregateType("session"),
|
||||||
|
sequence: 15,
|
||||||
|
executer: &testExecuter{
|
||||||
|
executions: []execution{
|
||||||
|
{
|
||||||
|
expectedStmt: "UPDATE projections.sessions7 SET (change_date, sequence, expiration) = ($1, $2, $3) WHERE (id = $4) AND (instance_id = $5)",
|
||||||
|
expectedArgs: []interface{}{
|
||||||
|
anyArg{},
|
||||||
|
anyArg{},
|
||||||
|
anyArg{},
|
||||||
|
"agg-id",
|
||||||
|
"instance-id",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "instance reduceSessionTerminated",
|
name: "instance reduceSessionTerminated",
|
||||||
args: args{
|
args: args{
|
||||||
@ -312,7 +343,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "DELETE FROM projections.sessions6 WHERE (id = $1) AND (instance_id = $2)",
|
expectedStmt: "DELETE FROM projections.sessions7 WHERE (id = $1) AND (instance_id = $2)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"agg-id",
|
"agg-id",
|
||||||
"instance-id",
|
"instance-id",
|
||||||
@ -339,7 +370,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "DELETE FROM projections.sessions6 WHERE (instance_id = $1)",
|
expectedStmt: "DELETE FROM projections.sessions7 WHERE (instance_id = $1)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"agg-id",
|
"agg-id",
|
||||||
},
|
},
|
||||||
@ -369,7 +400,7 @@ func TestSessionProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "UPDATE projections.sessions6 SET password_checked_at = $1 WHERE (user_id = $2) AND (password_checked_at < $3)",
|
expectedStmt: "UPDATE projections.sessions7 SET password_checked_at = $1 WHERE (user_id = $2) AND (password_checked_at < $3)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
nil,
|
nil,
|
||||||
"agg-id",
|
"agg-id",
|
||||||
|
@ -44,6 +44,7 @@ type Session struct {
|
|||||||
OTPEmailFactor SessionOTPFactor
|
OTPEmailFactor SessionOTPFactor
|
||||||
Metadata map[string][]byte
|
Metadata map[string][]byte
|
||||||
UserAgent domain.UserAgent
|
UserAgent domain.UserAgent
|
||||||
|
Expiration time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type SessionUserFactor struct {
|
type SessionUserFactor struct {
|
||||||
@ -185,6 +186,10 @@ var (
|
|||||||
name: projection.SessionColumnUserAgentHeader,
|
name: projection.SessionColumnUserAgentHeader,
|
||||||
table: sessionsTable,
|
table: sessionsTable,
|
||||||
}
|
}
|
||||||
|
SessionColumnExpiration = Column{
|
||||||
|
name: projection.SessionColumnExpiration,
|
||||||
|
table: sessionsTable,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (q *Queries) SessionByID(ctx context.Context, shouldTriggerBulk bool, id, sessionToken string) (session *Session, err error) {
|
func (q *Queries) SessionByID(ctx context.Context, shouldTriggerBulk bool, id, sessionToken string) (session *Session, err error) {
|
||||||
@ -290,6 +295,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil
|
|||||||
SessionColumnUserAgentIP.identifier(),
|
SessionColumnUserAgentIP.identifier(),
|
||||||
SessionColumnUserAgentDescription.identifier(),
|
SessionColumnUserAgentDescription.identifier(),
|
||||||
SessionColumnUserAgentHeader.identifier(),
|
SessionColumnUserAgentHeader.identifier(),
|
||||||
|
SessionColumnExpiration.identifier(),
|
||||||
).From(sessionsTable.identifier()).
|
).From(sessionsTable.identifier()).
|
||||||
LeftJoin(join(LoginNameUserIDCol, SessionColumnUserID)).
|
LeftJoin(join(LoginNameUserIDCol, SessionColumnUserID)).
|
||||||
LeftJoin(join(HumanUserIDCol, SessionColumnUserID)).
|
LeftJoin(join(HumanUserIDCol, SessionColumnUserID)).
|
||||||
@ -314,6 +320,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil
|
|||||||
token sql.NullString
|
token sql.NullString
|
||||||
userAgentIP sql.NullString
|
userAgentIP sql.NullString
|
||||||
userAgentHeader database.Map[[]string]
|
userAgentHeader database.Map[[]string]
|
||||||
|
expiration sql.NullTime
|
||||||
)
|
)
|
||||||
|
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
@ -342,6 +349,7 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil
|
|||||||
&userAgentIP,
|
&userAgentIP,
|
||||||
&session.UserAgent.Description,
|
&session.UserAgent.Description,
|
||||||
&userAgentHeader,
|
&userAgentHeader,
|
||||||
|
&expiration,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -365,10 +373,10 @@ func prepareSessionQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuil
|
|||||||
session.OTPEmailFactor.OTPCheckedAt = otpEmailCheckedAt.Time
|
session.OTPEmailFactor.OTPCheckedAt = otpEmailCheckedAt.Time
|
||||||
session.Metadata = metadata
|
session.Metadata = metadata
|
||||||
session.UserAgent.Header = http.Header(userAgentHeader)
|
session.UserAgent.Header = http.Header(userAgentHeader)
|
||||||
|
|
||||||
if userAgentIP.Valid {
|
if userAgentIP.Valid {
|
||||||
session.UserAgent.IP = net.ParseIP(userAgentIP.String)
|
session.UserAgent.IP = net.ParseIP(userAgentIP.String)
|
||||||
}
|
}
|
||||||
|
session.Expiration = expiration.Time
|
||||||
return session, token.String, nil
|
return session, token.String, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -395,6 +403,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui
|
|||||||
SessionColumnOTPSMSCheckedAt.identifier(),
|
SessionColumnOTPSMSCheckedAt.identifier(),
|
||||||
SessionColumnOTPEmailCheckedAt.identifier(),
|
SessionColumnOTPEmailCheckedAt.identifier(),
|
||||||
SessionColumnMetadata.identifier(),
|
SessionColumnMetadata.identifier(),
|
||||||
|
SessionColumnExpiration.identifier(),
|
||||||
countColumn.identifier(),
|
countColumn.identifier(),
|
||||||
).From(sessionsTable.identifier()).
|
).From(sessionsTable.identifier()).
|
||||||
LeftJoin(join(LoginNameUserIDCol, SessionColumnUserID)).
|
LeftJoin(join(LoginNameUserIDCol, SessionColumnUserID)).
|
||||||
@ -420,6 +429,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui
|
|||||||
otpSMSCheckedAt sql.NullTime
|
otpSMSCheckedAt sql.NullTime
|
||||||
otpEmailCheckedAt sql.NullTime
|
otpEmailCheckedAt sql.NullTime
|
||||||
metadata database.Map[[]byte]
|
metadata database.Map[[]byte]
|
||||||
|
expiration sql.NullTime
|
||||||
)
|
)
|
||||||
|
|
||||||
err := rows.Scan(
|
err := rows.Scan(
|
||||||
@ -443,6 +453,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui
|
|||||||
&otpSMSCheckedAt,
|
&otpSMSCheckedAt,
|
||||||
&otpEmailCheckedAt,
|
&otpEmailCheckedAt,
|
||||||
&metadata,
|
&metadata,
|
||||||
|
&expiration,
|
||||||
&sessions.Count,
|
&sessions.Count,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -462,6 +473,7 @@ func prepareSessionsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBui
|
|||||||
session.OTPSMSFactor.OTPCheckedAt = otpSMSCheckedAt.Time
|
session.OTPSMSFactor.OTPCheckedAt = otpSMSCheckedAt.Time
|
||||||
session.OTPEmailFactor.OTPCheckedAt = otpEmailCheckedAt.Time
|
session.OTPEmailFactor.OTPCheckedAt = otpEmailCheckedAt.Time
|
||||||
session.Metadata = metadata
|
session.Metadata = metadata
|
||||||
|
session.Expiration = expiration.Time
|
||||||
|
|
||||||
sessions.Sessions = append(sessions.Sessions, session)
|
sessions.Sessions = append(sessions.Sessions, session)
|
||||||
}
|
}
|
||||||
|
@ -20,61 +20,63 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
expectedSessionQuery = regexp.QuoteMeta(`SELECT projections.sessions6.id,` +
|
expectedSessionQuery = regexp.QuoteMeta(`SELECT projections.sessions7.id,` +
|
||||||
` projections.sessions6.creation_date,` +
|
` projections.sessions7.creation_date,` +
|
||||||
` projections.sessions6.change_date,` +
|
` projections.sessions7.change_date,` +
|
||||||
` projections.sessions6.sequence,` +
|
` projections.sessions7.sequence,` +
|
||||||
` projections.sessions6.state,` +
|
` projections.sessions7.state,` +
|
||||||
` projections.sessions6.resource_owner,` +
|
` projections.sessions7.resource_owner,` +
|
||||||
` projections.sessions6.creator,` +
|
` projections.sessions7.creator,` +
|
||||||
` projections.sessions6.user_id,` +
|
` projections.sessions7.user_id,` +
|
||||||
` projections.sessions6.user_checked_at,` +
|
` projections.sessions7.user_checked_at,` +
|
||||||
` projections.login_names2.login_name,` +
|
` projections.login_names2.login_name,` +
|
||||||
` projections.users8_humans.display_name,` +
|
` projections.users8_humans.display_name,` +
|
||||||
` projections.users8.resource_owner,` +
|
` projections.users8.resource_owner,` +
|
||||||
` projections.sessions6.password_checked_at,` +
|
` projections.sessions7.password_checked_at,` +
|
||||||
` projections.sessions6.intent_checked_at,` +
|
` projections.sessions7.intent_checked_at,` +
|
||||||
` projections.sessions6.webauthn_checked_at,` +
|
` projections.sessions7.webauthn_checked_at,` +
|
||||||
` projections.sessions6.webauthn_user_verified,` +
|
` projections.sessions7.webauthn_user_verified,` +
|
||||||
` projections.sessions6.totp_checked_at,` +
|
` projections.sessions7.totp_checked_at,` +
|
||||||
` projections.sessions6.otp_sms_checked_at,` +
|
` projections.sessions7.otp_sms_checked_at,` +
|
||||||
` projections.sessions6.otp_email_checked_at,` +
|
` projections.sessions7.otp_email_checked_at,` +
|
||||||
` projections.sessions6.metadata,` +
|
` projections.sessions7.metadata,` +
|
||||||
` projections.sessions6.token_id,` +
|
` projections.sessions7.token_id,` +
|
||||||
` projections.sessions6.user_agent_fingerprint_id,` +
|
` projections.sessions7.user_agent_fingerprint_id,` +
|
||||||
` projections.sessions6.user_agent_ip,` +
|
` projections.sessions7.user_agent_ip,` +
|
||||||
` projections.sessions6.user_agent_description,` +
|
` projections.sessions7.user_agent_description,` +
|
||||||
` projections.sessions6.user_agent_header` +
|
` projections.sessions7.user_agent_header,` +
|
||||||
` FROM projections.sessions6` +
|
` projections.sessions7.expiration` +
|
||||||
` LEFT JOIN projections.login_names2 ON projections.sessions6.user_id = projections.login_names2.user_id AND projections.sessions6.instance_id = projections.login_names2.instance_id` +
|
` FROM projections.sessions7` +
|
||||||
` LEFT JOIN projections.users8_humans ON projections.sessions6.user_id = projections.users8_humans.user_id AND projections.sessions6.instance_id = projections.users8_humans.instance_id` +
|
` LEFT JOIN projections.login_names2 ON projections.sessions7.user_id = projections.login_names2.user_id AND projections.sessions7.instance_id = projections.login_names2.instance_id` +
|
||||||
` LEFT JOIN projections.users8 ON projections.sessions6.user_id = projections.users8.id AND projections.sessions6.instance_id = projections.users8.instance_id` +
|
` LEFT JOIN projections.users8_humans ON projections.sessions7.user_id = projections.users8_humans.user_id AND projections.sessions7.instance_id = projections.users8_humans.instance_id` +
|
||||||
|
` LEFT JOIN projections.users8 ON projections.sessions7.user_id = projections.users8.id AND projections.sessions7.instance_id = projections.users8.instance_id` +
|
||||||
` AS OF SYSTEM TIME '-1 ms'`)
|
` AS OF SYSTEM TIME '-1 ms'`)
|
||||||
expectedSessionsQuery = regexp.QuoteMeta(`SELECT projections.sessions6.id,` +
|
expectedSessionsQuery = regexp.QuoteMeta(`SELECT projections.sessions7.id,` +
|
||||||
` projections.sessions6.creation_date,` +
|
` projections.sessions7.creation_date,` +
|
||||||
` projections.sessions6.change_date,` +
|
` projections.sessions7.change_date,` +
|
||||||
` projections.sessions6.sequence,` +
|
` projections.sessions7.sequence,` +
|
||||||
` projections.sessions6.state,` +
|
` projections.sessions7.state,` +
|
||||||
` projections.sessions6.resource_owner,` +
|
` projections.sessions7.resource_owner,` +
|
||||||
` projections.sessions6.creator,` +
|
` projections.sessions7.creator,` +
|
||||||
` projections.sessions6.user_id,` +
|
` projections.sessions7.user_id,` +
|
||||||
` projections.sessions6.user_checked_at,` +
|
` projections.sessions7.user_checked_at,` +
|
||||||
` projections.login_names2.login_name,` +
|
` projections.login_names2.login_name,` +
|
||||||
` projections.users8_humans.display_name,` +
|
` projections.users8_humans.display_name,` +
|
||||||
` projections.users8.resource_owner,` +
|
` projections.users8.resource_owner,` +
|
||||||
` projections.sessions6.password_checked_at,` +
|
` projections.sessions7.password_checked_at,` +
|
||||||
` projections.sessions6.intent_checked_at,` +
|
` projections.sessions7.intent_checked_at,` +
|
||||||
` projections.sessions6.webauthn_checked_at,` +
|
` projections.sessions7.webauthn_checked_at,` +
|
||||||
` projections.sessions6.webauthn_user_verified,` +
|
` projections.sessions7.webauthn_user_verified,` +
|
||||||
` projections.sessions6.totp_checked_at,` +
|
` projections.sessions7.totp_checked_at,` +
|
||||||
` projections.sessions6.otp_sms_checked_at,` +
|
` projections.sessions7.otp_sms_checked_at,` +
|
||||||
` projections.sessions6.otp_email_checked_at,` +
|
` projections.sessions7.otp_email_checked_at,` +
|
||||||
` projections.sessions6.metadata,` +
|
` projections.sessions7.metadata,` +
|
||||||
|
` projections.sessions7.expiration,` +
|
||||||
` COUNT(*) OVER ()` +
|
` COUNT(*) OVER ()` +
|
||||||
` FROM projections.sessions6` +
|
` FROM projections.sessions7` +
|
||||||
` LEFT JOIN projections.login_names2 ON projections.sessions6.user_id = projections.login_names2.user_id AND projections.sessions6.instance_id = projections.login_names2.instance_id` +
|
` LEFT JOIN projections.login_names2 ON projections.sessions7.user_id = projections.login_names2.user_id AND projections.sessions7.instance_id = projections.login_names2.instance_id` +
|
||||||
` LEFT JOIN projections.users8_humans ON projections.sessions6.user_id = projections.users8_humans.user_id AND projections.sessions6.instance_id = projections.users8_humans.instance_id` +
|
` LEFT JOIN projections.users8_humans ON projections.sessions7.user_id = projections.users8_humans.user_id AND projections.sessions7.instance_id = projections.users8_humans.instance_id` +
|
||||||
` LEFT JOIN projections.users8 ON projections.sessions6.user_id = projections.users8.id AND projections.sessions6.instance_id = projections.users8.instance_id` +
|
` LEFT JOIN projections.users8 ON projections.sessions7.user_id = projections.users8.id AND projections.sessions7.instance_id = projections.users8.instance_id` +
|
||||||
` AS OF SYSTEM TIME '-1 ms'`)
|
` AS OF SYSTEM TIME '-1 ms'`)
|
||||||
|
|
||||||
sessionCols = []string{
|
sessionCols = []string{
|
||||||
@ -103,6 +105,7 @@ var (
|
|||||||
"user_agent_ip",
|
"user_agent_ip",
|
||||||
"user_agent_description",
|
"user_agent_description",
|
||||||
"user_agent_header",
|
"user_agent_header",
|
||||||
|
"expiration",
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionsCols = []string{
|
sessionsCols = []string{
|
||||||
@ -126,6 +129,7 @@ var (
|
|||||||
"otp_sms_checked_at",
|
"otp_sms_checked_at",
|
||||||
"otp_email_checked_at",
|
"otp_email_checked_at",
|
||||||
"metadata",
|
"metadata",
|
||||||
|
"expiration",
|
||||||
"count",
|
"count",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -182,6 +186,7 @@ func Test_SessionsPrepare(t *testing.T) {
|
|||||||
testNow,
|
testNow,
|
||||||
testNow,
|
testNow,
|
||||||
[]byte(`{"key": "dmFsdWU="}`),
|
[]byte(`{"key": "dmFsdWU="}`),
|
||||||
|
testNow,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -228,6 +233,7 @@ func Test_SessionsPrepare(t *testing.T) {
|
|||||||
Metadata: map[string][]byte{
|
Metadata: map[string][]byte{
|
||||||
"key": []byte("value"),
|
"key": []byte("value"),
|
||||||
},
|
},
|
||||||
|
Expiration: testNow,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -261,6 +267,7 @@ func Test_SessionsPrepare(t *testing.T) {
|
|||||||
testNow,
|
testNow,
|
||||||
testNow,
|
testNow,
|
||||||
[]byte(`{"key": "dmFsdWU="}`),
|
[]byte(`{"key": "dmFsdWU="}`),
|
||||||
|
testNow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"session-id2",
|
"session-id2",
|
||||||
@ -283,6 +290,7 @@ func Test_SessionsPrepare(t *testing.T) {
|
|||||||
testNow,
|
testNow,
|
||||||
testNow,
|
testNow,
|
||||||
[]byte(`{"key": "dmFsdWU="}`),
|
[]byte(`{"key": "dmFsdWU="}`),
|
||||||
|
testNow,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -329,6 +337,7 @@ func Test_SessionsPrepare(t *testing.T) {
|
|||||||
Metadata: map[string][]byte{
|
Metadata: map[string][]byte{
|
||||||
"key": []byte("value"),
|
"key": []byte("value"),
|
||||||
},
|
},
|
||||||
|
Expiration: testNow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ID: "session-id2",
|
ID: "session-id2",
|
||||||
@ -367,6 +376,7 @@ func Test_SessionsPrepare(t *testing.T) {
|
|||||||
Metadata: map[string][]byte{
|
Metadata: map[string][]byte{
|
||||||
"key": []byte("value"),
|
"key": []byte("value"),
|
||||||
},
|
},
|
||||||
|
Expiration: testNow,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -458,6 +468,7 @@ func Test_SessionPrepare(t *testing.T) {
|
|||||||
"1.2.3.4",
|
"1.2.3.4",
|
||||||
"agentDescription",
|
"agentDescription",
|
||||||
[]byte(`{"foo":["foo","bar"]}`),
|
[]byte(`{"foo":["foo","bar"]}`),
|
||||||
|
testNow,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -504,6 +515,7 @@ func Test_SessionPrepare(t *testing.T) {
|
|||||||
Description: gu.Ptr("agentDescription"),
|
Description: gu.Ptr("agentDescription"),
|
||||||
Header: http.Header{"foo": []string{"foo", "bar"}},
|
Header: http.Header{"foo": []string{"foo", "bar"}},
|
||||||
},
|
},
|
||||||
|
Expiration: testNow,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -18,5 +18,6 @@ func RegisterEventMappers(es *eventstore.Eventstore) {
|
|||||||
RegisterFilterEventMapper(AggregateType, OTPEmailCheckedType, eventstore.GenericEventMapper[OTPEmailCheckedEvent]).
|
RegisterFilterEventMapper(AggregateType, OTPEmailCheckedType, eventstore.GenericEventMapper[OTPEmailCheckedEvent]).
|
||||||
RegisterFilterEventMapper(AggregateType, TokenSetType, TokenSetEventMapper).
|
RegisterFilterEventMapper(AggregateType, TokenSetType, TokenSetEventMapper).
|
||||||
RegisterFilterEventMapper(AggregateType, MetadataSetType, MetadataSetEventMapper).
|
RegisterFilterEventMapper(AggregateType, MetadataSetType, MetadataSetEventMapper).
|
||||||
|
RegisterFilterEventMapper(AggregateType, LifetimeSetType, eventstore.GenericEventMapper[LifetimeSetEvent]).
|
||||||
RegisterFilterEventMapper(AggregateType, TerminateType, TerminateEventMapper)
|
RegisterFilterEventMapper(AggregateType, TerminateType, TerminateEventMapper)
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ const (
|
|||||||
OTPEmailCheckedType = sessionEventPrefix + "otp.email.checked"
|
OTPEmailCheckedType = sessionEventPrefix + "otp.email.checked"
|
||||||
TokenSetType = sessionEventPrefix + "token.set"
|
TokenSetType = sessionEventPrefix + "token.set"
|
||||||
MetadataSetType = sessionEventPrefix + "metadata.set"
|
MetadataSetType = sessionEventPrefix + "metadata.set"
|
||||||
|
LifetimeSetType = sessionEventPrefix + "lifetime.set"
|
||||||
TerminateType = sessionEventPrefix + "terminated"
|
TerminateType = sessionEventPrefix + "terminated"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -607,6 +608,39 @@ func MetadataSetEventMapper(event eventstore.Event) (eventstore.Event, error) {
|
|||||||
return added, nil
|
return added, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LifetimeSetEvent struct {
|
||||||
|
eventstore.BaseEvent `json:"-"`
|
||||||
|
|
||||||
|
Lifetime time.Duration `json:"lifetime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LifetimeSetEvent) Payload() interface{} {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LifetimeSetEvent) UniqueConstraints() []*eventstore.UniqueConstraint {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *LifetimeSetEvent) SetBaseEvent(base *eventstore.BaseEvent) {
|
||||||
|
e.BaseEvent = *base
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLifetimeSetEvent(
|
||||||
|
ctx context.Context,
|
||||||
|
aggregate *eventstore.Aggregate,
|
||||||
|
lifetime time.Duration,
|
||||||
|
) *LifetimeSetEvent {
|
||||||
|
return &LifetimeSetEvent{
|
||||||
|
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||||
|
ctx,
|
||||||
|
aggregate,
|
||||||
|
LifetimeSetType,
|
||||||
|
),
|
||||||
|
Lifetime: lifetime,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type TerminateEvent struct {
|
type TerminateEvent struct {
|
||||||
eventstore.BaseEvent `json:"-"`
|
eventstore.BaseEvent `json:"-"`
|
||||||
}
|
}
|
||||||
|
@ -509,6 +509,8 @@ Errors:
|
|||||||
Session:
|
Session:
|
||||||
NotExisting: Сесията не съществува
|
NotExisting: Сесията не съществува
|
||||||
Terminated: Сесията вече е прекратена
|
Terminated: Сесията вече е прекратена
|
||||||
|
Expired: Сесията е изтекла
|
||||||
|
PositiveLifetime: Животът на сесията не трябва да е по-малък от 0
|
||||||
Token:
|
Token:
|
||||||
Invalid: Токенът на сесията е невалиден
|
Invalid: Токенът на сесията е невалиден
|
||||||
WebAuthN:
|
WebAuthN:
|
||||||
|
@ -491,6 +491,8 @@ Errors:
|
|||||||
Session:
|
Session:
|
||||||
NotExisting: Session existiert nicht
|
NotExisting: Session existiert nicht
|
||||||
Terminated: Session bereits beendet
|
Terminated: Session bereits beendet
|
||||||
|
Expired: Session ist abgelaufen
|
||||||
|
PositiveLifetime: Session Lebensdauer darf nicht kleiner als 0 sein
|
||||||
Token:
|
Token:
|
||||||
Invalid: Session Token ist ungültig
|
Invalid: Session Token ist ungültig
|
||||||
WebAuthN:
|
WebAuthN:
|
||||||
|
@ -491,6 +491,8 @@ Errors:
|
|||||||
Session:
|
Session:
|
||||||
NotExisting: Session does not exist
|
NotExisting: Session does not exist
|
||||||
Terminated: Session already terminated
|
Terminated: Session already terminated
|
||||||
|
Expired: Session has expired
|
||||||
|
PositiveLifetime: Session lifetime must not be less than 0
|
||||||
Token:
|
Token:
|
||||||
Invalid: Session Token is invalid
|
Invalid: Session Token is invalid
|
||||||
WebAuthN:
|
WebAuthN:
|
||||||
|
@ -490,7 +490,9 @@ Errors:
|
|||||||
ScanFailed: La consulta de uso de los segundos de ejecuciónde acciones ha fallado
|
ScanFailed: La consulta de uso de los segundos de ejecuciónde acciones ha fallado
|
||||||
Session:
|
Session:
|
||||||
NotExisting: La sesión no existe
|
NotExisting: La sesión no existe
|
||||||
Terminated: Sesión ya terminada
|
Terminated: La Sesión ya terminada
|
||||||
|
Expired: La sesión ha expirado
|
||||||
|
PositiveLifetime: La duración de la sesión no debe ser inferior a 0
|
||||||
Token:
|
Token:
|
||||||
Invalid: El identificador de sesión no es válido
|
Invalid: El identificador de sesión no es válido
|
||||||
WebAuthN:
|
WebAuthN:
|
||||||
|
@ -491,6 +491,8 @@ Errors:
|
|||||||
Session:
|
Session:
|
||||||
NotExisting: La session n'existe pas
|
NotExisting: La session n'existe pas
|
||||||
Terminated: La session est déjà terminée
|
Terminated: La session est déjà terminée
|
||||||
|
Expired: La session a expiré
|
||||||
|
PositiveLifetime: La durée de vie de la session ne doit pas être inférieure à 0
|
||||||
Token:
|
Token:
|
||||||
Invalid: Le jeton de session n'est pas valide
|
Invalid: Le jeton de session n'est pas valide
|
||||||
WebAuthN:
|
WebAuthN:
|
||||||
|
@ -491,7 +491,9 @@ Errors:
|
|||||||
ScanFailed: La query dei secondi delle azioni utilizzate non è riuscita
|
ScanFailed: La query dei secondi delle azioni utilizzate non è riuscita
|
||||||
Session:
|
Session:
|
||||||
NotExisting: La sessione non esiste
|
NotExisting: La sessione non esiste
|
||||||
Terminated: Sessione già terminata
|
Terminated: La Sessione già terminata
|
||||||
|
Expired: La sessione è scaduta
|
||||||
|
PositiveLifetime: La durata della sessione non deve essere inferiore a 0
|
||||||
Token:
|
Token:
|
||||||
Invalid: Il token della sessione non è valido
|
Invalid: Il token della sessione non è valido
|
||||||
WebAuthN:
|
WebAuthN:
|
||||||
|
@ -480,6 +480,8 @@ Errors:
|
|||||||
Session:
|
Session:
|
||||||
NotExisting: セッションが存在しない
|
NotExisting: セッションが存在しない
|
||||||
Terminated: セッションはすでに終了しています
|
Terminated: セッションはすでに終了しています
|
||||||
|
Expired: セッションの有効期限が切れました
|
||||||
|
PositiveLifetime: セッションの有効期間は 0 未満であってはなりません
|
||||||
Token:
|
Token:
|
||||||
Invalid: セッショントークンが無効です
|
Invalid: セッショントークンが無効です
|
||||||
WebAuthN:
|
WebAuthN:
|
||||||
|
@ -491,6 +491,8 @@ Errors:
|
|||||||
Session:
|
Session:
|
||||||
NotExisting: Сесијата не постои
|
NotExisting: Сесијата не постои
|
||||||
Terminated: Сесијата е веќе завршена
|
Terminated: Сесијата е веќе завршена
|
||||||
|
Expired: Сесијата истече
|
||||||
|
PositiveLifetime: Времетраењето на сесијата не смее да биде помало од 0
|
||||||
Token:
|
Token:
|
||||||
Invalid: Токенот за сесија е невалиден
|
Invalid: Токенот за сесија е невалиден
|
||||||
WebAuthN:
|
WebAuthN:
|
||||||
|
@ -491,6 +491,8 @@ Errors:
|
|||||||
Session:
|
Session:
|
||||||
NotExisting: Sesja nie istnieje
|
NotExisting: Sesja nie istnieje
|
||||||
Terminated: Sesja już zakończona
|
Terminated: Sesja już zakończona
|
||||||
|
Expired: Sesja wygasła
|
||||||
|
PositiveLifetime: Czas życia sesji nie może być krótszy niż 0
|
||||||
Token:
|
Token:
|
||||||
Invalid: Token sesji jest nieprawidłowy
|
Invalid: Token sesji jest nieprawidłowy
|
||||||
WebAuthN:
|
WebAuthN:
|
||||||
|
@ -489,6 +489,8 @@ Errors:
|
|||||||
Session:
|
Session:
|
||||||
NotExisting: A sessão não existe
|
NotExisting: A sessão não existe
|
||||||
Terminated: A sessão já foi encerrada
|
Terminated: A sessão já foi encerrada
|
||||||
|
Expired: A Sessão expirou
|
||||||
|
PositiveLifetime: O tempo de vida da sessão não deve ser inferior a 0
|
||||||
Token:
|
Token:
|
||||||
Invalid: O token da sessão é inválido
|
Invalid: O token da sessão é inválido
|
||||||
WebAuthN:
|
WebAuthN:
|
||||||
|
@ -491,6 +491,8 @@ Errors:
|
|||||||
Session:
|
Session:
|
||||||
NotExisting: 会话不存在
|
NotExisting: 会话不存在
|
||||||
Terminated: 会话已经终止
|
Terminated: 会话已经终止
|
||||||
|
Expired: 会话已过期
|
||||||
|
PositiveLifetime: 会话生存期不得小于 0
|
||||||
Token:
|
Token:
|
||||||
Invalid: 会话令牌是无效的
|
Invalid: 会话令牌是无效的
|
||||||
WebAuthN:
|
WebAuthN:
|
||||||
|
@ -40,6 +40,11 @@ message Session {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
UserAgent user_agent = 7;
|
UserAgent user_agent = 7;
|
||||||
|
optional google.protobuf.Timestamp expiration_date = 8 [
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "\"time the session will be automatically invalidated\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
message Factors {
|
message Factors {
|
||||||
|
@ -10,6 +10,7 @@ import "zitadel/session/v2beta/session.proto";
|
|||||||
import "google/api/annotations.proto";
|
import "google/api/annotations.proto";
|
||||||
import "google/api/field_behavior.proto";
|
import "google/api/field_behavior.proto";
|
||||||
import "google/protobuf/struct.proto";
|
import "google/protobuf/struct.proto";
|
||||||
|
import "google/protobuf/duration.proto";
|
||||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||||
import "validate/validate.proto";
|
import "validate/validate.proto";
|
||||||
|
|
||||||
@ -275,6 +276,12 @@ message CreateSessionRequest{
|
|||||||
];
|
];
|
||||||
RequestChallenges challenges = 3;
|
RequestChallenges challenges = 3;
|
||||||
UserAgent user_agent = 4;
|
UserAgent user_agent = 4;
|
||||||
|
optional google.protobuf.Duration lifetime = 5 [
|
||||||
|
(validate.rules).duration = {gt: {seconds: 0}},
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "\"duration after which the session will be automatically invalidated\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
message CreateSessionResponse{
|
message CreateSessionResponse{
|
||||||
@ -322,6 +329,12 @@ message SetSessionRequest{
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
RequestChallenges challenges = 5;
|
RequestChallenges challenges = 5;
|
||||||
|
optional google.protobuf.Duration lifetime = 6 [
|
||||||
|
(validate.rules).duration = {gt: {seconds: 0}},
|
||||||
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
|
description: "\"duration after which the session will be automatically invalidated\"";
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetSessionResponse{
|
message SetSessionResponse{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user