mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-10 13:23:40 +00:00
fix: add search queries to ListSessions and remodel integration tests
This commit is contained in:
parent
8ec099ae28
commit
3da2db0851
@ -438,7 +438,7 @@ func startAPIs(
|
|||||||
if err := apis.RegisterService(ctx, user_v2.CreateServer(commands, queries, keys.User, keys.IDPConfig, idp.CallbackURL(), idp.SAMLRootURL(), assets.AssetAPI(), permissionCheck)); err != nil {
|
if err := apis.RegisterService(ctx, user_v2.CreateServer(commands, queries, keys.User, keys.IDPConfig, idp.CallbackURL(), idp.SAMLRootURL(), assets.AssetAPI(), permissionCheck)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := apis.RegisterService(ctx, session_v2beta.CreateServer(commands, queries)); err != nil {
|
if err := apis.RegisterService(ctx, session_v2beta.CreateServer(commands, queries, permissionCheck)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := apis.RegisterService(ctx, settings_v2beta.CreateServer(commands, queries)); err != nil {
|
if err := apis.RegisterService(ctx, settings_v2beta.CreateServer(commands, queries)); err != nil {
|
||||||
@ -450,7 +450,7 @@ func startAPIs(
|
|||||||
if err := apis.RegisterService(ctx, feature_v2beta.CreateServer(commands, queries)); err != nil {
|
if err := apis.RegisterService(ctx, feature_v2beta.CreateServer(commands, queries)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := apis.RegisterService(ctx, session_v2.CreateServer(commands, queries)); err != nil {
|
if err := apis.RegisterService(ctx, session_v2.CreateServer(commands, queries, permissionCheck)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := apis.RegisterService(ctx, settings_v2.CreateServer(commands, queries)); err != nil {
|
if err := apis.RegisterService(ctx, settings_v2.CreateServer(commands, queries)); err != nil {
|
||||||
|
233
internal/api/grpc/session/v2/integration_test/query_test.go
Normal file
233
internal/api/grpc/session/v2/integration_test/query_test.go
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package session_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/muhlemmer/gu"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/integration"
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/session/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestServer_GetSession(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
ctx context.Context
|
||||||
|
req *session.GetSessionRequest
|
||||||
|
dep func(ctx context.Context, t *testing.T, request *session.GetSessionRequest) uint64
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want *session.GetSessionResponse
|
||||||
|
wantFactors []wantFactor
|
||||||
|
wantExpirationWindow time.Duration
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "get session, no id provided",
|
||||||
|
args: args{
|
||||||
|
CTX,
|
||||||
|
&session.GetSessionRequest{
|
||||||
|
SessionId: "",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get session, not found",
|
||||||
|
args: args{
|
||||||
|
CTX,
|
||||||
|
&session.GetSessionRequest{
|
||||||
|
SessionId: "unknown",
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get session, no permission",
|
||||||
|
args: args{
|
||||||
|
UserCTX,
|
||||||
|
&session.GetSessionRequest{},
|
||||||
|
func(ctx context.Context, t *testing.T, request *session.GetSessionRequest) uint64 {
|
||||||
|
resp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
request.SessionId = resp.SessionId
|
||||||
|
return resp.GetDetails().GetSequence()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get session, permission, ok",
|
||||||
|
args: args{
|
||||||
|
CTX,
|
||||||
|
&session.GetSessionRequest{},
|
||||||
|
func(ctx context.Context, t *testing.T, request *session.GetSessionRequest) uint64 {
|
||||||
|
resp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
request.SessionId = resp.SessionId
|
||||||
|
return resp.GetDetails().GetSequence()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &session.GetSessionResponse{
|
||||||
|
Session: &session.Session{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get session, token, ok",
|
||||||
|
args: args{
|
||||||
|
UserCTX,
|
||||||
|
&session.GetSessionRequest{},
|
||||||
|
func(ctx context.Context, t *testing.T, request *session.GetSessionRequest) uint64 {
|
||||||
|
resp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
request.SessionId = resp.SessionId
|
||||||
|
request.SessionToken = gu.Ptr(resp.SessionToken)
|
||||||
|
return resp.GetDetails().GetSequence()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &session.GetSessionResponse{
|
||||||
|
Session: &session.Session{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get session, user agent, ok",
|
||||||
|
args: args{
|
||||||
|
UserCTX,
|
||||||
|
&session.GetSessionRequest{},
|
||||||
|
func(ctx context.Context, t *testing.T, request *session.GetSessionRequest) uint64 {
|
||||||
|
resp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
|
||||||
|
UserAgent: &session.UserAgent{
|
||||||
|
FingerprintId: gu.Ptr("fingerPrintID"),
|
||||||
|
Ip: gu.Ptr("1.2.3.4"),
|
||||||
|
Description: gu.Ptr("Description"),
|
||||||
|
Header: map[string]*session.UserAgent_HeaderValues{
|
||||||
|
"foo": {Values: []string{"foo", "bar"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
request.SessionId = resp.SessionId
|
||||||
|
request.SessionToken = gu.Ptr(resp.SessionToken)
|
||||||
|
return resp.GetDetails().GetSequence()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &session.GetSessionResponse{
|
||||||
|
Session: &session.Session{
|
||||||
|
UserAgent: &session.UserAgent{
|
||||||
|
FingerprintId: gu.Ptr("fingerPrintID"),
|
||||||
|
Ip: gu.Ptr("1.2.3.4"),
|
||||||
|
Description: gu.Ptr("Description"),
|
||||||
|
Header: map[string]*session.UserAgent_HeaderValues{
|
||||||
|
"foo": {Values: []string{"foo", "bar"}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get session, lifetime, ok",
|
||||||
|
args: args{
|
||||||
|
UserCTX,
|
||||||
|
&session.GetSessionRequest{},
|
||||||
|
func(ctx context.Context, t *testing.T, request *session.GetSessionRequest) uint64 {
|
||||||
|
resp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
|
||||||
|
Lifetime: durationpb.New(5 * time.Minute),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
request.SessionId = resp.SessionId
|
||||||
|
request.SessionToken = gu.Ptr(resp.SessionToken)
|
||||||
|
return resp.GetDetails().GetSequence()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantExpirationWindow: 5 * time.Minute,
|
||||||
|
want: &session.GetSessionResponse{
|
||||||
|
Session: &session.Session{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get session, metadata, ok",
|
||||||
|
args: args{
|
||||||
|
UserCTX,
|
||||||
|
&session.GetSessionRequest{},
|
||||||
|
func(ctx context.Context, t *testing.T, request *session.GetSessionRequest) uint64 {
|
||||||
|
resp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
|
||||||
|
Metadata: map[string][]byte{"foo": []byte("bar")},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
request.SessionId = resp.SessionId
|
||||||
|
request.SessionToken = gu.Ptr(resp.SessionToken)
|
||||||
|
return resp.GetDetails().GetSequence()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
want: &session.GetSessionResponse{
|
||||||
|
Session: &session.Session{
|
||||||
|
Metadata: map[string][]byte{"foo": []byte("bar")},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "get session, user, ok",
|
||||||
|
args: args{
|
||||||
|
UserCTX,
|
||||||
|
&session.GetSessionRequest{},
|
||||||
|
func(ctx context.Context, t *testing.T, request *session.GetSessionRequest) uint64 {
|
||||||
|
resp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{
|
||||||
|
Checks: &session.Checks{
|
||||||
|
User: &session.CheckUser{
|
||||||
|
Search: &session.CheckUser_UserId{
|
||||||
|
UserId: User.GetUserId(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
request.SessionId = resp.SessionId
|
||||||
|
request.SessionToken = gu.Ptr(resp.SessionToken)
|
||||||
|
return resp.GetDetails().GetSequence()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantFactors: []wantFactor{wantUserFactor},
|
||||||
|
want: &session.GetSessionResponse{
|
||||||
|
Session: &session.Session{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
var sequence uint64
|
||||||
|
if tt.args.dep != nil {
|
||||||
|
sequence = tt.args.dep(tt.args.ctx, t, tt.args.req)
|
||||||
|
}
|
||||||
|
|
||||||
|
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(tt.args.ctx, time.Minute)
|
||||||
|
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
|
||||||
|
got, err := Client.GetSession(tt.args.ctx, tt.args.req)
|
||||||
|
if tt.wantErr {
|
||||||
|
assert.Error(ttt, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !assert.NoError(ttt, err) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tt.want.Session.Id = tt.args.req.SessionId
|
||||||
|
tt.want.Session.Sequence = sequence
|
||||||
|
verifySession(ttt, got.GetSession(), tt.want.GetSession(), time.Minute, tt.wantExpirationWindow, User.GetUserId(), tt.wantFactors...)
|
||||||
|
}, retryDuration, tick)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
74
internal/api/grpc/session/v2/integration_test/server_test.go
Normal file
74
internal/api/grpc/session/v2/integration_test/server_test.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
//go:build integration
|
||||||
|
|
||||||
|
package session_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/zitadel/logging"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/integration"
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/session/v2"
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
CTX context.Context
|
||||||
|
IAMOwnerCTX context.Context
|
||||||
|
UserCTX context.Context
|
||||||
|
Instance *integration.Instance
|
||||||
|
Client session.SessionServiceClient
|
||||||
|
User *user.AddHumanUserResponse
|
||||||
|
DeactivatedUser *user.AddHumanUserResponse
|
||||||
|
LockedUser *user.AddHumanUserResponse
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
os.Exit(func() int {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
Instance = integration.NewInstance(ctx)
|
||||||
|
Client = Instance.Client.SessionV2
|
||||||
|
|
||||||
|
CTX = Instance.WithAuthorization(ctx, integration.UserTypeOrgOwner)
|
||||||
|
IAMOwnerCTX = Instance.WithAuthorization(ctx, integration.UserTypeIAMOwner)
|
||||||
|
UserCTX = Instance.WithAuthorization(ctx, integration.UserTypeNoPermission)
|
||||||
|
User = createFullUser(CTX)
|
||||||
|
DeactivatedUser = createDeactivatedUser(CTX)
|
||||||
|
LockedUser = createLockedUser(CTX)
|
||||||
|
return m.Run()
|
||||||
|
}())
|
||||||
|
}
|
||||||
|
|
||||||
|
func createFullUser(ctx context.Context) *user.AddHumanUserResponse {
|
||||||
|
userResp := Instance.CreateHumanUser(ctx)
|
||||||
|
Instance.Client.UserV2.VerifyEmail(ctx, &user.VerifyEmailRequest{
|
||||||
|
UserId: userResp.GetUserId(),
|
||||||
|
VerificationCode: userResp.GetEmailCode(),
|
||||||
|
})
|
||||||
|
Instance.Client.UserV2.VerifyPhone(ctx, &user.VerifyPhoneRequest{
|
||||||
|
UserId: userResp.GetUserId(),
|
||||||
|
VerificationCode: userResp.GetPhoneCode(),
|
||||||
|
})
|
||||||
|
Instance.SetUserPassword(ctx, userResp.GetUserId(), integration.UserPassword, false)
|
||||||
|
Instance.RegisterUserPasskey(ctx, userResp.GetUserId())
|
||||||
|
return userResp
|
||||||
|
}
|
||||||
|
|
||||||
|
func createDeactivatedUser(ctx context.Context) *user.AddHumanUserResponse {
|
||||||
|
userResp := Instance.CreateHumanUser(ctx)
|
||||||
|
_, err := Instance.Client.UserV2.DeactivateUser(ctx, &user.DeactivateUserRequest{UserId: userResp.GetUserId()})
|
||||||
|
logging.OnError(err).Fatal("deactivate human user")
|
||||||
|
return userResp
|
||||||
|
}
|
||||||
|
|
||||||
|
func createLockedUser(ctx context.Context) *user.AddHumanUserResponse {
|
||||||
|
userResp := Instance.CreateHumanUser(ctx)
|
||||||
|
_, err := Instance.Client.UserV2.LockUser(ctx, &user.LockUserRequest{UserId: userResp.GetUserId()})
|
||||||
|
logging.OnError(err).Fatal("lock human user")
|
||||||
|
return userResp
|
||||||
|
}
|
@ -5,7 +5,6 @@ package session_test
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -14,7 +13,6 @@ import (
|
|||||||
"github.com/pquerna/otp/totp"
|
"github.com/pquerna/otp/totp"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/zitadel/logging"
|
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
@ -29,63 +27,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
func verifyCurrentSession(t *testing.T, id, token string, sequence uint64, window time.Duration, metadata map[string][]byte, userAgent *session.UserAgent, expirationWindow time.Duration, userID string, factors ...wantFactor) *session.Session {
|
||||||
CTX context.Context
|
|
||||||
IAMOwnerCTX context.Context
|
|
||||||
Instance *integration.Instance
|
|
||||||
Client session.SessionServiceClient
|
|
||||||
User *user.AddHumanUserResponse
|
|
||||||
DeactivatedUser *user.AddHumanUserResponse
|
|
||||||
LockedUser *user.AddHumanUserResponse
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
os.Exit(func() int {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
Instance = integration.NewInstance(ctx)
|
|
||||||
Client = Instance.Client.SessionV2
|
|
||||||
|
|
||||||
CTX = Instance.WithAuthorization(ctx, integration.UserTypeOrgOwner)
|
|
||||||
IAMOwnerCTX = Instance.WithAuthorization(ctx, integration.UserTypeIAMOwner)
|
|
||||||
User = createFullUser(CTX)
|
|
||||||
DeactivatedUser = createDeactivatedUser(CTX)
|
|
||||||
LockedUser = createLockedUser(CTX)
|
|
||||||
return m.Run()
|
|
||||||
}())
|
|
||||||
}
|
|
||||||
|
|
||||||
func createFullUser(ctx context.Context) *user.AddHumanUserResponse {
|
|
||||||
userResp := Instance.CreateHumanUser(ctx)
|
|
||||||
Instance.Client.UserV2.VerifyEmail(ctx, &user.VerifyEmailRequest{
|
|
||||||
UserId: userResp.GetUserId(),
|
|
||||||
VerificationCode: userResp.GetEmailCode(),
|
|
||||||
})
|
|
||||||
Instance.Client.UserV2.VerifyPhone(ctx, &user.VerifyPhoneRequest{
|
|
||||||
UserId: userResp.GetUserId(),
|
|
||||||
VerificationCode: userResp.GetPhoneCode(),
|
|
||||||
})
|
|
||||||
Instance.SetUserPassword(ctx, userResp.GetUserId(), integration.UserPassword, false)
|
|
||||||
Instance.RegisterUserPasskey(ctx, userResp.GetUserId())
|
|
||||||
return userResp
|
|
||||||
}
|
|
||||||
|
|
||||||
func createDeactivatedUser(ctx context.Context) *user.AddHumanUserResponse {
|
|
||||||
userResp := Instance.CreateHumanUser(ctx)
|
|
||||||
_, err := Instance.Client.UserV2.DeactivateUser(ctx, &user.DeactivateUserRequest{UserId: userResp.GetUserId()})
|
|
||||||
logging.OnError(err).Fatal("deactivate human user")
|
|
||||||
return userResp
|
|
||||||
}
|
|
||||||
|
|
||||||
func createLockedUser(ctx context.Context) *user.AddHumanUserResponse {
|
|
||||||
userResp := Instance.CreateHumanUser(ctx)
|
|
||||||
_, err := Instance.Client.UserV2.LockUser(ctx, &user.LockUserRequest{UserId: userResp.GetUserId()})
|
|
||||||
logging.OnError(err).Fatal("lock human user")
|
|
||||||
return userResp
|
|
||||||
}
|
|
||||||
|
|
||||||
func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, window time.Duration, metadata map[string][]byte, userAgent *session.UserAgent, expirationWindow time.Duration, userID string, factors ...wantFactor) *session.Session {
|
|
||||||
t.Helper()
|
t.Helper()
|
||||||
require.NotEmpty(t, id)
|
require.NotEmpty(t, id)
|
||||||
require.NotEmpty(t, token)
|
require.NotEmpty(t, token)
|
||||||
@ -96,15 +38,25 @@ func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, windo
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
s := resp.GetSession()
|
s := resp.GetSession()
|
||||||
|
want := &session.Session{
|
||||||
|
Id: id,
|
||||||
|
Sequence: sequence,
|
||||||
|
Metadata: metadata,
|
||||||
|
UserAgent: userAgent,
|
||||||
|
}
|
||||||
|
verifySession(t, s, want, window, expirationWindow, userID, factors...)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
assert.Equal(t, id, s.GetId())
|
func verifySession(t assert.TestingT, s *session.Session, want *session.Session, window time.Duration, expirationWindow time.Duration, userID string, factors ...wantFactor) {
|
||||||
|
assert.Equal(t, want.Id, s.GetId())
|
||||||
assert.WithinRange(t, s.GetCreationDate().AsTime(), time.Now().Add(-window), time.Now().Add(window))
|
assert.WithinRange(t, s.GetCreationDate().AsTime(), time.Now().Add(-window), time.Now().Add(window))
|
||||||
assert.WithinRange(t, s.GetChangeDate().AsTime(), time.Now().Add(-window), time.Now().Add(window))
|
assert.WithinRange(t, s.GetChangeDate().AsTime(), time.Now().Add(-window), time.Now().Add(window))
|
||||||
assert.Equal(t, sequence, s.GetSequence())
|
assert.Equal(t, want.Sequence, s.GetSequence())
|
||||||
assert.Equal(t, metadata, s.GetMetadata())
|
assert.Equal(t, want.Metadata, s.GetMetadata())
|
||||||
|
|
||||||
if !proto.Equal(userAgent, s.GetUserAgent()) {
|
if !proto.Equal(want.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(), want.UserAgent)
|
||||||
}
|
}
|
||||||
if expirationWindow == 0 {
|
if expirationWindow == 0 {
|
||||||
assert.Nil(t, s.GetExpirationDate())
|
assert.Nil(t, s.GetExpirationDate())
|
||||||
@ -113,7 +65,6 @@ func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, windo
|
|||||||
}
|
}
|
||||||
|
|
||||||
verifyFactors(t, s.GetFactors(), window, userID, factors)
|
verifyFactors(t, s.GetFactors(), window, userID, factors)
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type wantFactor int
|
type wantFactor int
|
||||||
@ -129,7 +80,7 @@ const (
|
|||||||
wantOTPEmailFactor
|
wantOTPEmailFactor
|
||||||
)
|
)
|
||||||
|
|
||||||
func verifyFactors(t testing.TB, factors *session.Factors, window time.Duration, userID string, want []wantFactor) {
|
func verifyFactors(t assert.TestingT, factors *session.Factors, window time.Duration, userID string, want []wantFactor) {
|
||||||
for _, w := range want {
|
for _, w := range want {
|
||||||
switch w {
|
switch w {
|
||||||
case wantUserFactor:
|
case wantUserFactor:
|
||||||
@ -194,8 +145,15 @@ func TestServer_CreateSession(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "user agent",
|
name: "full session",
|
||||||
req: &session.CreateSessionRequest{
|
req: &session.CreateSessionRequest{
|
||||||
|
Checks: &session.Checks{
|
||||||
|
User: &session.CheckUser{
|
||||||
|
Search: &session.CheckUser_UserId{
|
||||||
|
UserId: User.GetUserId(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
Metadata: map[string][]byte{"foo": []byte("bar")},
|
Metadata: map[string][]byte{"foo": []byte("bar")},
|
||||||
UserAgent: &session.UserAgent{
|
UserAgent: &session.UserAgent{
|
||||||
FingerprintId: gu.Ptr("fingerPrintID"),
|
FingerprintId: gu.Ptr("fingerPrintID"),
|
||||||
@ -205,6 +163,7 @@ func TestServer_CreateSession(t *testing.T) {
|
|||||||
"foo": {Values: []string{"foo", "bar"}},
|
"foo": {Values: []string{"foo", "bar"}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Lifetime: durationpb.New(5 * time.Minute),
|
||||||
},
|
},
|
||||||
want: &session.CreateSessionResponse{
|
want: &session.CreateSessionResponse{
|
||||||
Details: &object.Details{
|
Details: &object.Details{
|
||||||
@ -212,14 +171,6 @@ func TestServer_CreateSession(t *testing.T) {
|
|||||||
ResourceOwner: Instance.ID(),
|
ResourceOwner: Instance.ID(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
wantUserAgent: &session.UserAgent{
|
|
||||||
FingerprintId: gu.Ptr("fingerPrintID"),
|
|
||||||
Ip: gu.Ptr("1.2.3.4"),
|
|
||||||
Description: gu.Ptr("Description"),
|
|
||||||
Header: map[string]*session.UserAgent_HeaderValues{
|
|
||||||
"foo": {Values: []string{"foo", "bar"}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "negative lifetime",
|
name: "negative lifetime",
|
||||||
@ -229,40 +180,6 @@ func TestServer_CreateSession(t *testing.T) {
|
|||||||
},
|
},
|
||||||
wantErr: true,
|
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{
|
|
||||||
ChangeDate: timestamppb.Now(),
|
|
||||||
ResourceOwner: Instance.ID(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantExpirationWindow: 5 * time.Minute,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "with user",
|
|
||||||
req: &session.CreateSessionRequest{
|
|
||||||
Checks: &session.Checks{
|
|
||||||
User: &session.CheckUser{
|
|
||||||
Search: &session.CheckUser_UserId{
|
|
||||||
UserId: User.GetUserId(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Metadata: map[string][]byte{"foo": []byte("bar")},
|
|
||||||
},
|
|
||||||
want: &session.CreateSessionResponse{
|
|
||||||
Details: &object.Details{
|
|
||||||
ChangeDate: timestamppb.Now(),
|
|
||||||
ResourceOwner: Instance.ID(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantFactors: []wantFactor{wantUserFactor},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "deactivated user",
|
name: "deactivated user",
|
||||||
req: &session.CreateSessionRequest{
|
req: &session.CreateSessionRequest{
|
||||||
@ -340,8 +257,6 @@ 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.wantExpirationWindow, User.GetUserId(), tt.wantFactors...)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
242
internal/api/grpc/session/v2/query.go
Normal file
242
internal/api/grpc/session/v2/query.go
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
package session
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/muhlemmer/gu"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
|
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||||
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
|
objpb "github.com/zitadel/zitadel/pkg/grpc/object"
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/session/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
timestampComparisons = map[objpb.TimestampQueryMethod]query.TimestampComparison{
|
||||||
|
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_EQUALS: query.TimestampEquals,
|
||||||
|
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_GREATER: query.TimestampGreater,
|
||||||
|
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_GREATER_OR_EQUALS: query.TimestampGreaterOrEquals,
|
||||||
|
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_LESS: query.TimestampLess,
|
||||||
|
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_LESS_OR_EQUALS: query.TimestampLessOrEquals,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) GetSession(ctx context.Context, req *session.GetSessionRequest) (*session.GetSessionResponse, error) {
|
||||||
|
res, err := s.query.SessionByID(ctx, true, req.GetSessionId(), req.GetSessionToken(), s.checkPermission)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &session.GetSessionResponse{
|
||||||
|
Session: sessionToPb(res),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequest) (*session.ListSessionsResponse, error) {
|
||||||
|
queries, err := listSessionsRequestToQuery(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
sessions, err := s.query.SearchSessions(ctx, queries, s.checkPermission)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &session.ListSessionsResponse{
|
||||||
|
Details: object.ToListDetails(sessions.SearchResponse),
|
||||||
|
Sessions: sessionsToPb(sessions.Sessions),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listSessionsRequestToQuery(ctx context.Context, req *session.ListSessionsRequest) (*query.SessionsSearchQueries, error) {
|
||||||
|
offset, limit, asc := object.ListQueryToQuery(req.Query)
|
||||||
|
queries, err := sessionQueriesToQuery(ctx, req.GetQueries())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &query.SessionsSearchQueries{
|
||||||
|
SearchRequest: query.SearchRequest{
|
||||||
|
Offset: offset,
|
||||||
|
Limit: limit,
|
||||||
|
Asc: asc,
|
||||||
|
SortingColumn: fieldNameToSessionColumn(req.GetSortingColumn()),
|
||||||
|
},
|
||||||
|
Queries: queries,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sessionQueriesToQuery(ctx context.Context, queries []*session.SearchQuery) (_ []query.SearchQuery, err error) {
|
||||||
|
q := make([]query.SearchQuery, len(queries))
|
||||||
|
for i, v := range queries {
|
||||||
|
q[i], err = sessionQueryToQuery(ctx, v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return q, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sessionQueryToQuery(ctx context.Context, sq *session.SearchQuery) (query.SearchQuery, error) {
|
||||||
|
switch q := sq.Query.(type) {
|
||||||
|
case *session.SearchQuery_IdsQuery:
|
||||||
|
return idsQueryToQuery(q.IdsQuery)
|
||||||
|
case *session.SearchQuery_UserIdQuery:
|
||||||
|
return query.NewUserIDSearchQuery(q.UserIdQuery.GetId())
|
||||||
|
case *session.SearchQuery_CreationDateQuery:
|
||||||
|
return creationDateQueryToQuery(q.CreationDateQuery)
|
||||||
|
case *session.SearchQuery_OwnCreatorQuery:
|
||||||
|
return query.NewSessionCreatorSearchQuery(authz.GetCtxData(ctx).UserID)
|
||||||
|
case *session.SearchQuery_OwnUseragentQuery:
|
||||||
|
return query.NewSessionUserAgentFingerprintIDSearchQuery(authz.GetCtxData(ctx).AgentID)
|
||||||
|
default:
|
||||||
|
return nil, zerrors.ThrowInvalidArgument(nil, "GRPC-Sfefs", "List.Query.Invalid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func idsQueryToQuery(q *session.IDsQuery) (query.SearchQuery, error) {
|
||||||
|
return query.NewSessionIDsSearchQuery(q.Ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
func creationDateQueryToQuery(q *session.CreationDateQuery) (query.SearchQuery, error) {
|
||||||
|
comparison := timestampComparisons[q.GetMethod()]
|
||||||
|
return query.NewCreationDateQuery(q.GetCreationDate().AsTime(), comparison)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fieldNameToSessionColumn(field session.SessionFieldName) query.Column {
|
||||||
|
switch field {
|
||||||
|
case session.SessionFieldName_SESSION_FIELD_NAME_CREATION_DATE:
|
||||||
|
return query.SessionColumnCreationDate
|
||||||
|
default:
|
||||||
|
return query.Column{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sessionsToPb(sessions []*query.Session) []*session.Session {
|
||||||
|
s := make([]*session.Session, len(sessions))
|
||||||
|
for i, session := range sessions {
|
||||||
|
s[i] = sessionToPb(session)
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func sessionToPb(s *query.Session) *session.Session {
|
||||||
|
return &session.Session{
|
||||||
|
Id: s.ID,
|
||||||
|
CreationDate: timestamppb.New(s.CreationDate),
|
||||||
|
ChangeDate: timestamppb.New(s.ChangeDate),
|
||||||
|
Sequence: s.Sequence,
|
||||||
|
Factors: factorsToPb(s),
|
||||||
|
Metadata: s.Metadata,
|
||||||
|
UserAgent: userAgentToPb(s.UserAgent),
|
||||||
|
ExpirationDate: expirationToPb(s.Expiration),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func userAgentToPb(ua domain.UserAgent) *session.UserAgent {
|
||||||
|
if ua.IsEmpty() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
out := &session.UserAgent{
|
||||||
|
FingerprintId: ua.FingerprintID,
|
||||||
|
Description: ua.Description,
|
||||||
|
}
|
||||||
|
if ua.IP != nil {
|
||||||
|
out.Ip = gu.Ptr(ua.IP.String())
|
||||||
|
}
|
||||||
|
if ua.Header == nil {
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
out.Header = make(map[string]*session.UserAgent_HeaderValues, len(ua.Header))
|
||||||
|
for k, v := range ua.Header {
|
||||||
|
out.Header[k] = &session.UserAgent_HeaderValues{
|
||||||
|
Values: v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
user := userFactorToPb(s.UserFactor)
|
||||||
|
if user == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &session.Factors{
|
||||||
|
User: user,
|
||||||
|
Password: passwordFactorToPb(s.PasswordFactor),
|
||||||
|
WebAuthN: webAuthNFactorToPb(s.WebAuthNFactor),
|
||||||
|
Intent: intentFactorToPb(s.IntentFactor),
|
||||||
|
Totp: totpFactorToPb(s.TOTPFactor),
|
||||||
|
OtpSms: otpFactorToPb(s.OTPSMSFactor),
|
||||||
|
OtpEmail: otpFactorToPb(s.OTPEmailFactor),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func passwordFactorToPb(factor query.SessionPasswordFactor) *session.PasswordFactor {
|
||||||
|
if factor.PasswordCheckedAt.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &session.PasswordFactor{
|
||||||
|
VerifiedAt: timestamppb.New(factor.PasswordCheckedAt),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func intentFactorToPb(factor query.SessionIntentFactor) *session.IntentFactor {
|
||||||
|
if factor.IntentCheckedAt.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &session.IntentFactor{
|
||||||
|
VerifiedAt: timestamppb.New(factor.IntentCheckedAt),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func webAuthNFactorToPb(factor query.SessionWebAuthNFactor) *session.WebAuthNFactor {
|
||||||
|
if factor.WebAuthNCheckedAt.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &session.WebAuthNFactor{
|
||||||
|
VerifiedAt: timestamppb.New(factor.WebAuthNCheckedAt),
|
||||||
|
UserVerified: factor.UserVerified,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func totpFactorToPb(factor query.SessionTOTPFactor) *session.TOTPFactor {
|
||||||
|
if factor.TOTPCheckedAt.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &session.TOTPFactor{
|
||||||
|
VerifiedAt: timestamppb.New(factor.TOTPCheckedAt),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func otpFactorToPb(factor query.SessionOTPFactor) *session.OTPFactor {
|
||||||
|
if factor.OTPCheckedAt.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &session.OTPFactor{
|
||||||
|
VerifiedAt: timestamppb.New(factor.OTPCheckedAt),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func userFactorToPb(factor query.SessionUserFactor) *session.UserFactor {
|
||||||
|
if factor.UserID == "" || factor.UserCheckedAt.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &session.UserFactor{
|
||||||
|
VerifiedAt: timestamppb.New(factor.UserCheckedAt),
|
||||||
|
Id: factor.UserID,
|
||||||
|
LoginName: factor.LoginName,
|
||||||
|
DisplayName: factor.DisplayName,
|
||||||
|
OrganizationId: factor.ResourceOwner,
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||||
"github.com/zitadel/zitadel/internal/command"
|
"github.com/zitadel/zitadel/internal/command"
|
||||||
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
"github.com/zitadel/zitadel/pkg/grpc/session/v2"
|
"github.com/zitadel/zitadel/pkg/grpc/session/v2"
|
||||||
)
|
)
|
||||||
@ -16,6 +17,8 @@ type Server struct {
|
|||||||
session.UnimplementedSessionServiceServer
|
session.UnimplementedSessionServiceServer
|
||||||
command *command.Commands
|
command *command.Commands
|
||||||
query *query.Queries
|
query *query.Queries
|
||||||
|
|
||||||
|
checkPermission domain.PermissionCheck
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct{}
|
type Config struct{}
|
||||||
@ -23,10 +26,12 @@ type Config struct{}
|
|||||||
func CreateServer(
|
func CreateServer(
|
||||||
command *command.Commands,
|
command *command.Commands,
|
||||||
query *query.Queries,
|
query *query.Queries,
|
||||||
|
checkPermission domain.PermissionCheck,
|
||||||
) *Server {
|
) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
command: command,
|
command: command,
|
||||||
query: query,
|
query: query,
|
||||||
|
checkPermission: checkPermission,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,56 +6,17 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/muhlemmer/gu"
|
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
"google.golang.org/protobuf/types/known/structpb"
|
"google.golang.org/protobuf/types/known/structpb"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
|
||||||
|
|
||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
|
||||||
"github.com/zitadel/zitadel/internal/command"
|
"github.com/zitadel/zitadel/internal/command"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
"github.com/zitadel/zitadel/internal/zerrors"
|
"github.com/zitadel/zitadel/internal/zerrors"
|
||||||
objpb "github.com/zitadel/zitadel/pkg/grpc/object"
|
|
||||||
"github.com/zitadel/zitadel/pkg/grpc/session/v2"
|
"github.com/zitadel/zitadel/pkg/grpc/session/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
timestampComparisons = map[objpb.TimestampQueryMethod]query.TimestampComparison{
|
|
||||||
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_EQUALS: query.TimestampEquals,
|
|
||||||
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_GREATER: query.TimestampGreater,
|
|
||||||
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_GREATER_OR_EQUALS: query.TimestampGreaterOrEquals,
|
|
||||||
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_LESS: query.TimestampLess,
|
|
||||||
objpb.TimestampQueryMethod_TIMESTAMP_QUERY_METHOD_LESS_OR_EQUALS: query.TimestampLessOrEquals,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *Server) GetSession(ctx context.Context, req *session.GetSessionRequest) (*session.GetSessionResponse, error) {
|
|
||||||
res, err := s.query.SessionByID(ctx, true, req.GetSessionId(), req.GetSessionToken())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &session.GetSessionResponse{
|
|
||||||
Session: sessionToPb(res),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequest) (*session.ListSessionsResponse, error) {
|
|
||||||
queries, err := listSessionsRequestToQuery(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
sessions, err := s.query.SearchSessions(ctx, queries)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &session.ListSessionsResponse{
|
|
||||||
Details: object.ToListDetails(sessions.SearchResponse),
|
|
||||||
Sessions: sessionsToPb(sessions.Sessions),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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, lifetime, err := s.createSessionRequestToCommand(ctx, req)
|
checks, metadata, userAgent, lifetime, err := s.createSessionRequestToCommand(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -110,197 +71,6 @@ func (s *Server) DeleteSession(ctx context.Context, req *session.DeleteSessionRe
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sessionsToPb(sessions []*query.Session) []*session.Session {
|
|
||||||
s := make([]*session.Session, len(sessions))
|
|
||||||
for i, session := range sessions {
|
|
||||||
s[i] = sessionToPb(session)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func sessionToPb(s *query.Session) *session.Session {
|
|
||||||
return &session.Session{
|
|
||||||
Id: s.ID,
|
|
||||||
CreationDate: timestamppb.New(s.CreationDate),
|
|
||||||
ChangeDate: timestamppb.New(s.ChangeDate),
|
|
||||||
Sequence: s.Sequence,
|
|
||||||
Factors: factorsToPb(s),
|
|
||||||
Metadata: s.Metadata,
|
|
||||||
UserAgent: userAgentToPb(s.UserAgent),
|
|
||||||
ExpirationDate: expirationToPb(s.Expiration),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func userAgentToPb(ua domain.UserAgent) *session.UserAgent {
|
|
||||||
if ua.IsEmpty() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
out := &session.UserAgent{
|
|
||||||
FingerprintId: ua.FingerprintID,
|
|
||||||
Description: ua.Description,
|
|
||||||
}
|
|
||||||
if ua.IP != nil {
|
|
||||||
out.Ip = gu.Ptr(ua.IP.String())
|
|
||||||
}
|
|
||||||
if ua.Header == nil {
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
out.Header = make(map[string]*session.UserAgent_HeaderValues, len(ua.Header))
|
|
||||||
for k, v := range ua.Header {
|
|
||||||
out.Header[k] = &session.UserAgent_HeaderValues{
|
|
||||||
Values: v,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 {
|
|
||||||
user := userFactorToPb(s.UserFactor)
|
|
||||||
if user == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &session.Factors{
|
|
||||||
User: user,
|
|
||||||
Password: passwordFactorToPb(s.PasswordFactor),
|
|
||||||
WebAuthN: webAuthNFactorToPb(s.WebAuthNFactor),
|
|
||||||
Intent: intentFactorToPb(s.IntentFactor),
|
|
||||||
Totp: totpFactorToPb(s.TOTPFactor),
|
|
||||||
OtpSms: otpFactorToPb(s.OTPSMSFactor),
|
|
||||||
OtpEmail: otpFactorToPb(s.OTPEmailFactor),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func passwordFactorToPb(factor query.SessionPasswordFactor) *session.PasswordFactor {
|
|
||||||
if factor.PasswordCheckedAt.IsZero() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &session.PasswordFactor{
|
|
||||||
VerifiedAt: timestamppb.New(factor.PasswordCheckedAt),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func intentFactorToPb(factor query.SessionIntentFactor) *session.IntentFactor {
|
|
||||||
if factor.IntentCheckedAt.IsZero() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &session.IntentFactor{
|
|
||||||
VerifiedAt: timestamppb.New(factor.IntentCheckedAt),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func webAuthNFactorToPb(factor query.SessionWebAuthNFactor) *session.WebAuthNFactor {
|
|
||||||
if factor.WebAuthNCheckedAt.IsZero() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &session.WebAuthNFactor{
|
|
||||||
VerifiedAt: timestamppb.New(factor.WebAuthNCheckedAt),
|
|
||||||
UserVerified: factor.UserVerified,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func totpFactorToPb(factor query.SessionTOTPFactor) *session.TOTPFactor {
|
|
||||||
if factor.TOTPCheckedAt.IsZero() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &session.TOTPFactor{
|
|
||||||
VerifiedAt: timestamppb.New(factor.TOTPCheckedAt),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func otpFactorToPb(factor query.SessionOTPFactor) *session.OTPFactor {
|
|
||||||
if factor.OTPCheckedAt.IsZero() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &session.OTPFactor{
|
|
||||||
VerifiedAt: timestamppb.New(factor.OTPCheckedAt),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func userFactorToPb(factor query.SessionUserFactor) *session.UserFactor {
|
|
||||||
if factor.UserID == "" || factor.UserCheckedAt.IsZero() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &session.UserFactor{
|
|
||||||
VerifiedAt: timestamppb.New(factor.UserCheckedAt),
|
|
||||||
Id: factor.UserID,
|
|
||||||
LoginName: factor.LoginName,
|
|
||||||
DisplayName: factor.DisplayName,
|
|
||||||
OrganizationId: factor.ResourceOwner,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func listSessionsRequestToQuery(ctx context.Context, req *session.ListSessionsRequest) (*query.SessionsSearchQueries, error) {
|
|
||||||
offset, limit, asc := object.ListQueryToQuery(req.Query)
|
|
||||||
queries, err := sessionQueriesToQuery(ctx, req.GetQueries())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &query.SessionsSearchQueries{
|
|
||||||
SearchRequest: query.SearchRequest{
|
|
||||||
Offset: offset,
|
|
||||||
Limit: limit,
|
|
||||||
Asc: asc,
|
|
||||||
SortingColumn: fieldNameToSessionColumn(req.GetSortingColumn()),
|
|
||||||
},
|
|
||||||
Queries: queries,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sessionQueriesToQuery(ctx context.Context, queries []*session.SearchQuery) (_ []query.SearchQuery, err error) {
|
|
||||||
q := make([]query.SearchQuery, len(queries)+1)
|
|
||||||
for i, v := range queries {
|
|
||||||
q[i], err = sessionQueryToQuery(v)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
creatorQuery, err := query.NewSessionCreatorSearchQuery(authz.GetCtxData(ctx).UserID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
q[len(queries)] = creatorQuery
|
|
||||||
return q, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sessionQueryToQuery(sq *session.SearchQuery) (query.SearchQuery, error) {
|
|
||||||
switch q := sq.Query.(type) {
|
|
||||||
case *session.SearchQuery_IdsQuery:
|
|
||||||
return idsQueryToQuery(q.IdsQuery)
|
|
||||||
case *session.SearchQuery_UserIdQuery:
|
|
||||||
return query.NewUserIDSearchQuery(q.UserIdQuery.GetId())
|
|
||||||
case *session.SearchQuery_CreationDateQuery:
|
|
||||||
return creationDateQueryToQuery(q.CreationDateQuery)
|
|
||||||
default:
|
|
||||||
return nil, zerrors.ThrowInvalidArgument(nil, "GRPC-Sfefs", "List.Query.Invalid")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func idsQueryToQuery(q *session.IDsQuery) (query.SearchQuery, error) {
|
|
||||||
return query.NewSessionIDsSearchQuery(q.Ids)
|
|
||||||
}
|
|
||||||
|
|
||||||
func creationDateQueryToQuery(q *session.CreationDateQuery) (query.SearchQuery, error) {
|
|
||||||
comparison := timestampComparisons[q.GetMethod()]
|
|
||||||
return query.NewCreationDateQuery(q.GetCreationDate().AsTime(), comparison)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fieldNameToSessionColumn(field session.SessionFieldName) query.Column {
|
|
||||||
switch field {
|
|
||||||
case session.SessionFieldName_SESSION_FIELD_NAME_CREATION_DATE:
|
|
||||||
return query.SessionColumnCreationDate
|
|
||||||
default:
|
|
||||||
return query.Column{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) createSessionRequestToCommand(ctx context.Context, req *session.CreateSessionRequest) ([]command.SessionCommand, map[string][]byte, *domain.UserAgent, time.Duration, 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 {
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/api/authz"
|
"github.com/zitadel/zitadel/internal/api/authz"
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
"github.com/zitadel/zitadel/internal/api/grpc/server"
|
||||||
"github.com/zitadel/zitadel/internal/command"
|
"github.com/zitadel/zitadel/internal/command"
|
||||||
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
session "github.com/zitadel/zitadel/pkg/grpc/session/v2beta"
|
session "github.com/zitadel/zitadel/pkg/grpc/session/v2beta"
|
||||||
)
|
)
|
||||||
@ -16,6 +17,8 @@ type Server struct {
|
|||||||
session.UnimplementedSessionServiceServer
|
session.UnimplementedSessionServiceServer
|
||||||
command *command.Commands
|
command *command.Commands
|
||||||
query *query.Queries
|
query *query.Queries
|
||||||
|
|
||||||
|
checkPermission domain.PermissionCheck
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct{}
|
type Config struct{}
|
||||||
@ -23,10 +26,12 @@ type Config struct{}
|
|||||||
func CreateServer(
|
func CreateServer(
|
||||||
command *command.Commands,
|
command *command.Commands,
|
||||||
query *query.Queries,
|
query *query.Queries,
|
||||||
|
checkPermission domain.PermissionCheck,
|
||||||
) *Server {
|
) *Server {
|
||||||
return &Server{
|
return &Server{
|
||||||
command: command,
|
command: command,
|
||||||
query: query,
|
query: query,
|
||||||
|
checkPermission: checkPermission,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (s *Server) GetSession(ctx context.Context, req *session.GetSessionRequest) (*session.GetSessionResponse, error) {
|
func (s *Server) GetSession(ctx context.Context, req *session.GetSessionRequest) (*session.GetSessionResponse, error) {
|
||||||
res, err := s.query.SessionByID(ctx, true, req.GetSessionId(), req.GetSessionToken())
|
res, err := s.query.SessionByID(ctx, true, req.GetSessionId(), req.GetSessionToken(), s.checkPermission)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -46,7 +46,7 @@ func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequ
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sessions, err := s.query.SearchSessions(ctx, queries)
|
sessions, err := s.query.SearchSessions(ctx, queries, s.checkPermission)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ func (repo *TokenVerifierRepo) verifySessionToken(ctx context.Context, sessionID
|
|||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
session, err := repo.Query.SessionByID(ctx, true, sessionID, token)
|
session, err := repo.Query.SessionByID(ctx, true, sessionID, token, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", "", err
|
return "", "", "", err
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ type Queries interface {
|
|||||||
GetNotifyUserByID(ctx context.Context, shouldTriggered bool, userID string) (*query.NotifyUser, error)
|
GetNotifyUserByID(ctx context.Context, shouldTriggered bool, userID string) (*query.NotifyUser, error)
|
||||||
CustomTextListByTemplate(ctx context.Context, aggregateID, template string, withOwnerRemoved bool) (*query.CustomTexts, error)
|
CustomTextListByTemplate(ctx context.Context, aggregateID, template string, withOwnerRemoved bool) (*query.CustomTexts, error)
|
||||||
SearchInstanceDomains(ctx context.Context, queries *query.InstanceDomainSearchQueries) (*query.InstanceDomains, error)
|
SearchInstanceDomains(ctx context.Context, queries *query.InstanceDomainSearchQueries) (*query.InstanceDomains, error)
|
||||||
SessionByID(ctx context.Context, shouldTriggerBulk bool, id, sessionToken string) (*query.Session, error)
|
SessionByID(ctx context.Context, shouldTriggerBulk bool, id, sessionToken string, check domain.PermissionCheck) (*query.Session, error)
|
||||||
NotificationPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string, withOwnerRemoved bool) (*query.NotificationPolicy, error)
|
NotificationPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string, withOwnerRemoved bool) (*query.NotificationPolicy, error)
|
||||||
SearchMilestones(ctx context.Context, instanceIDs []string, queries *query.MilestonesSearchQueries) (*query.Milestones, error)
|
SearchMilestones(ctx context.Context, instanceIDs []string, queries *query.MilestonesSearchQueries) (*query.Milestones, error)
|
||||||
NotificationProviderByIDAndType(ctx context.Context, aggID string, providerType domain.NotificationProviderType) (*query.DebugNotificationProvider, error)
|
NotificationProviderByIDAndType(ctx context.Context, aggID string, providerType domain.NotificationProviderType) (*query.DebugNotificationProvider, error)
|
||||||
|
@ -400,7 +400,7 @@ func (u *userNotifier) reduceSessionOTPSMSChallenged(event eventstore.Event) (*h
|
|||||||
if alreadyHandled {
|
if alreadyHandled {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
s, err := u.queries.SessionByID(ctx, true, e.Aggregate().ID, "")
|
s, err := u.queries.SessionByID(ctx, true, e.Aggregate().ID, "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -496,7 +496,7 @@ func (u *userNotifier) reduceSessionOTPEmailChallenged(event eventstore.Event) (
|
|||||||
if alreadyHandled {
|
if alreadyHandled {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
s, err := u.queries.SessionByID(ctx, true, e.Aggregate().ID, "")
|
s, err := u.queries.SessionByID(ctx, true, e.Aggregate().ID, "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -324,7 +324,7 @@ func (u *userNotifierLegacy) reduceSessionOTPSMSChallenged(event eventstore.Even
|
|||||||
return handler.NewNoOpStatement(e), nil
|
return handler.NewNoOpStatement(e), nil
|
||||||
}
|
}
|
||||||
ctx := HandlerContext(event.Aggregate())
|
ctx := HandlerContext(event.Aggregate())
|
||||||
s, err := u.queries.SessionByID(ctx, true, e.Aggregate().ID, "")
|
s, err := u.queries.SessionByID(ctx, true, e.Aggregate().ID, "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -428,7 +428,7 @@ func (u *userNotifierLegacy) reduceSessionOTPEmailChallenged(event eventstore.Ev
|
|||||||
return handler.NewNoOpStatement(e), nil
|
return handler.NewNoOpStatement(e), nil
|
||||||
}
|
}
|
||||||
ctx := HandlerContext(event.Aggregate())
|
ctx := HandlerContext(event.Aggregate())
|
||||||
s, err := u.queries.SessionByID(ctx, true, e.Aggregate().ID, "")
|
s, err := u.queries.SessionByID(ctx, true, e.Aggregate().ID, "", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
sq "github.com/Masterminds/squirrel"
|
sq "github.com/Masterminds/squirrel"
|
||||||
@ -80,6 +81,24 @@ type SessionsSearchQueries struct {
|
|||||||
Queries []SearchQuery
|
Queries []SearchQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sessionsCheckPermission(ctx context.Context, sessions *Sessions, permissionCheck domain.PermissionCheck) {
|
||||||
|
sessions.Sessions = slices.DeleteFunc(sessions.Sessions,
|
||||||
|
func(session *Session) bool {
|
||||||
|
return sessionCheckPermission(ctx, session.ResourceOwner, session.Creator, permissionCheck) != nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sessionCheckPermission(ctx context.Context, resourceOwner string, creator string, permissionCheck domain.PermissionCheck) error {
|
||||||
|
data := authz.GetCtxData(ctx)
|
||||||
|
if data.UserID != creator {
|
||||||
|
if err := permissionCheck(ctx, domain.PermissionSessionRead, resourceOwner, ""); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (q *SessionsSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
func (q *SessionsSearchQueries) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
|
||||||
query = q.SearchRequest.toQuery(query)
|
query = q.SearchRequest.toQuery(query)
|
||||||
for _, q := range q.Queries {
|
for _, q := range q.Queries {
|
||||||
@ -195,7 +214,24 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
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, permissionCheck domain.PermissionCheck) (session *Session, err error) {
|
||||||
|
session, tokenID, err := q.sessionByID(ctx, shouldTriggerBulk, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if sessionToken == "" {
|
||||||
|
if err := sessionCheckPermission(ctx, session.ResourceOwner, session.Creator, permissionCheck); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return session, nil
|
||||||
|
}
|
||||||
|
if err := q.sessionTokenVerifier(ctx, sessionToken, session.ID, tokenID); err != nil {
|
||||||
|
return nil, zerrors.ThrowPermissionDenied(nil, "QUERY-dsfr3", "Errors.PermissionDenied")
|
||||||
|
}
|
||||||
|
return session, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) sessionByID(ctx context.Context, shouldTriggerBulk bool, id string) (session *Session, tokenID string, err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
@ -214,27 +250,31 @@ func (q *Queries) SessionByID(ctx context.Context, shouldTriggerBulk bool, id, s
|
|||||||
},
|
},
|
||||||
).ToSql()
|
).ToSql()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, zerrors.ThrowInternal(err, "QUERY-dn9JW", "Errors.Query.SQLStatement")
|
return nil, "", zerrors.ThrowInternal(err, "QUERY-dn9JW", "Errors.Query.SQLStatement")
|
||||||
}
|
}
|
||||||
|
|
||||||
var tokenID string
|
|
||||||
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
|
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
|
||||||
session, tokenID, err = scan(row)
|
session, tokenID, err = scan(row)
|
||||||
return err
|
return err
|
||||||
}, stmt, args...)
|
}, stmt, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
if sessionToken == "" {
|
return session, tokenID, nil
|
||||||
return session, nil
|
|
||||||
}
|
|
||||||
if err := q.sessionTokenVerifier(ctx, sessionToken, session.ID, tokenID); err != nil {
|
|
||||||
return nil, zerrors.ThrowPermissionDenied(nil, "QUERY-dsfr3", "Errors.PermissionDenied")
|
|
||||||
}
|
|
||||||
return session, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) SearchSessions(ctx context.Context, queries *SessionsSearchQueries) (sessions *Sessions, err error) {
|
func (q *Queries) SearchSessions(ctx context.Context, queries *SessionsSearchQueries, permissionCheck domain.PermissionCheck) (*Sessions, error) {
|
||||||
|
sessions, err := q.searchSessions(ctx, queries)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if permissionCheck != nil {
|
||||||
|
sessionsCheckPermission(ctx, sessions, permissionCheck)
|
||||||
|
}
|
||||||
|
return sessions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) searchSessions(ctx context.Context, queries *SessionsSearchQueries) (sessions *Sessions, err error) {
|
||||||
ctx, span := tracing.NewSpan(ctx)
|
ctx, span := tracing.NewSpan(ctx)
|
||||||
defer func() { span.EndWithError(err) }()
|
defer func() { span.EndWithError(err) }()
|
||||||
|
|
||||||
@ -272,6 +312,10 @@ func NewSessionCreatorSearchQuery(creator string) (SearchQuery, error) {
|
|||||||
return NewTextQuery(SessionColumnCreator, creator, TextEquals)
|
return NewTextQuery(SessionColumnCreator, creator, TextEquals)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewSessionUserAgentFingerprintIDSearchQuery(fingerprintID string) (SearchQuery, error) {
|
||||||
|
return NewTextQuery(SessionColumnUserAgentFingerprintID, fingerprintID, TextEquals)
|
||||||
|
}
|
||||||
|
|
||||||
func NewUserIDSearchQuery(id string) (SearchQuery, error) {
|
func NewUserIDSearchQuery(id string) (SearchQuery, error) {
|
||||||
return NewTextQuery(SessionColumnUserID, id, TextEquals)
|
return NewTextQuery(SessionColumnUserID, id, TextEquals)
|
||||||
}
|
}
|
||||||
|
@ -136,6 +136,8 @@ message SearchQuery {
|
|||||||
IDsQuery ids_query = 1;
|
IDsQuery ids_query = 1;
|
||||||
UserIDQuery user_id_query = 2;
|
UserIDQuery user_id_query = 2;
|
||||||
CreationDateQuery creation_date_query = 3;
|
CreationDateQuery creation_date_query = 3;
|
||||||
|
OwnCreatorQuery own_creator_query = 4;
|
||||||
|
OwnUserAgentQuery own_useragent_query = 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,6 +159,10 @@ message CreationDateQuery {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message OwnCreatorQuery {}
|
||||||
|
|
||||||
|
message OwnUserAgentQuery {}
|
||||||
|
|
||||||
message UserAgent {
|
message UserAgent {
|
||||||
optional string fingerprint_id = 1;
|
optional string fingerprint_id = 1;
|
||||||
optional string ip = 2;
|
optional string ip = 2;
|
||||||
@ -169,7 +175,7 @@ message UserAgent {
|
|||||||
message HeaderValues {
|
message HeaderValues {
|
||||||
repeated string values = 1;
|
repeated string values = 1;
|
||||||
}
|
}
|
||||||
map<string,HeaderValues> header = 4;
|
map<string, HeaderValues> header = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SessionFieldName {
|
enum SessionFieldName {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user