merge main into next

This commit is contained in:
adlerhurst
2023-10-19 12:34:00 +02:00
parent b5564572bc
commit bd23a7a56f
107 changed files with 1321 additions and 554 deletions

View File

@@ -3,7 +3,7 @@ package management
import (
"context"
"github.com/zitadel/oidc/v2/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/oidc"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/http"

View File

@@ -4,7 +4,7 @@ import (
"context"
"github.com/zitadel/logging"
"github.com/zitadel/oidc/v2/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/oidc"
"golang.org/x/text/language"
"google.golang.org/protobuf/types/known/durationpb"
@@ -647,6 +647,26 @@ func (s *Server) RemoveHumanAuthFactorU2F(ctx context.Context, req *mgmt_pb.Remo
}, nil
}
func (s *Server) RemoveHumanAuthFactorOTPSMS(ctx context.Context, req *mgmt_pb.RemoveHumanAuthFactorOTPSMSRequest) (*mgmt_pb.RemoveHumanAuthFactorOTPSMSResponse, error) {
objectDetails, err := s.command.RemoveHumanOTPSMS(ctx, req.UserId, authz.GetCtxData(ctx).OrgID)
if err != nil {
return nil, err
}
return &mgmt_pb.RemoveHumanAuthFactorOTPSMSResponse{
Details: obj_grpc.DomainToChangeDetailsPb(objectDetails),
}, nil
}
func (s *Server) RemoveHumanAuthFactorOTPEmail(ctx context.Context, req *mgmt_pb.RemoveHumanAuthFactorOTPEmailRequest) (*mgmt_pb.RemoveHumanAuthFactorOTPEmailResponse, error) {
objectDetails, err := s.command.RemoveHumanOTPEmail(ctx, req.UserId, authz.GetCtxData(ctx).OrgID)
if err != nil {
return nil, err
}
return &mgmt_pb.RemoveHumanAuthFactorOTPEmailResponse{
Details: obj_grpc.DomainToChangeDetailsPb(objectDetails),
}, nil
}
func (s *Server) ListHumanPasswordless(ctx context.Context, req *mgmt_pb.ListHumanPasswordlessRequest) (*mgmt_pb.ListHumanPasswordlessResponse, error) {
query := new(query.UserAuthMethodSearchQueries)
err := query.AppendUserIDQuery(req.UserId)

View File

@@ -4,7 +4,7 @@ import (
"context"
"github.com/zitadel/logging"
"github.com/zitadel/oidc/v2/pkg/op"
"github.com/zitadel/oidc/v3/pkg/op"
"google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/timestamppb"

View File

@@ -54,7 +54,7 @@ func TestServer_GetAuthRequest(t *testing.T) {
require.NoError(t, err)
client, err := Tester.CreateOIDCNativeClient(CTX, redirectURI, logoutRedirectURI, project.GetId())
require.NoError(t, err)
authRequestID, err := Tester.CreateOIDCAuthRequest(client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI)
authRequestID, err := Tester.CreateOIDCAuthRequest(CTX, client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI)
require.NoError(t, err)
now := time.Now()
@@ -134,7 +134,7 @@ func TestServer_CreateCallback(t *testing.T) {
name: "session not found",
req: &oidc_pb.CreateCallbackRequest{
AuthRequestId: func() string {
authRequestID, err := Tester.CreateOIDCAuthRequest(client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI)
authRequestID, err := Tester.CreateOIDCAuthRequest(CTX, client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI)
require.NoError(t, err)
return authRequestID
}(),
@@ -151,7 +151,7 @@ func TestServer_CreateCallback(t *testing.T) {
name: "session token invalid",
req: &oidc_pb.CreateCallbackRequest{
AuthRequestId: func() string {
authRequestID, err := Tester.CreateOIDCAuthRequest(client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI)
authRequestID, err := Tester.CreateOIDCAuthRequest(CTX, client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI)
require.NoError(t, err)
return authRequestID
}(),
@@ -168,7 +168,7 @@ func TestServer_CreateCallback(t *testing.T) {
name: "fail callback",
req: &oidc_pb.CreateCallbackRequest{
AuthRequestId: func() string {
authRequestID, err := Tester.CreateOIDCAuthRequest(client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI)
authRequestID, err := Tester.CreateOIDCAuthRequest(CTX, client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI)
require.NoError(t, err)
return authRequestID
}(),
@@ -192,7 +192,7 @@ func TestServer_CreateCallback(t *testing.T) {
name: "code callback",
req: &oidc_pb.CreateCallbackRequest{
AuthRequestId: func() string {
authRequestID, err := Tester.CreateOIDCAuthRequest(client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI)
authRequestID, err := Tester.CreateOIDCAuthRequest(CTX, client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURI)
require.NoError(t, err)
return authRequestID
}(),
@@ -217,7 +217,7 @@ func TestServer_CreateCallback(t *testing.T) {
AuthRequestId: func() string {
client, err := Tester.CreateOIDCImplicitFlowClient(CTX, redirectURIImplicit)
require.NoError(t, err)
authRequestID, err := Tester.CreateOIDCAuthRequestImplicit(client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURIImplicit)
authRequestID, err := Tester.CreateOIDCAuthRequestImplicit(CTX, client.GetClientId(), Tester.Users[integration.FirstInstanceUsersKey][integration.OrgOwner].ID, redirectURIImplicit)
require.NoError(t, err)
return authRequestID
}(),

View File

@@ -1,7 +1,7 @@
package oidc
import (
"github.com/zitadel/oidc/v2/pkg/op"
"github.com/zitadel/oidc/v3/pkg/op"
"google.golang.org/grpc"
"github.com/zitadel/zitadel/internal/api/authz"

View File

@@ -33,12 +33,7 @@ func authorize(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
return nil, status.Error(codes.Unauthenticated, "auth header missing")
}
var orgDomain string
orgID := grpc_util.GetHeader(authCtx, http.ZitadelOrgID)
if o, ok := req.(OrganisationFromRequest); ok {
orgID = o.OrganisationFromRequest().ID
orgDomain = o.OrganisationFromRequest().Domain
}
orgID, orgDomain := orgIDAndDomainFromRequest(authCtx, req)
ctxSetter, err := authz.CheckUserAuthorization(authCtx, req, authToken, orgID, orgDomain, verifier, authConfig, authOpt, info.FullMethod)
if err != nil {
return nil, err
@@ -47,11 +42,38 @@ func authorize(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo,
return handler(ctxSetter(ctx), req)
}
type OrganisationFromRequest interface {
OrganisationFromRequest() *Organisation
func orgIDAndDomainFromRequest(ctx context.Context, req interface{}) (id, domain string) {
orgID := grpc_util.GetHeader(ctx, http.ZitadelOrgID)
o, ok := req.(OrganizationFromRequest)
if !ok {
return orgID, ""
}
id = o.OrganizationFromRequest().ID
domain = o.OrganizationFromRequest().Domain
if id != "" || domain != "" {
return id, domain
}
// check if the deprecated organisation is used.
// to be removed before going GA (https://github.com/zitadel/zitadel/issues/6718)
id = o.OrganisationFromRequest().ID
domain = o.OrganisationFromRequest().Domain
if id != "" || domain != "" {
return id, domain
}
return orgID, domain
}
type Organisation struct {
// Deprecated: will be removed in favor of OrganizationFromRequest (https://github.com/zitadel/zitadel/issues/6718)
type OrganisationFromRequest interface {
OrganisationFromRequest() *Organization
}
type Organization struct {
ID string
Domain string
}
type OrganizationFromRequest interface {
OrganizationFromRequest() *Organization
OrganisationFromRequest
}

View File

@@ -2,10 +2,13 @@ package session
import (
"context"
"net"
"net/http"
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/muhlemmer/gu"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/object/v2"
"github.com/zitadel/zitadel/internal/command"
@@ -41,7 +44,7 @@ func (s *Server) ListSessions(ctx context.Context, req *session.ListSessionsRequ
}
func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRequest) (*session.CreateSessionResponse, error) {
checks, metadata, err := s.createSessionRequestToCommand(ctx, req)
checks, metadata, userAgent, err := s.createSessionRequestToCommand(ctx, req)
if err != nil {
return nil, err
}
@@ -50,7 +53,7 @@ func (s *Server) CreateSession(ctx context.Context, req *session.CreateSessionRe
return nil, err
}
set, err := s.command.CreateSession(ctx, cmds, metadata)
set, err := s.command.CreateSession(ctx, cmds, metadata, userAgent)
if err != nil {
return nil, err
}
@@ -113,9 +116,34 @@ func sessionToPb(s *query.Session) *session.Session {
Sequence: s.Sequence,
Factors: factorsToPb(s),
Metadata: s.Metadata,
UserAgent: userAgentToPb(s.UserAgent),
}
}
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 factorsToPb(s *query.Session) *session.Factors {
user := userFactorToPb(s.UserFactor)
if user == nil {
@@ -188,6 +216,7 @@ func userFactorToPb(factor query.SessionUserFactor) *session.UserFactor {
LoginName: factor.LoginName,
DisplayName: factor.DisplayName,
OrganisationId: factor.ResourceOwner,
OrganizationId: factor.ResourceOwner,
}
}
@@ -236,12 +265,30 @@ func idsQueryToQuery(q *session.IDsQuery) (query.SearchQuery, error) {
return query.NewSessionIDsSearchQuery(q.Ids)
}
func (s *Server) createSessionRequestToCommand(ctx context.Context, req *session.CreateSessionRequest) ([]command.SessionCommand, map[string][]byte, error) {
func (s *Server) createSessionRequestToCommand(ctx context.Context, req *session.CreateSessionRequest) ([]command.SessionCommand, map[string][]byte, *domain.UserAgent, error) {
checks, err := s.checksToCommand(ctx, req.Checks)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
return checks, req.GetMetadata(), nil
return checks, req.GetMetadata(), userAgentToCommand(req.GetUserAgent()), nil
}
func userAgentToCommand(userAgent *session.UserAgent) *domain.UserAgent {
if userAgent == nil {
return nil
}
out := &domain.UserAgent{
FingerprintID: userAgent.FingerprintId,
IP: net.ParseIP(userAgent.GetIp()),
Description: userAgent.Description,
}
if len(userAgent.Header) > 0 {
out.Header = make(http.Header, len(userAgent.Header))
for k, values := range userAgent.Header {
out.Header[k] = values.GetValues()
}
}
return out
}
func (s *Server) setSessionRequestToCommand(ctx context.Context, req *session.SetSessionRequest) ([]command.SessionCommand, error) {

View File

@@ -14,6 +14,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/metadata"
"google.golang.org/protobuf/proto"
"github.com/zitadel/zitadel/internal/integration"
object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
@@ -53,7 +54,7 @@ func TestMain(m *testing.M) {
}())
}
func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, window time.Duration, metadata map[string][]byte, factors ...wantFactor) *session.Session {
func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, window time.Duration, metadata map[string][]byte, userAgent *session.UserAgent, factors ...wantFactor) *session.Session {
t.Helper()
require.NotEmpty(t, id)
require.NotEmpty(t, token)
@@ -70,6 +71,11 @@ func verifyCurrentSession(t testing.TB, id, token string, sequence uint64, windo
assert.WithinRange(t, s.GetChangeDate().AsTime(), time.Now().Add(-window), time.Now().Add(window))
assert.Equal(t, sequence, s.GetSequence())
assert.Equal(t, metadata, s.GetMetadata())
if !proto.Equal(userAgent, s.GetUserAgent()) {
t.Errorf("user agent =\n%v\nwant\n%v", s.GetUserAgent(), userAgent)
}
verifyFactors(t, s.GetFactors(), window, factors)
return s
}
@@ -131,11 +137,12 @@ func verifyFactors(t testing.TB, factors *session.Factors, window time.Duration,
func TestServer_CreateSession(t *testing.T) {
tests := []struct {
name string
req *session.CreateSessionRequest
want *session.CreateSessionResponse
wantErr bool
wantFactors []wantFactor
name string
req *session.CreateSessionRequest
want *session.CreateSessionResponse
wantErr bool
wantFactors []wantFactor
wantUserAgent *session.UserAgent
}{
{
name: "empty session",
@@ -148,6 +155,33 @@ func TestServer_CreateSession(t *testing.T) {
},
},
},
{
name: "user agent",
req: &session.CreateSessionRequest{
Metadata: map[string][]byte{"foo": []byte("bar")},
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"}},
},
},
},
want: &session.CreateSessionResponse{
Details: &object.Details{
ResourceOwner: Tester.Organisation.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: "with user",
req: &session.CreateSessionRequest{
@@ -219,7 +253,7 @@ func TestServer_CreateSession(t *testing.T) {
require.NoError(t, err)
integration.AssertDetails(t, tt.want, got)
verifyCurrentSession(t, got.GetSessionId(), got.GetSessionToken(), got.GetDetails().GetSequence(), time.Minute, tt.req.GetMetadata(), tt.wantFactors...)
verifyCurrentSession(t, got.GetSessionId(), got.GetSessionToken(), got.GetDetails().GetSequence(), time.Minute, tt.req.GetMetadata(), tt.wantUserAgent, tt.wantFactors...)
})
}
}
@@ -242,7 +276,7 @@ func TestServer_CreateSession_webauthn(t *testing.T) {
},
})
require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil)
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
assertionData, err := Tester.WebAuthN.CreateAssertionResponse(createResp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), true)
require.NoError(t, err)
@@ -258,7 +292,7 @@ func TestServer_CreateSession_webauthn(t *testing.T) {
},
})
require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantWebAuthNFactorUserVerified)
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactorUserVerified)
}
func TestServer_CreateSession_successfulIntent(t *testing.T) {
@@ -274,7 +308,7 @@ func TestServer_CreateSession_successfulIntent(t *testing.T) {
},
})
require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil)
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
intentID, token, _, _ := Tester.CreateSuccessfulOAuthIntent(t, idpID, User.GetUserId(), "id")
updateResp, err := Client.SetSession(CTX, &session.SetSessionRequest{
@@ -288,7 +322,7 @@ func TestServer_CreateSession_successfulIntent(t *testing.T) {
},
})
require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantIntentFactor)
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantIntentFactor)
}
func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
@@ -304,7 +338,7 @@ func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
},
})
require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil)
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
idpUserID := "id"
intentID, token, _, _ := Tester.CreateSuccessfulOAuthIntent(t, idpID, "", idpUserID)
@@ -331,7 +365,7 @@ func TestServer_CreateSession_successfulIntentUnknownUserID(t *testing.T) {
},
})
require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantIntentFactor)
verifyCurrentSession(t, createResp.GetSessionId(), updateResp.GetSessionToken(), updateResp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantIntentFactor)
}
func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) {
@@ -347,7 +381,7 @@ func TestServer_CreateSession_startedIntentFalseToken(t *testing.T) {
},
})
require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil)
verifyCurrentSession(t, createResp.GetSessionId(), createResp.GetSessionToken(), createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
intentID := Tester.CreateIntent(t, idpID)
_, err = Client.SetSession(CTX, &session.SetSessionRequest{
@@ -399,7 +433,7 @@ func TestServer_SetSession_flow(t *testing.T) {
createResp, err := Client.CreateSession(CTX, &session.CreateSessionRequest{})
require.NoError(t, err)
sessionToken := createResp.GetSessionToken()
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, createResp.GetDetails().GetSequence(), time.Minute, nil)
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, createResp.GetDetails().GetSequence(), time.Minute, nil, nil)
t.Run("check user", func(t *testing.T) {
resp, err := Client.SetSession(CTX, &session.SetSessionRequest{
@@ -415,7 +449,7 @@ func TestServer_SetSession_flow(t *testing.T) {
})
require.NoError(t, err)
sessionToken = resp.GetSessionToken()
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor)
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor)
})
t.Run("check webauthn, user verified (passkey)", func(t *testing.T) {
@@ -430,7 +464,7 @@ func TestServer_SetSession_flow(t *testing.T) {
},
})
require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil)
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil)
sessionToken = resp.GetSessionToken()
assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), true)
@@ -447,7 +481,7 @@ func TestServer_SetSession_flow(t *testing.T) {
})
require.NoError(t, err)
sessionToken = resp.GetSessionToken()
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantWebAuthNFactorUserVerified)
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactorUserVerified)
})
userAuthCtx := Tester.WithAuthorizationToken(CTX, sessionToken)
@@ -474,7 +508,7 @@ func TestServer_SetSession_flow(t *testing.T) {
},
})
require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil)
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil)
sessionToken = resp.GetSessionToken()
assertionData, err := Tester.WebAuthN.CreateAssertionResponse(resp.GetChallenges().GetWebAuthN().GetPublicKeyCredentialRequestOptions(), false)
@@ -491,7 +525,7 @@ func TestServer_SetSession_flow(t *testing.T) {
})
require.NoError(t, err)
sessionToken = resp.GetSessionToken()
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantWebAuthNFactor)
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactor)
})
}
})
@@ -510,7 +544,7 @@ func TestServer_SetSession_flow(t *testing.T) {
})
require.NoError(t, err)
sessionToken = resp.GetSessionToken()
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantWebAuthNFactor, wantTOTPFactor)
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactor, wantTOTPFactor)
})
t.Run("check OTP SMS", func(t *testing.T) {
@@ -522,7 +556,7 @@ func TestServer_SetSession_flow(t *testing.T) {
},
})
require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil)
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil)
sessionToken = resp.GetSessionToken()
otp := resp.GetChallenges().GetOtpSms()
@@ -539,7 +573,7 @@ func TestServer_SetSession_flow(t *testing.T) {
})
require.NoError(t, err)
sessionToken = resp.GetSessionToken()
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantWebAuthNFactor, wantOTPSMSFactor)
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactor, wantOTPSMSFactor)
})
t.Run("check OTP Email", func(t *testing.T) {
@@ -553,7 +587,7 @@ func TestServer_SetSession_flow(t *testing.T) {
},
})
require.NoError(t, err)
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil)
verifyCurrentSession(t, createResp.GetSessionId(), resp.GetSessionToken(), resp.GetDetails().GetSequence(), time.Minute, nil, nil)
sessionToken = resp.GetSessionToken()
otp := resp.GetChallenges().GetOtpEmail()
@@ -570,7 +604,7 @@ func TestServer_SetSession_flow(t *testing.T) {
})
require.NoError(t, err)
sessionToken = resp.GetSessionToken()
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, wantUserFactor, wantWebAuthNFactor, wantOTPEmailFactor)
verifyCurrentSession(t, createResp.GetSessionId(), sessionToken, resp.GetDetails().GetSequence(), time.Minute, nil, nil, wantUserFactor, wantWebAuthNFactor, wantOTPEmailFactor)
})
}

View File

@@ -2,15 +2,19 @@ package session
import (
"context"
"net"
"net/http"
"testing"
"time"
"github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/domain"
caos_errs "github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/query"
@@ -23,7 +27,7 @@ func Test_sessionsToPb(t *testing.T) {
past := now.Add(-time.Hour)
sessions := []*query.Session{
{ // no factor
{ // no factor, with user agent
ID: "999",
CreationDate: now,
ChangeDate: now,
@@ -32,6 +36,12 @@ func Test_sessionsToPb(t *testing.T) {
ResourceOwner: "me",
Creator: "he",
Metadata: map[string][]byte{"hello": []byte("world")},
UserAgent: domain.UserAgent{
FingerprintID: gu.Ptr("fingerprintID"),
Description: gu.Ptr("description"),
IP: net.IPv4(1, 2, 3, 4),
Header: http.Header{"foo": []string{"foo", "bar"}},
},
},
{ // user factor
ID: "999",
@@ -114,13 +124,21 @@ func Test_sessionsToPb(t *testing.T) {
}
want := []*session.Session{
{ // no factor
{ // no factor, with user agent
Id: "999",
CreationDate: timestamppb.New(now),
ChangeDate: timestamppb.New(now),
Sequence: 123,
Factors: nil,
Metadata: map[string][]byte{"hello": []byte("world")},
UserAgent: &session.UserAgent{
FingerprintId: gu.Ptr("fingerprintID"),
Description: gu.Ptr("description"),
Ip: gu.Ptr("1.2.3.4"),
Header: map[string]*session.UserAgent_HeaderValues{
"foo": {Values: []string{"foo", "bar"}},
},
},
},
{ // user factor
Id: "999",
@@ -134,6 +152,7 @@ func Test_sessionsToPb(t *testing.T) {
LoginName: "donald",
DisplayName: "donald duck",
OrganisationId: "org1",
OrganizationId: "org1",
},
},
Metadata: map[string][]byte{"hello": []byte("world")},
@@ -150,6 +169,7 @@ func Test_sessionsToPb(t *testing.T) {
LoginName: "donald",
DisplayName: "donald duck",
OrganisationId: "org1",
OrganizationId: "org1",
},
Password: &session.PasswordFactor{
VerifiedAt: timestamppb.New(past),
@@ -169,6 +189,7 @@ func Test_sessionsToPb(t *testing.T) {
LoginName: "donald",
DisplayName: "donald duck",
OrganisationId: "org1",
OrganizationId: "org1",
},
WebAuthN: &session.WebAuthNFactor{
VerifiedAt: timestamppb.New(past),
@@ -189,6 +210,7 @@ func Test_sessionsToPb(t *testing.T) {
LoginName: "donald",
DisplayName: "donald duck",
OrganisationId: "org1",
OrganizationId: "org1",
},
Totp: &session.TOTPFactor{
VerifiedAt: timestamppb.New(past),
@@ -208,6 +230,71 @@ func Test_sessionsToPb(t *testing.T) {
}
}
func Test_userAgentToPb(t *testing.T) {
type args struct {
ua domain.UserAgent
}
tests := []struct {
name string
args args
want *session.UserAgent
}{
{
name: "empty",
args: args{domain.UserAgent{}},
},
{
name: "fingerprint id and description",
args: args{domain.UserAgent{
FingerprintID: gu.Ptr("fingerPrintID"),
Description: gu.Ptr("description"),
}},
want: &session.UserAgent{
FingerprintId: gu.Ptr("fingerPrintID"),
Description: gu.Ptr("description"),
},
},
{
name: "with ip",
args: args{domain.UserAgent{
FingerprintID: gu.Ptr("fingerPrintID"),
Description: gu.Ptr("description"),
IP: net.IPv4(1, 2, 3, 4),
}},
want: &session.UserAgent{
FingerprintId: gu.Ptr("fingerPrintID"),
Description: gu.Ptr("description"),
Ip: gu.Ptr("1.2.3.4"),
},
},
{
name: "with header",
args: args{domain.UserAgent{
FingerprintID: gu.Ptr("fingerPrintID"),
Description: gu.Ptr("description"),
Header: http.Header{
"foo": []string{"foo", "bar"},
"hello": []string{"world"},
},
}},
want: &session.UserAgent{
FingerprintId: gu.Ptr("fingerPrintID"),
Description: gu.Ptr("description"),
Header: map[string]*session.UserAgent_HeaderValues{
"foo": {Values: []string{"foo", "bar"}},
"hello": {Values: []string{"world"}},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := userAgentToPb(tt.args.ua)
assert.Equal(t, tt.want, got)
})
}
}
func mustNewTextQuery(t testing.TB, column query.Column, value string, compare query.TextComparison) query.SearchQuery {
q, err := query.NewTextQuery(column, value, compare)
require.NoError(t, err)
@@ -510,3 +597,73 @@ func Test_userVerificationRequirementToDomain(t *testing.T) {
})
}
}
func Test_userAgentToCommand(t *testing.T) {
type args struct {
userAgent *session.UserAgent
}
tests := []struct {
name string
args args
want *domain.UserAgent
}{
{
name: "nil",
args: args{nil},
want: nil,
},
{
name: "all fields",
args: args{&session.UserAgent{
FingerprintId: gu.Ptr("fp1"),
Ip: gu.Ptr("1.2.3.4"),
Description: gu.Ptr("firefox"),
Header: map[string]*session.UserAgent_HeaderValues{
"hello": {
Values: []string{"foo", "bar"},
},
},
}},
want: &domain.UserAgent{
FingerprintID: gu.Ptr("fp1"),
IP: net.ParseIP("1.2.3.4"),
Description: gu.Ptr("firefox"),
Header: http.Header{
"hello": []string{"foo", "bar"},
},
},
},
{
name: "invalid ip",
args: args{&session.UserAgent{
FingerprintId: gu.Ptr("fp1"),
Ip: gu.Ptr("oops"),
Description: gu.Ptr("firefox"),
Header: map[string]*session.UserAgent_HeaderValues{
"hello": {
Values: []string{"foo", "bar"},
},
},
}},
want: &domain.UserAgent{
FingerprintID: gu.Ptr("fp1"),
IP: nil,
Description: gu.Ptr("firefox"),
Header: http.Header{
"hello": []string{"foo", "bar"},
},
},
},
{
name: "nil fields",
args: args{&session.UserAgent{}},
want: &domain.UserAgent{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := userAgentToCommand(tt.args.userAgent)
assert.Equal(t, tt.want, got)
})
}
}

View File

@@ -3,7 +3,7 @@ package system
import (
"strings"
"github.com/zitadel/oidc/v2/pkg/oidc"
"github.com/zitadel/oidc/v3/pkg/oidc"
"golang.org/x/text/language"
"github.com/zitadel/zitadel/internal/api/grpc/authn"