diff --git a/controller/env/appenv.go b/controller/env/appenv.go index 90e7122a2..13217e56b 100644 --- a/controller/env/appenv.go +++ b/controller/env/appenv.go @@ -34,6 +34,7 @@ import ( clientOperations "github.com/openziti/edge-api/rest_client_api_server/operations" managementServer "github.com/openziti/edge-api/rest_management_api_server" managementOperations "github.com/openziti/edge-api/rest_management_api_server/operations" + "github.com/openziti/edge-api/rest_model" edgeConfig "github.com/openziti/edge/controller/config" "github.com/openziti/edge/controller/internal/permissions" "github.com/openziti/edge/controller/model" @@ -48,10 +49,10 @@ import ( "github.com/openziti/fabric/controller/xctrl" "github.com/openziti/fabric/controller/xmgmt" "github.com/openziti/foundation/v2/errorz" + "github.com/openziti/foundation/v2/stringz" "github.com/openziti/identity" "github.com/openziti/metrics" - "github.com/openziti/sdk-golang/ziti/config" - "github.com/openziti/sdk-golang/ziti/constants" + "github.com/openziti/sdk-golang/ziti" "github.com/openziti/storage/boltz" "github.com/openziti/xweb/v2" cmap "github.com/orcaman/concurrent-map/v2" @@ -64,12 +65,14 @@ import ( var _ model.Env = &AppEnv{} +const ZitiSession = "zt-session" + type AppEnv struct { BoltStores *persistence.Stores Managers *model.Managers Config *edgeConfig.Config - Versions *config.Versions + Versions *ziti.Versions ApiServerCsrSigner cert.Signer ApiClientCsrSigner cert.Signer @@ -299,18 +302,9 @@ func (ae *AppEnv) FillRequestContext(rc *response.RequestContext) error { return err } - totpRequired := rc.ApiSession.MfaRequired || rc.AuthPolicy.Secondary.RequireTotp + ProcessAuthQueries(ae, rc) - isPartialAuth := false - if totpRequired && !rc.ApiSession.MfaComplete { - isPartialAuth = true - } - - if rc.AuthPolicy.Secondary.RequiredExtJwtSigner != nil { - if !processSecondaryJwtSigner(ae, rc) { - isPartialAuth = true - } - } + isPartialAuth := len(rc.AuthQueries) > 0 if isPartialAuth { rc.ActivePermissions = append(rc.ActivePermissions, permissions.PartiallyAuthenticatePermission) @@ -322,28 +316,61 @@ func (ae *AppEnv) FillRequestContext(rc *response.RequestContext) error { rc.ActivePermissions = append(rc.ActivePermissions, permissions.AdminPermission) } } + return nil } -func processSecondaryJwtSigner(ae *AppEnv, rc *response.RequestContext) bool { +func NewAuthQueryZitiMfa() *rest_model.AuthQueryDetail { + provider := rest_model.MfaProvidersZiti + return &rest_model.AuthQueryDetail{ + TypeID: "MFA", + Format: rest_model.MfaFormatsAlphaNumeric, + HTTPMethod: http.MethodPost, + HTTPURL: "./authenticate/mfa", + MaxLength: model.TotpMaxLength, + MinLength: model.TotpMinLength, + Provider: &provider, + } +} + +func NewAuthQueryExtJwt(url string) *rest_model.AuthQueryDetail { + return &rest_model.AuthQueryDetail{ + HTTPURL: url, + TypeID: "EXT-JWT", + } +} + +// ProcessAuthQueries will inspect a response.RequestContext and set the AuthQueries +// with the current outstanding authentication queries. +func ProcessAuthQueries(ae *AppEnv, rc *response.RequestContext) { + if rc.ApiSession == nil || rc.AuthPolicy == nil { + return + } + + totpRequired := rc.ApiSession.MfaRequired || rc.AuthPolicy.Secondary.RequireTotp + + if totpRequired && !rc.ApiSession.MfaComplete { + rc.AuthQueries = append(rc.AuthQueries, NewAuthQueryZitiMfa()) + } + if rc.AuthPolicy.Secondary.RequiredExtJwtSigner != nil { - rc.AuthStatus.SecondaryExtJwtSignerId = *rc.AuthPolicy.Secondary.RequiredExtJwtSigner extJwtAuthVal := ae.GetAuthRegistry().GetByMethod(model.AuthMethodExtJwt) extJwtAuth := extJwtAuthVal.(*model.AuthModuleExtJwt) if extJwtAuth != nil { authResult, err := extJwtAuth.ProcessSecondary(model.NewAuthContextHttp(rc.Request, model.AuthMethodExtJwt, nil, rc.NewChangeContext())) - if err != nil { - return false + if err != nil || !authResult.IsSuccessful() { + signer, err := ae.Managers.ExternalJwtSigner.Read(*rc.AuthPolicy.Secondary.RequiredExtJwtSigner) + authUrl := "" + if err == nil { + authUrl = stringz.OrEmpty(signer.ExternalAuthUrl) + } + + rc.AuthQueries = append(rc.AuthQueries, NewAuthQueryExtJwt(authUrl)) + } - - return authResult.IsSuccessful() } - - return false } - - return true } func NewAppEnv(c *edgeConfig.Config, host HostController) *AppEnv { @@ -365,7 +392,7 @@ func NewAppEnv(c *edgeConfig.Config, host HostController) *AppEnv { ae := &AppEnv{ Config: c, - Versions: &config.Versions{ + Versions: &ziti.Versions{ Api: "1.0.0", EnrollmentApi: "1.0.0", }, @@ -499,7 +526,7 @@ func getJwtSigningMethod(cert *tls.Certificate) jwt.SigningMethod { } func (ae *AppEnv) GetSessionTokenFromRequest(r *http.Request) string { - return r.Header.Get(constants.ZitiSession) + return r.Header.Get(ZitiSession) } func (ae *AppEnv) CreateRequestContext(rw http.ResponseWriter, r *http.Request) *response.RequestContext { diff --git a/controller/internal/routes/api_session_api_model.go b/controller/internal/routes/api_session_api_model.go index 6e0ce7fa2..c955e3669 100644 --- a/controller/internal/routes/api_session_api_model.go +++ b/controller/internal/routes/api_session_api_model.go @@ -24,7 +24,6 @@ import ( "github.com/openziti/edge/controller/response" "github.com/openziti/fabric/controller/models" "github.com/openziti/foundation/v2/stringz" - "net/http" "path" ) @@ -61,11 +60,6 @@ func MapApiSessionToRestInterface(ae *env.AppEnv, _ *response.RequestContext, ap } func MapApiSessionToRestModel(ae *env.AppEnv, apiSession *model.ApiSession) (*rest_model.APISessionDetail, error) { - authQueries := rest_model.AuthQueryList{} - - if apiSession.MfaRequired && !apiSession.MfaComplete { - authQueries = append(authQueries, newAuthCheckZitiMfa()) - } lastActivityAt := strfmt.DateTime(apiSession.LastActivityAt) @@ -76,7 +70,7 @@ func MapApiSessionToRestModel(ae *env.AppEnv, apiSession *model.ApiSession) (*re Token: &apiSession.Token, IPAddress: &apiSession.IPAddress, ConfigTypes: stringz.SetToSlice(apiSession.ConfigTypes), - AuthQueries: authQueries, + AuthQueries: rest_model.AuthQueryList{}, //not in a request context, can't fill IsMfaComplete: &apiSession.MfaComplete, IsMfaRequired: &apiSession.MfaRequired, LastActivityAt: lastActivityAt, @@ -96,16 +90,3 @@ func MapApiSessionToRestModel(ae *env.AppEnv, apiSession *model.ApiSession) (*re return ret, nil } - -func newAuthCheckZitiMfa() *rest_model.AuthQueryDetail { - provider := rest_model.MfaProvidersZiti - return &rest_model.AuthQueryDetail{ - TypeID: "MFA", - Format: rest_model.MfaFormatsAlphaNumeric, - HTTPMethod: http.MethodPost, - HTTPURL: "./authenticate/mfa", - MaxLength: model.TotpMaxLength, - MinLength: model.TotpMinLength, - Provider: &provider, - } -} diff --git a/controller/internal/routes/authenticate_router.go b/controller/internal/routes/authenticate_router.go index ccc476b1b..558911404 100644 --- a/controller/internal/routes/authenticate_router.go +++ b/controller/internal/routes/authenticate_router.go @@ -31,7 +31,6 @@ import ( "github.com/openziti/edge/controller/response" "github.com/openziti/foundation/v2/errorz" "github.com/openziti/metrics" - "github.com/openziti/sdk-golang/ziti/constants" "net" "net/http" "time" @@ -92,6 +91,8 @@ func (ro *AuthRouter) authHandler(ae *env.AppEnv, rc *response.RequestContext, h return } + rc.AuthPolicy = authResult.AuthPolicy() + identity := authResult.Identity() if identity.EnvInfo == nil { identity.EnvInfo = &model.EnvInfo{} @@ -189,15 +190,18 @@ func (ro *AuthRouter) authHandler(ae *env.AppEnv, rc *response.RequestContext, h ae.GetManagers().PostureResponse.SetSdkInfo(identity.Id, sessionId, identity.SdkInfo) - apiSession := MapToCurrentApiSessionRestModel(ae, filledApiSession, ae.Config.SessionTimeoutDuration()) rc.ApiSession = filledApiSession + env.ProcessAuthQueries(ae, rc) + + apiSession := MapToCurrentApiSessionRestModel(ae, rc, ae.Config.SessionTimeoutDuration()) + //re-calc session headers as they were not set when ApiSession == NIL response.AddSessionHeaders(rc) envelope := &rest_model.CurrentAPISessionDetailEnvelope{Data: apiSession, Meta: &rest_model.Meta{}} - rc.ResponseWriter.Header().Set(constants.ZitiSession, filledApiSession.Token) + rc.ResponseWriter.Header().Set(env.ZitiSession, filledApiSession.Token) ro.createTimer.UpdateSince(start) diff --git a/controller/internal/routes/ca_router.go b/controller/internal/routes/ca_router.go index 2d364e192..95e61747e 100644 --- a/controller/internal/routes/ca_router.go +++ b/controller/internal/routes/ca_router.go @@ -30,7 +30,7 @@ import ( "github.com/openziti/edge/controller/model" "github.com/openziti/edge/controller/response" "github.com/openziti/fabric/controller/fields" - "github.com/openziti/sdk-golang/ziti/config" + "github.com/openziti/sdk-golang/ziti" "github.com/openziti/storage/boltz" "github.com/pkg/errors" "net/http" @@ -264,7 +264,7 @@ func (r *CaRouter) generateJwt(ae *env.AppEnv, rc *response.RequestContext) { method := "ca" - claims := &config.EnrollmentClaims{ + claims := &ziti.EnrollmentClaims{ EnrollmentMethod: method, StandardClaims: jwt.StandardClaims{ ExpiresAt: notAfter, @@ -278,7 +278,7 @@ func (r *CaRouter) generateJwt(ae *env.AppEnv, rc *response.RequestContext) { return } - jwt, genErr := ae.GetJwtSigner().Generate(ca.Id, ca.Id, mapClaims) + jwtStr, genErr := ae.GetJwtSigner().Generate(ca.Id, ca.Id, mapClaims) if genErr != nil { rc.RespondWithError(errors.New("could not generate claims")) @@ -287,5 +287,5 @@ func (r *CaRouter) generateJwt(ae *env.AppEnv, rc *response.RequestContext) { rc.ResponseWriter.Header().Set("content-type", "application/jwt") rc.ResponseWriter.WriteHeader(http.StatusOK) - _, _ = rc.ResponseWriter.Write([]byte(jwt)) + _, _ = rc.ResponseWriter.Write([]byte(jwtStr)) } diff --git a/controller/internal/routes/current_api_session_api_model.go b/controller/internal/routes/current_api_session_api_model.go index fa05ceb7d..a1b49b4d8 100644 --- a/controller/internal/routes/current_api_session_api_model.go +++ b/controller/internal/routes/current_api_session_api_model.go @@ -55,9 +55,11 @@ func (factory *CurrentApiSessionLinkFactoryImpl) Links(entity models.Entity) res } } -func MapToCurrentApiSessionRestModel(ae *env.AppEnv, apiSession *model.ApiSession, sessionTimeout time.Duration) *rest_model.CurrentAPISessionDetail { +func MapToCurrentApiSessionRestModel(ae *env.AppEnv, rc *response.RequestContext, sessionTimeout time.Duration) *rest_model.CurrentAPISessionDetail { - detail, err := MapApiSessionToRestModel(ae, apiSession) + detail, err := MapApiSessionToRestModel(ae, rc.ApiSession) + + MapApiSessionAuthQueriesToRestEntity(ae, rc, detail) if err != nil { pfxlog.Logger().Errorf("error could not convert apiSession to rest model: %v", err) @@ -67,7 +69,7 @@ func MapToCurrentApiSessionRestModel(ae *env.AppEnv, apiSession *model.ApiSessio detail = &rest_model.APISessionDetail{} } expiresAt := strfmt.DateTime(time.Time(detail.LastActivityAt).Add(sessionTimeout)) - expirationSeconds := int64(apiSession.ExpirationDuration.Seconds()) + expirationSeconds := int64(rc.ApiSession.ExpirationDuration.Seconds()) ret := &rest_model.CurrentAPISessionDetail{ APISessionDetail: *detail, @@ -78,8 +80,22 @@ func MapToCurrentApiSessionRestModel(ae *env.AppEnv, apiSession *model.ApiSessio return ret } -func MapApiSessionCertificateToRestEntity(appEnv *env.AppEnv, context *response.RequestContext, i *model.ApiSessionCertificate) (interface{}, error) { - return MapApiSessionCertificateToRestModel(i) +func MapApiSessionAuthQueriesToRestEntity(ae *env.AppEnv, rc *response.RequestContext, detail *rest_model.APISessionDetail) { + for _, authQuery := range rc.AuthQueries { + detail.AuthQueries = append(detail.AuthQueries, &rest_model.AuthQueryDetail{ + Format: authQuery.Format, + HTTPMethod: authQuery.HTTPMethod, + HTTPURL: authQuery.HTTPURL, + MaxLength: authQuery.MaxLength, + MinLength: authQuery.MinLength, + Provider: authQuery.Provider, + TypeID: authQuery.TypeID, + }) + } +} + +func MapApiSessionCertificateToRestEntity(appEnv *env.AppEnv, context *response.RequestContext, cert *model.ApiSessionCertificate) (interface{}, error) { + return MapApiSessionCertificateToRestModel(cert) } func MapApiSessionCertificateToRestModel(apiSessionCert *model.ApiSessionCertificate) (*rest_model.CurrentAPISessionCertificateDetail, error) { diff --git a/controller/internal/routes/current_api_session_router.go b/controller/internal/routes/current_api_session_router.go index ff30f4571..df6af6d9c 100644 --- a/controller/internal/routes/current_api_session_router.go +++ b/controller/internal/routes/current_api_session_router.go @@ -25,7 +25,6 @@ import ( "github.com/openziti/edge/controller/env" "github.com/openziti/edge/controller/internal/permissions" "github.com/openziti/edge/controller/response" - "github.com/openziti/foundation/v2/stringz" "net/http" "time" ) @@ -86,23 +85,7 @@ func (router *CurrentSessionRouter) Register(ae *env.AppEnv) { } func (router *CurrentSessionRouter) Detail(ae *env.AppEnv, rc *response.RequestContext) { - apiSession := MapToCurrentApiSessionRestModel(ae, rc.ApiSession, ae.Config.SessionTimeoutDuration()) - - if rc.AuthStatus.SecondaryExtJwtSignerId != "" && !rc.AuthStatus.PassedSecondaryExtJwtSignerId { - extJwtSigner, err := ae.GetManagers().ExternalJwtSigner.Read(rc.AuthStatus.SecondaryExtJwtSignerId) - - if err != nil { - rc.RespondWithError(err) - return - } - - authQuery := &rest_model.AuthQueryDetail{ - TypeID: "EXT-JWT", - HTTPURL: stringz.OrEmpty(extJwtSigner.ExternalAuthUrl), - } - - apiSession.AuthQueries = append(apiSession.AuthQueries, authQuery) - } + apiSession := MapToCurrentApiSessionRestModel(ae, rc, ae.Config.SessionTimeoutDuration()) rc.Respond(rest_model.CurrentAPISessionDetailEnvelope{Data: apiSession, Meta: &rest_model.Meta{}}, http.StatusOK) } diff --git a/controller/internal/routes/current_identity_router.go b/controller/internal/routes/current_identity_router.go index 616ac9832..7f7dca095 100644 --- a/controller/internal/routes/current_identity_router.go +++ b/controller/internal/routes/current_identity_router.go @@ -29,6 +29,7 @@ import ( "github.com/openziti/edge/controller/persistence" "github.com/openziti/edge/controller/response" "github.com/openziti/foundation/v2/errorz" + "github.com/openziti/foundation/v2/stringz" "github.com/openziti/storage/boltz" "github.com/pkg/errors" "net/http" @@ -57,7 +58,7 @@ func (r *CurrentIdentityRouter) Register(ae *env.AppEnv) { ae.ClientApi.CurrentIdentityDeleteMfaHandler = clientCurrentIdentity.DeleteMfaHandlerFunc(func(params clientCurrentIdentity.DeleteMfaParams, i interface{}) middleware.Responder { return ae.IsAllowed(func(ae *env.AppEnv, rc *response.RequestContext) { - r.removeMfa(ae, rc, params.MfaValidation, params.MfaValidationCode) + r.removeMfa(ae, rc, params.MfaValidationCode) }, params.HTTPRequest, "", "", permissions.IsAuthenticated()) }) @@ -104,7 +105,7 @@ func (r *CurrentIdentityRouter) Register(ae *env.AppEnv) { ae.ManagementApi.CurrentIdentityDeleteMfaHandler = managementCurrentIdentity.DeleteMfaHandlerFunc(func(params managementCurrentIdentity.DeleteMfaParams, i interface{}) middleware.Responder { return ae.IsAllowed(func(ae *env.AppEnv, rc *response.RequestContext) { - r.removeMfa(ae, rc, params.MfaValidation, params.MfaValidationCode) + r.removeMfa(ae, rc, params.MfaValidationCode) }, params.HTTPRequest, "", "", permissions.IsAuthenticated()) }) @@ -220,14 +221,8 @@ func (r *CurrentIdentityRouter) detailMfa(ae *env.AppEnv, rc *response.RequestCo }) } -func (r *CurrentIdentityRouter) removeMfa(ae *env.AppEnv, rc *response.RequestContext, mfaValidationBody *rest_model.MfaCode, mfaCodeHeader *string) { - code := "" - - if mfaValidationBody != nil && mfaValidationBody.Code != nil { - code = *mfaValidationBody.Code - } else if mfaCodeHeader != nil { - code = *mfaCodeHeader - } +func (r *CurrentIdentityRouter) removeMfa(ae *env.AppEnv, rc *response.RequestContext, requestCode *string) { + code := stringz.OrEmpty(requestCode) err := ae.Managers.Mfa.DeleteForIdentity(rc.Identity, code, rc.NewChangeContext()) diff --git a/controller/model/enrollment_model.go b/controller/model/enrollment_model.go index 3f15c3552..61060d3d7 100644 --- a/controller/model/enrollment_model.go +++ b/controller/model/enrollment_model.go @@ -23,7 +23,7 @@ import ( "github.com/openziti/edge/controller/persistence" "github.com/openziti/fabric/controller/models" "github.com/openziti/foundation/v2/errorz" - "github.com/openziti/sdk-golang/ziti/config" + "github.com/openziti/sdk-golang/ziti" "github.com/openziti/storage/boltz" "go.etcd.io/bbolt" "time" @@ -59,7 +59,7 @@ func (entity *Enrollment) FillJwtInfoWithExpiresAt(env Env, subject string, expi entity.Token = uuid.New().String() } - enrollmentClaims := config.EnrollmentClaims{ + enrollmentClaims := ziti.EnrollmentClaims{ EnrollmentMethod: entity.Method, StandardClaims: jwt.StandardClaims{ Audience: "", diff --git a/controller/response/context.go b/controller/response/context.go index c9519e921..058329e6f 100644 --- a/controller/response/context.go +++ b/controller/response/context.go @@ -18,6 +18,7 @@ package response import ( "errors" + "github.com/openziti/edge-api/rest_model" "github.com/openziti/edge/controller/model" "github.com/openziti/fabric/controller/change" "net/http" @@ -35,7 +36,7 @@ type RequestContext struct { ApiSession *model.ApiSession Identity *model.Identity AuthPolicy *model.AuthPolicy - AuthStatus AuthStatus + AuthQueries rest_model.AuthQueryList ActivePermissions []string ResponseWriter http.ResponseWriter Request *http.Request @@ -46,11 +47,6 @@ type RequestContext struct { StartTime time.Time } -type AuthStatus struct { - SecondaryExtJwtSignerId string - PassedSecondaryExtJwtSignerId bool -} - func (rc *RequestContext) GetId() string { return rc.Id } diff --git a/go.mod b/go.mod index 9c1668da2..463d6a33d 100644 --- a/go.mod +++ b/go.mod @@ -29,13 +29,13 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/netfoundry/secretstream v0.1.5 github.com/openziti/channel/v2 v2.0.62 - github.com/openziti/edge-api v0.25.11 + github.com/openziti/edge-api v0.25.17 github.com/openziti/fabric v0.23.1 github.com/openziti/foundation/v2 v2.0.21 github.com/openziti/identity v1.0.47 github.com/openziti/jwks v1.0.3 github.com/openziti/metrics v1.2.19 - github.com/openziti/sdk-golang v0.18.76 + github.com/openziti/sdk-golang v0.20.0 github.com/openziti/storage v0.2.0 github.com/openziti/transport/v2 v2.0.75 github.com/openziti/x509-claims v1.0.3 @@ -108,6 +108,7 @@ require ( github.com/natefinch/lumberjack v2.0.0+incompatible // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect + github.com/openziti/secretstream v0.1.6 // indirect github.com/parallaxsecond/parsec-client-go v0.0.0-20221025095442-f0a77d263cf9 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect diff --git a/go.sum b/go.sum index 7a6460765..fd17f0d65 100644 --- a/go.sum +++ b/go.sum @@ -455,8 +455,8 @@ github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openziti/channel/v2 v2.0.62 h1:WmNYAugoyQ2HFu2VEhOH4WExzXsX6+dzSQDzNfHf5M8= github.com/openziti/channel/v2 v2.0.62/go.mod h1:TS2FJs1GuCZXUfSFfptrNWKeTuQRO7YJ9K7C2jWMznA= -github.com/openziti/edge-api v0.25.11 h1:HHjDgoybPZGRZ+tM2udehI+U5Xv991iGED8E6CtDb9w= -github.com/openziti/edge-api v0.25.11/go.mod h1:PBFMYELgr7JUuaCqHobq1U+WESsutzgEDoELU/9qFOg= +github.com/openziti/edge-api v0.25.17 h1:SLmcI2bPg9ZK+HgJy9Jr2D6iYx+rvK/kWl3aN1ITg8c= +github.com/openziti/edge-api v0.25.17/go.mod h1:TC+hI2eI9X5PvqT0UtnOpEDQBkMK5yUEc8BtDJhyCCE= github.com/openziti/fabric v0.23.1 h1:9RFRmApJ9EGUNNwIP4OSZcgFmiBdVLTvLfYsYRID8ws= github.com/openziti/fabric v0.23.1/go.mod h1:p5EI0s0LvNi6HipLR+PWDon89C3dhfyX/jac/3cwmpA= github.com/openziti/foundation/v2 v2.0.21 h1:3EDDmSunsbd2DlULuY/vqj12LHRZOknH/m3lf6Ws5Nw= @@ -467,8 +467,10 @@ github.com/openziti/jwks v1.0.3 h1:hf8wkb+Cg4nH/HM0KROFd7u+C3DkRVcFZJ7tDV+4icc= github.com/openziti/jwks v1.0.3/go.mod h1:t4xxq8vlXGsPn29kiQVnZBBDDnEoOFqtJoHibkJunQQ= github.com/openziti/metrics v1.2.19 h1:gQO3e2lUotRHBdGUXYBPWMIErIyyF5hw0EakwQbJzuM= github.com/openziti/metrics v1.2.19/go.mod h1:ovvxTpDBxGLcVLHgPTFFvwT4ur8p4Z76BPUhIE5iwqc= -github.com/openziti/sdk-golang v0.18.76 h1:D+UW1lpGHBBgfVrObpauq9RvJV/TFPdEEshfuPkiMcI= -github.com/openziti/sdk-golang v0.18.76/go.mod h1:kw/5rWDLwx52iwW/4a0VRQMUi7GPSI3aETx+G5TvdFQ= +github.com/openziti/sdk-golang v0.20.0 h1:a5pwPOpp1mS66+5lHEU74kWIEU3D2ySE/sZnNLNdf4M= +github.com/openziti/sdk-golang v0.20.0/go.mod h1:5deFxXx5JWeOVCfRkyi6EfeALbhQ7avx2hymLJj9Q98= +github.com/openziti/secretstream v0.1.6 h1:TbpTwW/lc/0kuvaoRNjpiyebxh2Hyx8XSTB269QtHN4= +github.com/openziti/secretstream v0.1.6/go.mod h1:Gc6fhaDC46UUvwJD4ogbYji22YSdz3fe8bno+BFIpcE= github.com/openziti/storage v0.2.0 h1:uwSoZQEZCzxp4+KZEi7fOWezbm0knmcCbRhni/DGHSo= github.com/openziti/storage v0.2.0/go.mod h1:rJjLObUtJBNcm7MvnTr4DHCXZ+ppg0OMeoJ5tfi1aJI= github.com/openziti/transport/v2 v2.0.75 h1:KZmnyRH1SOXSI6DXqDRsbRxRJE2cWv5EDCiQqC+R+hQ= diff --git a/pb/edge_ctrl_pb/messages.go b/pb/edge_ctrl_pb/messages.go index 6eed9036f..a81ab721b 100644 --- a/pb/edge_ctrl_pb/messages.go +++ b/pb/edge_ctrl_pb/messages.go @@ -1,6 +1,7 @@ package edge_ctrl_pb import ( + "github.com/openziti/edge-api/rest_model" "github.com/openziti/fabric/controller/xt" "github.com/openziti/sdk-golang/ziti" ) @@ -114,18 +115,18 @@ func GetPrecedence(p ziti.Precedence) TerminatorPrecedence { return TerminatorPrecedence_Default } -func (self TerminatorPrecedence) GetZitiLabel() string { +func (self TerminatorPrecedence) GetZitiLabel() rest_model.TerminatorPrecedence { if self == TerminatorPrecedence_Default { - return ziti.PrecedenceDefaultLabel + return rest_model.TerminatorPrecedenceDefault } if self == TerminatorPrecedence_Required { - return ziti.PrecedenceRequiredLabel + return rest_model.TerminatorPrecedenceRequired } if self == TerminatorPrecedence_Failed { - return ziti.PrecedenceFailedLabel + return rest_model.TerminatorPrecedenceFailed } - return ziti.PrecedenceDefaultLabel + return rest_model.TerminatorPrecedenceDefault } diff --git a/router/enroll/enroll.go b/router/enroll/enroll.go index 6016c09d5..a55952a02 100644 --- a/router/enroll/enroll.go +++ b/router/enroll/enroll.go @@ -29,7 +29,7 @@ import ( "github.com/openziti/edge/router/internal/edgerouter" "github.com/openziti/fabric/router" "github.com/openziti/identity/certtools" - "github.com/openziti/sdk-golang/ziti/config" + "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/enroll" "gopkg.in/resty.v1" "net/http" @@ -44,7 +44,7 @@ type apiPost struct { } type Enroller interface { - Enroll(jwt []byte, silent bool, engine string, keyAlg config.KeyAlgVar) error + Enroll(jwt []byte, silent bool, engine string, keyAlg ziti.KeyAlgVar) error LoadConfig(cfgmap map[interface{}]interface{}) error } @@ -78,7 +78,7 @@ func (re *RestEnroller) LoadConfig(cfgmap map[interface{}]interface{}) error { return nil } -func (re *RestEnroller) Enroll(jwtBuf []byte, silent bool, engine string, keyAlg config.KeyAlgVar) error { +func (re *RestEnroller) Enroll(jwtBuf []byte, silent bool, engine string, keyAlg ziti.KeyAlgVar) error { log := pfxlog.Logger() if re.config == nil { diff --git a/router/handler_edge_ctrl/serviceList.go b/router/handler_edge_ctrl/serviceList.go index fddaef15f..640b52bc2 100644 --- a/router/handler_edge_ctrl/serviceList.go +++ b/router/handler_edge_ctrl/serviceList.go @@ -3,17 +3,17 @@ package handler_edge_ctrl import ( "encoding/json" "github.com/openziti/channel/v2" + "github.com/openziti/edge-api/rest_model" "github.com/openziti/edge/pb/edge_ctrl_pb" - "github.com/openziti/sdk-golang/ziti/edge" "github.com/sirupsen/logrus" "google.golang.org/protobuf/proto" ) type ServiceListHandler struct { - handler func(ch channel.Channel, lastUpdateToken []byte, list []*edge.Service) + handler func(ch channel.Channel, lastUpdateToken []byte, list []*rest_model.ServiceDetail) } -func NewServiceListHandler(handler func(ch channel.Channel, lastUpdateToken []byte, list []*edge.Service)) *ServiceListHandler { +func NewServiceListHandler(handler func(ch channel.Channel, lastUpdateToken []byte, list []*rest_model.ServiceDetail)) *ServiceListHandler { return &ServiceListHandler{ handler: handler, } @@ -34,15 +34,25 @@ func (self *ServiceListHandler) HandleReceive(msg *channel.Message, ch channel.C } func (self *ServiceListHandler) handleServicesList(ch channel.Channel, list *edge_ctrl_pb.ServicesList) { - var serviceList []*edge.Service + var serviceList []*rest_model.ServiceDetail + for _, entry := range list.Services { - service := &edge.Service{ - Id: entry.Id, - Name: entry.Name, - Permissions: entry.Permissions, - Encryption: entry.Encryption, - Configs: map[string]map[string]interface{}{}, - Tags: map[string]string{}, + + var permissions rest_model.DialBindArray + + for _, perm := range entry.Permissions { + permissions = append(permissions, rest_model.DialBind(perm)) + } + + service := &rest_model.ServiceDetail{ + BaseEntity: rest_model.BaseEntity{ + ID: &entry.Id, + Tags: &rest_model.Tags{}, + }, + Name: &entry.Name, + Permissions: permissions, + EncryptionRequired: &entry.Encryption, + Config: map[string]map[string]interface{}{}, } err := json.Unmarshal(entry.Config, &service.Configs) @@ -50,7 +60,7 @@ func (self *ServiceListHandler) handleServicesList(ch channel.Channel, list *edg logrus. WithError(err). WithField("json", string(entry.Config)). - WithField("service", service.Id). + WithField("service", *service.ID). Error("unable to unmarshal config json") return } @@ -60,7 +70,7 @@ func (self *ServiceListHandler) handleServicesList(ch channel.Channel, list *edg logrus. WithError(err). WithField("json", string(entry.Tags)). - WithField("service", service.Id). + WithField("service", *service.ID). Error("unable to unmarshal tag json") return } diff --git a/router/xgress_common/connection.go b/router/xgress_common/connection.go index ccf7088c9..c1e38b719 100644 --- a/router/xgress_common/connection.go +++ b/router/xgress_common/connection.go @@ -25,7 +25,7 @@ import ( "github.com/openziti/foundation/v2/concurrenz" "github.com/openziti/foundation/v2/info" "github.com/openziti/sdk-golang/ziti/edge" - "github.com/openziti/sdk-golang/ziti/edge/impl" + "github.com/openziti/sdk-golang/ziti/edge/network" "github.com/pkg/errors" log "github.com/sirupsen/logrus" "io" @@ -194,7 +194,7 @@ func (self *XgressConn) ReadPayload() ([]byte, map[uint8][]byte, error) { if err == nil { err = cryptoErr } else { - err = impl.MultipleErrors{err, cryptoErr} + err = network.MultipleErrors{err, cryptoErr} } } } diff --git a/router/xgress_edge_tunnel/fabric.go b/router/xgress_edge_tunnel/fabric.go index fc83d09fd..6edae8866 100644 --- a/router/xgress_edge_tunnel/fabric.go +++ b/router/xgress_edge_tunnel/fabric.go @@ -24,6 +24,7 @@ import ( "github.com/netfoundry/secretstream/kx" "github.com/openziti/channel/v2" "github.com/openziti/channel/v2/protobufs" + "github.com/openziti/edge-api/rest_model" "github.com/openziti/edge/pb/edge_ctrl_pb" "github.com/openziti/edge/router/xgress_common" "github.com/openziti/edge/tunnel" @@ -48,6 +49,10 @@ import ( "time" ) +func ToPtr[T any](in T) *T { + return &in +} + func newProvider(factory *Factory, tunneler *tunneler) *fabricProvider { return &fabricProvider{ factory: factory, @@ -64,7 +69,7 @@ type fabricProvider struct { apiSessionLock sync.Mutex apiSessionTokens map[string]string - currentIdentity *edge.CurrentIdentity + currentIdentity *rest_model.IdentityDetail dialSessions cmap.ConcurrentMap[string, string] bindSessions cmap.ConcurrentMap[string, string] @@ -92,14 +97,16 @@ func (self *fabricProvider) updateApiSession(ctrlId string, resp *edge_ctrl_pb.C self.tunneler.stateManager.RemoveConnectedApiSession(currentToken) self.apiSessionTokens[ctrlId] = resp.Token - self.currentIdentity = &edge.CurrentIdentity{ - Id: resp.IdentityId, - Name: resp.IdentityName, - DefaultHostingPrecedence: strings.ToLower(resp.DefaultHostingPrecedence.String()), - DefaultHostingCost: uint16(resp.DefaultHostingCost), - AppData: map[string]interface{}{}, - ServiceHostingPrecedences: map[string]interface{}{}, - ServiceHostingCosts: map[string]interface{}{}, + self.currentIdentity = &rest_model.IdentityDetail{ + BaseEntity: rest_model.BaseEntity{ + ID: &resp.IdentityId, + }, + Name: &resp.IdentityName, + DefaultHostingPrecedence: rest_model.TerminatorPrecedence(strings.ToLower(resp.DefaultHostingPrecedence.String())), + DefaultHostingCost: ToPtr(rest_model.TerminatorCost(int64(resp.DefaultHostingCost))), + AppData: &rest_model.Tags{}, + ServiceHostingPrecedences: rest_model.TerminatorPrecedenceMap{}, + ServiceHostingCosts: rest_model.TerminatorCostMap{}, } for k, v := range resp.ServicePrecedences { @@ -107,7 +114,7 @@ func (self *fabricProvider) updateApiSession(ctrlId string, resp *edge_ctrl_pb.C } for k, v := range resp.ServiceCosts { - self.currentIdentity.ServiceHostingCosts[k] = float64(v) + self.currentIdentity.ServiceHostingCosts[k] = ToPtr(rest_model.TerminatorCost(v)) } if resp.AppDataJson != "" { @@ -123,21 +130,17 @@ func (self *fabricProvider) updateApiSession(ctrlId string, resp *edge_ctrl_pb.C } func (self *fabricProvider) authenticate() error { - info := sdkinfo.GetSdkInfo() + envInfo, _ := sdkinfo.GetSdkInfo() buildInfo := build.GetBuildInfo() osVersion := "unknown" osRelease := "unknown" - if val, ok := info["osVersion"]; ok { - if valStr, ok := val.(string); ok { - osVersion = valStr - } + if envInfo.OsVersion != "" { + osVersion = envInfo.OsVersion } - if val, ok := info["osRelease"]; ok { - if valStr, ok := val.(string); ok { - osRelease = valStr - } + if envInfo.OsRelease != "" { + osRelease = envInfo.OsRelease } request := &edge_ctrl_pb.CreateApiSessionRequest{ @@ -189,7 +192,7 @@ func (self *fabricProvider) authenticate() error { func (self *fabricProvider) PrepForUse(string) {} -func (self *fabricProvider) GetCurrentIdentity() (*edge.CurrentIdentity, error) { +func (self *fabricProvider) GetCurrentIdentity() (*rest_model.IdentityDetail, error) { return self.currentIdentity, nil } diff --git a/router/xgress_edge_tunnel/servicepoll.go b/router/xgress_edge_tunnel/servicepoll.go index a54ac2772..62daa43d9 100644 --- a/router/xgress_edge_tunnel/servicepoll.go +++ b/router/xgress_edge_tunnel/servicepoll.go @@ -19,9 +19,9 @@ limitations under the License. import ( "github.com/michaelquigley/pfxlog" "github.com/openziti/channel/v2" + "github.com/openziti/edge-api/rest_model" "github.com/openziti/edge/tunnel/intercept" "github.com/openziti/sdk-golang/ziti" - "github.com/openziti/sdk-golang/ziti/edge" cmap "github.com/orcaman/concurrent-map/v2" "github.com/sirupsen/logrus" "reflect" @@ -31,7 +31,7 @@ import ( func newServicePoller(fabricProvider *fabricProvider) *servicePoller { result := &servicePoller{ - services: cmap.New[*edge.Service](), + services: cmap.New[*rest_model.ServiceDetail](), servicesLastUpdateToken: cmap.New[[]byte](), fabricProvider: fabricProvider, } @@ -40,7 +40,7 @@ func newServicePoller(fabricProvider *fabricProvider) *servicePoller { } type servicePoller struct { - services cmap.ConcurrentMap[string, *edge.Service] + services cmap.ConcurrentMap[string, *rest_model.ServiceDetail] serviceListener *intercept.ServiceListener servicesLastUpdateToken cmap.ConcurrentMap[string, []byte] serviceListenerLock sync.Mutex @@ -48,7 +48,7 @@ type servicePoller struct { fabricProvider *fabricProvider } -func (self *servicePoller) handleServiceListUpdate(ch channel.Channel, lastUpdateToken []byte, services []*edge.Service) { +func (self *servicePoller) handleServiceListUpdate(ch channel.Channel, lastUpdateToken []byte, services []*rest_model.ServiceDetail) { self.serviceListenerLock.Lock() defer self.serviceListenerLock.Unlock() @@ -61,16 +61,16 @@ func (self *servicePoller) handleServiceListUpdate(ch channel.Channel, lastUpdat self.servicesLastUpdateToken.Set(ch.Id(), lastUpdateToken) - idMap := make(map[string]*edge.Service) + idMap := make(map[string]*rest_model.ServiceDetail) for _, s := range services { - idMap[s.Id] = s + idMap[*s.ID] = s } var toRemove []string // process Deletes - self.services.IterCb(func(k string, svc *edge.Service) { - if _, found := idMap[svc.Id]; !found { + self.services.IterCb(func(k string, svc *rest_model.ServiceDetail) { + if _, found := idMap[*svc.ID]; !found { toRemove = append(toRemove, k) self.serviceListener.HandleServicesChange(ziti.ServiceRemoved, svc) } @@ -82,7 +82,7 @@ func (self *servicePoller) handleServiceListUpdate(ch channel.Channel, lastUpdat // Adds and Updates for _, s := range services { - self.services.Upsert(s.Id, s, func(exist bool, valueInMap *edge.Service, newValue *edge.Service) *edge.Service { + self.services.Upsert(*s.ID, s, func(exist bool, valueInMap *rest_model.ServiceDetail, newValue *rest_model.ServiceDetail) *rest_model.ServiceDetail { if !exist { self.serviceListener.HandleServicesChange(ziti.ServiceAdded, s) return s diff --git a/tests/addressable_terminators_test.go b/tests/addressable_terminators_test.go index ce20c85bf..519ae9a79 100644 --- a/tests/addressable_terminators_test.go +++ b/tests/addressable_terminators_test.go @@ -142,7 +142,7 @@ func Test_AddressableTerminatorSameIdentity(t *testing.T) { listener.(edge.SessionListener).SetErrorEventHandler(errorHandler) defer func() { _ = listener.Close() }() - context2 := ziti.NewContextWithConfig(identity.config) + context2 := ziti.NewContext(identity.config) listener2, err := context2.ListenWithOptions(service.Name, &ziti.ListenOptions{ BindUsingEdgeIdentity: true, ConnectTimeout: 5 * time.Second, diff --git a/tests/api_session_test.go b/tests/api_session_test.go index 7955f92fe..65811b915 100644 --- a/tests/api_session_test.go +++ b/tests/api_session_test.go @@ -46,7 +46,7 @@ func Test_ApiSession(t *testing.T) { expected := s(configType1.Id, configType2.Id) sort.Strings(expected) - sort.Strings(session.configTypes) - ctx.Req.Equal(expected, session.configTypes) + sort.Strings(session.AuthResponse.ConfigTypes) + ctx.Req.Equal(expected, session.AuthResponse.ConfigTypes) }) } diff --git a/tests/auth_cert_test.go b/tests/auth_cert_test.go index 79209c618..616b7eea6 100644 --- a/tests/auth_cert_test.go +++ b/tests/auth_cert_test.go @@ -29,12 +29,12 @@ import ( "fmt" "github.com/Jeffail/gabs" "github.com/openziti/edge-api/rest_model" + "github.com/openziti/edge/controller/env" "github.com/openziti/edge/controller/model" "github.com/openziti/edge/eid" "github.com/openziti/edge/internal/cert" "github.com/openziti/fabric/controller/change" nfPem "github.com/openziti/foundation/v2/pem" - "github.com/openziti/sdk-golang/ziti/constants" "github.com/stretchr/testify/require" "net/http" "reflect" @@ -147,7 +147,7 @@ func (test *authCertTests) testAuthenticateValidCertEmptyBody(t *testing.T) { standardJsonResponseTests(resp, http.StatusOK, t) t.Run("returns a session token HTTP headers", func(t *testing.T) { - require.New(t).NotEmpty(resp.Header().Get(constants.ZitiSession), fmt.Sprintf("HTTP header %s is empty", constants.ZitiSession)) + require.New(t).NotEmpty(resp.Header().Get(env.ZitiSession), fmt.Sprintf("HTTP header %s is empty", env.ZitiSession)) }) t.Run("returns a session token in body", func(t *testing.T) { @@ -167,7 +167,7 @@ func (test *authCertTests) testAuthenticateValidCertEmptyBody(t *testing.T) { r.NoError(err) bodyToken := data.Path("data.token").Data().(string) - headerToken := resp.Header().Get(constants.ZitiSession) + headerToken := resp.Header().Get(env.ZitiSession) r.Equal(bodyToken, headerToken) }) @@ -209,7 +209,7 @@ func (test *authCertTests) testAuthenticateValidCertValidClientInfoBody(t *testi standardJsonResponseTests(resp, http.StatusOK, t) t.Run("returns a session token HTTP headers", func(t *testing.T) { - require.New(t).NotEmpty(resp.Header().Get(constants.ZitiSession), fmt.Sprintf("HTTP header %s is empty", constants.ZitiSession)) + require.New(t).NotEmpty(resp.Header().Get(env.ZitiSession), fmt.Sprintf("HTTP header %s is empty", env.ZitiSession)) }) t.Run("returns a session token in body", func(t *testing.T) { @@ -229,7 +229,7 @@ func (test *authCertTests) testAuthenticateValidCertValidClientInfoBody(t *testi r.NoError(err) bodyToken := data.Path("data.token").Data().(string) - headerToken := resp.Header().Get(constants.ZitiSession) + headerToken := resp.Header().Get(env.ZitiSession) r.Equal(bodyToken, headerToken) }) @@ -342,7 +342,7 @@ func (test *authCertTests) testAuthenticateValidCertInvalidJson(t *testing.T) { standardErrorJsonResponseTests(resp, "COULD_NOT_PARSE_BODY", http.StatusBadRequest, t) t.Run("returns without a ziti session header", func(t *testing.T) { - require.New(t).Equal("", resp.Header().Get(constants.ZitiSession)) + require.New(t).Equal("", resp.Header().Get(env.ZitiSession)) }) } @@ -425,7 +425,7 @@ rv1CXRECfHglY+vO0CFumQOV5bec2R8= standardErrorJsonResponseTests(resp, "INVALID_AUTH", http.StatusUnauthorized, t) t.Run("returns without a ziti session header", func(t *testing.T) { - require.New(t).Equal("", resp.Header().Get(constants.ZitiSession)) + require.New(t).Equal("", resp.Header().Get(env.ZitiSession)) }) } diff --git a/tests/auth_external_jwt_signer_test.go b/tests/auth_external_jwt_signer_test.go index 3c154a05a..7be01ff98 100644 --- a/tests/auth_external_jwt_signer_test.go +++ b/tests/auth_external_jwt_signer_test.go @@ -151,7 +151,7 @@ func Test_Authenticate_External_Jwt(t *testing.T) { IssuedAt: time.Now().Unix(), Issuer: *validJwtSigner.Issuer, NotBefore: time.Now().Unix(), - Subject: ctx.AdminManagementSession.identityId, + Subject: *ctx.AdminManagementSession.AuthResponse.IdentityID, } jwtToken.Header["kid"] = *validJwtSigner.Kid @@ -183,7 +183,7 @@ func Test_Authenticate_External_Jwt(t *testing.T) { IssuedAt: time.Now().Unix(), Issuer: "fake.issuer", NotBefore: time.Now().Unix(), - Subject: ctx.AdminManagementSession.identityId, + Subject: *ctx.AdminManagementSession.AuthResponse.IdentityID, } jwtToken.Header["kid"] = *notEnabledJwtSigner.Kid @@ -210,7 +210,7 @@ func Test_Authenticate_External_Jwt(t *testing.T) { IssuedAt: time.Now().Unix(), Issuer: "i will cause this to fail", NotBefore: time.Now().Unix(), - Subject: ctx.AdminManagementSession.identityId, + Subject: *ctx.AdminManagementSession.AuthResponse.IdentityID, } jwtToken.Header["kid"] = *validJwtSigner.Kid @@ -237,7 +237,7 @@ func Test_Authenticate_External_Jwt(t *testing.T) { IssuedAt: time.Now().Unix(), Issuer: *validJwtSigner.Issuer, NotBefore: time.Now().Unix(), - Subject: ctx.AdminManagementSession.identityId, + Subject: *ctx.AdminManagementSession.AuthResponse.IdentityID, } jwtToken.Header["kid"] = *validJwtSigner.Kid @@ -264,7 +264,7 @@ func Test_Authenticate_External_Jwt(t *testing.T) { IssuedAt: time.Now().Unix(), Issuer: "fake.issuer", NotBefore: time.Now().Unix(), - Subject: ctx.AdminManagementSession.identityId, + Subject: *ctx.AdminManagementSession.AuthResponse.IdentityID, } jwtStrSigned, err := jwtToken.SignedString(validJwtSignerPrivateKey) @@ -289,7 +289,7 @@ func Test_Authenticate_External_Jwt(t *testing.T) { IssuedAt: time.Now().Unix(), Issuer: "fake.issuer", NotBefore: time.Now().Unix(), - Subject: ctx.AdminManagementSession.identityId, + Subject: *ctx.AdminManagementSession.AuthResponse.IdentityID, } jwtToken.Header["kid"] = *validJwtSigner.Kid @@ -316,7 +316,7 @@ func Test_Authenticate_External_Jwt(t *testing.T) { IssuedAt: time.Now().Unix(), Issuer: "fake.issuer", NotBefore: time.Now().Unix(), - Subject: ctx.AdminManagementSession.identityId, + Subject: *ctx.AdminManagementSession.AuthResponse.IdentityID, } jwtToken.Header["kid"] = invalidJwtSignerCertFingerprint diff --git a/tests/auth_perf_test.go b/tests/auth_perf_test.go index ec35d9c7c..becdd72d4 100644 --- a/tests/auth_perf_test.go +++ b/tests/auth_perf_test.go @@ -1,3 +1,4 @@ +//go:build apitests && perftests // +build apitests,perftests /* @@ -19,13 +20,8 @@ package tests import ( - identity2 "github.com/openziti/identity" "github.com/openziti/sdk-golang/ziti" - "github.com/openziti/sdk-golang/ziti/edge" - "github.com/openziti/sdk-golang/ziti/edge/api" - "github.com/openziti/sdk-golang/ziti/sdkinfo" "github.com/rcrowley/go-metrics" - "net/url" "os" "testing" "time" @@ -48,25 +44,14 @@ func Test_AuthPerformance(t *testing.T) { identity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) config := ctx.AdminManagementSession.testContext.EnrollIdentity(identity.Id) - context := ziti.NewContextWithConfig(config) - _, _ = context.GetServices() - - ctrlUrl, err := url.Parse(config.ZtAPI) - ctx.Req.NoError(err) - id, err := identity2.LoadIdentity(config.ID) - ctx.Req.NoError(err) - client, err := api.NewClient(ctrlUrl, id.ClientTLSConfig(), s("all")) - ctx.Req.NoError(err) - - info := sdkinfo.GetSdkInfo() - _, err = client.Login(info) + context, err := ziti.NewContext(config) ctx.Req.NoError(err) for i := 0; i < 25; i++ { go func() { for { start := time.Now() - _, err := client.Login(info) + err := context.Authenticate() ctx.Req.NoError(err) meter.Mark(1) done := time.Now() @@ -103,27 +88,21 @@ func Test_CombinedSessionCreatePerformance(t *testing.T) { identity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) config := ctx.AdminManagementSession.testContext.EnrollIdentity(identity.Id) - context := ziti.NewContextWithConfig(config) - _, _ = context.GetServices() - - ctrlUrl, err := url.Parse(config.ZtAPI) - ctx.Req.NoError(err) - id, err := identity2.LoadIdentity(config.ID) - ctx.Req.NoError(err) - client, err := api.NewClient(ctrlUrl, id.ClientTLSConfig(), s("all")) + context, err := ziti.NewContext(config) ctx.Req.NoError(err) - info := sdkinfo.GetSdkInfo() - _, err = client.Login(info) + err = context.Authenticate() ctx.Req.NoError(err) + client := context.(*ziti.ContextImpl).CtrlClt + service := ctx.AdminManagementSession.RequireNewServiceAccessibleToAll("smartrouting") for i := 0; i < 25; i++ { go func() { for { start := time.Now() - _, err := client.Login(info) + err := context.Authenticate() ctx.Req.NoError(err) apiSessionCreateMeter.Mark(1) done := time.Now() @@ -131,7 +110,8 @@ func Test_CombinedSessionCreatePerformance(t *testing.T) { apiSessionCreateHistogram.Update(diff.Milliseconds()) start = time.Now() - _, err = client.CreateSession(service.Id, edge.SessionDial) + + _, err = client.CreateSession(service.Id, ziti.SessionType(ziti.SessionDial)) ctx.Req.NoError(err) sessionCreateMeter.Mark(1) done = time.Now() @@ -165,25 +145,19 @@ func Test_SessionCreatePerformance(t *testing.T) { identity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) config := ctx.AdminManagementSession.testContext.EnrollIdentity(identity.Id) - context := ziti.NewContextWithConfig(config) - _, _ = context.GetServices() - - ctrlUrl, err := url.Parse(config.ZtAPI) - ctx.Req.NoError(err) - id, err := identity2.LoadIdentity(config.ID) - ctx.Req.NoError(err) - client, err := api.NewClient(ctrlUrl, id.ClientTLSConfig(), s("all")) + context, err := ziti.NewContext(config) ctx.Req.NoError(err) - info := sdkinfo.GetSdkInfo() - _, err = client.Login(info) + err = context.Authenticate() ctx.Req.NoError(err) + client := context.(*ziti.ContextImpl).CtrlClt + for i := 0; i < 50; i++ { go func() { for { start := time.Now() - _, err := client.CreateSession(service.Id, edge.SessionDial) + _, err := client.CreateSession(service.Id, ziti.SessionType(ziti.SessionDial)) ctx.Req.NoError(err) meter.Mark(1) done := time.Now() diff --git a/tests/auth_policy_test.go b/tests/auth_policy_test.go index 13a90071c..392b8ca10 100644 --- a/tests/auth_policy_test.go +++ b/tests/auth_policy_test.go @@ -1421,6 +1421,11 @@ func Test_AuthPolicies(t *testing.T) { ctx.Req.NotEmpty(currentApiSessionEnv.Data.AuthQueries) + //API Session from auth ahs the auth query + ctx.Req.Equal("EXT-JWT", apiSession.AuthResponse.AuthQueries[0].TypeID) + ctx.Req.Equal(*extJwtSignerAllowed.ExternalAuthURL, apiSession.AuthResponse.AuthQueries[0].HTTPURL) + + //API Session from get current has auth query ctx.Req.Equal("EXT-JWT", currentApiSessionEnv.Data.AuthQueries[0].TypeID) ctx.Req.Equal(*extJwtSignerAllowed.ExternalAuthURL, currentApiSessionEnv.Data.AuthQueries[0].HTTPURL) diff --git a/tests/auth_updb_test.go b/tests/auth_updb_test.go index f47ae9eac..dd8ed7c43 100644 --- a/tests/auth_updb_test.go +++ b/tests/auth_updb_test.go @@ -22,7 +22,7 @@ package tests import ( "fmt" "github.com/Jeffail/gabs" - "github.com/openziti/sdk-golang/ziti/constants" + "github.com/openziti/edge/controller/env" "github.com/stretchr/testify/require" "net/http" "testing" @@ -151,7 +151,7 @@ func (tests *authUpdbTests) testAuthenticateUPDBDefaultAdminSuccess(t *testing.T standardJsonResponseTests(resp, http.StatusOK, t) t.Run("returns a session token HTTP headers", func(t *testing.T) { - require.New(t).NotEmpty(resp.Header().Get(constants.ZitiSession), fmt.Sprintf("HTTP header %s is empty", constants.ZitiSession)) + require.New(t).NotEmpty(resp.Header().Get(env.ZitiSession), fmt.Sprintf("HTTP header %s is empty", env.ZitiSession)) }) t.Run("returns a session token in body", func(t *testing.T) { @@ -171,7 +171,7 @@ func (tests *authUpdbTests) testAuthenticateUPDBDefaultAdminSuccess(t *testing.T r.NoError(err) bodyToken := data.Path("data.token").Data().(string) - headerToken := resp.Header().Get(constants.ZitiSession) + headerToken := resp.Header().Get(env.ZitiSession) r.Equal(bodyToken, headerToken) }) diff --git a/tests/authenticate.go b/tests/authenticate.go index 01651eb9b..8dae7bd46 100644 --- a/tests/authenticate.go +++ b/tests/authenticate.go @@ -18,20 +18,25 @@ package tests import ( "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" "crypto/tls" "crypto/x509" + "crypto/x509/pkix" "encoding/json" "fmt" "github.com/Jeffail/gabs" "github.com/michaelquigley/pfxlog" "github.com/openziti/edge-api/rest_model" + "github.com/openziti/edge/controller/env" "github.com/openziti/edge/eid" "github.com/openziti/edge/internal/cert" "github.com/openziti/foundation/v2/stringz" "github.com/openziti/sdk-golang/ziti" - "github.com/openziti/sdk-golang/ziti/constants" "github.com/pkg/errors" "gopkg.in/resty.v1" + "math/big" "net/http" "net/url" "sort" @@ -116,7 +121,14 @@ func (authenticator *certAuthenticator) Authenticate(ctx *TestContext, apiPath s sess.client.SetHostURL(resolvedUrl) + apiSession := &rest_model.CurrentAPISessionDetail{} + + envelope := &rest_model.CurrentAPISessionDetailEnvelope{ + Data: apiSession, + Meta: &rest_model.Meta{}, + } resp, err := sess.client.R(). + SetResult(envelope). SetHeader("content-type", "application/json"). Post("authenticate?method=cert") @@ -128,9 +140,8 @@ func (authenticator *certAuthenticator) Authenticate(ctx *TestContext, apiPath s return nil, errors.Errorf("failed to authenticate via CERT: invalid response code encountered, got %d, expected %d: %s", resp.StatusCode(), http.StatusOK, string(resp.Body())) } - if err = sess.parseSessionInfoFromResponse(ctx, resp); err != nil { - return nil, err - } + sess.AuthResponse = apiSession + sess.lastServiceUpdate = time.Time(*apiSession.CreatedAt) return sess, nil } @@ -212,9 +223,17 @@ func (authenticator *updbAuthenticator) Authenticate(ctx *TestContext, apiPath s _, _ = body.SetP(authenticator.ConfigTypes, "configTypes") } + apiSession := &rest_model.CurrentAPISessionDetail{} + + envelope := &rest_model.CurrentAPISessionDetailEnvelope{ + Data: apiSession, + Meta: &rest_model.Meta{}, + } + resp, err := sess.client.R(). SetHeader("content-type", "application/json"). SetBody(body.String()). + SetResult(envelope). Post("authenticate?method=password") if err != nil { @@ -225,26 +244,21 @@ func (authenticator *updbAuthenticator) Authenticate(ctx *TestContext, apiPath s return nil, errors.Errorf("failed to authenticate via UPDB as %v: invalid response code encountered, got %d, expected %d", authenticator, resp.StatusCode(), http.StatusOK) } - if err = sess.parseSessionInfoFromResponse(ctx, resp); err != nil { - return nil, err - } + sess.AuthResponse = apiSession + sess.lastServiceUpdate = time.Time(*apiSession.CreatedAt) return sess, nil } type session struct { - authenticator authenticator - id string - token string - identityId string - createdAt time.Time - lastServiceUpdate time.Time - configTypes []string - testContext *TestContext - baseUrl string + authenticator authenticator + testContext *TestContext + baseUrl string authenticatedRequests - apiPath string - client *resty.Client + apiPath string + client *resty.Client + AuthResponse *rest_model.CurrentAPISessionDetail + lastServiceUpdate time.Time } // Clone allows a session to be cloned with a new internal Resty Client that targets another API. Useful for @@ -253,15 +267,11 @@ type session struct { func (sess *session) Clone(ctx *TestContext, apiPath string) (*session, error) { clone := &session{ authenticator: sess.authenticator, - id: sess.id, - token: sess.token, - identityId: sess.identityId, - createdAt: sess.createdAt, - lastServiceUpdate: sess.lastServiceUpdate, - configTypes: sess.configTypes, + AuthResponse: sess.AuthResponse, testContext: sess.testContext, baseUrl: sess.baseUrl, apiPath: apiPath, + lastServiceUpdate: sess.lastServiceUpdate, client: resty.NewWithClient(sess.client.GetClient()), } @@ -294,8 +304,12 @@ func (sess *session) CloneToManagementApi(ctx *TestContext) (*session, error) { } func (sess *session) NewRequest() *resty.Request { - sess.client.R() - return sess.client.R().SetHeader(constants.ZitiSession, sess.token) + if sess.AuthResponse != nil && sess.AuthResponse.Token != nil { + return sess.client.R().SetHeader(env.ZitiSession, *sess.AuthResponse.Token) + } + + return sess.client.R() + } // resolveApiUrl takes a URL prefix, apiHost, in the format of "https://domain:port" and joins @@ -318,50 +332,6 @@ func (sess *session) resolveApiUrl(apiHost string, apiPath string) (string, erro return resolvedUrl.String(), nil } -func (sess *session) parseSessionInfoFromResponse(ctx *TestContext, response *resty.Response) error { - respBody := response.Body() - - if len(respBody) == 0 { - return errors.Errorf("failed to authenticate via UPDB %v: encountered zero length body", sess.authenticator) - } - - ctx.logJson(respBody) - - bodyContainer, err := gabs.ParseJSON(respBody) - - if err != nil { - return errors.Errorf("failed to authenticate via UPDB as %v: failed to parse response: %s", sess.authenticator, err) - } - - if sessionId, ok := bodyContainer.Path("data.id").Data().(string); ok { - sess.id = sessionId - } else { - return errors.Errorf("failed to authenticate via UPDB as %v: failed to find session id", sess.authenticator) - } - - if sessionToken, ok := bodyContainer.Path("data.token").Data().(string); ok { - sess.token = sessionToken - } else { - return errors.Errorf("failed to authenticate via UPDB as %v: failed to find session token", sess.authenticator) - } - - if identityId, ok := bodyContainer.Path("data.identity.id").Data().(string); ok { - sess.identityId = identityId - } else { - return errors.Errorf("failed to authenticate via UPDB as %v: failed to find identity id", sess.authenticator) - } - - if createdAt, ok := bodyContainer.Path("data.createdAt").Data().(string); ok { - t, err := time.Parse(time.RFC3339, createdAt) - ctx.Req.NoError(err) - sess.createdAt = t - sess.lastServiceUpdate = t - } - - sess.configTypes = ctx.toStringSlice(bodyContainer.Path("data.configTypes")) - return nil -} - func (sess *session) logout() error { resp, err := sess.NewRequest().Delete("current-api-session") @@ -370,7 +340,7 @@ func (sess *session) logout() error { } if resp.StatusCode() != http.StatusOK { - return errors.Errorf("could not delete current session %s for logout: got status code %d expected %d", sess.token, resp.StatusCode(), http.StatusOK) + return errors.Errorf("could not delete current session %s for logout: got status code %d expected %d", *sess.AuthResponse.Token, resp.StatusCode(), http.StatusOK) } return nil @@ -394,7 +364,13 @@ func (request *authenticatedRequests) newAuthenticatedRequestWithBody(body inter func (request *authenticatedRequests) RequireCreateSdkContext(roleAttributes ...string) (*identity, ziti.Context) { identity := request.RequireNewIdentityWithOtt(false, roleAttributes...) identity.config = request.testContext.EnrollIdentity(identity.Id) - context := ziti.NewContextWithConfig(identity.config) + + context, err := ziti.NewContext(identity.config) + + if err != nil { + pfxlog.Logger().Fatalf("could not create new context with config: %v", err) + } + return identity, context } @@ -1087,3 +1063,35 @@ func (request *authenticatedRequests) getIdentityJwt(identityId string) string { data := request.testContext.RequireGetNonNilPathValue(jsonBody, "data", "enrollment", "ott", "jwt") return data.Data().(string) } + +func newSelfSignedCert(commonName string) (*x509.Certificate, crypto.PrivateKey) { + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + panic(err) + } + template := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + CommonName: commonName, + Organization: []string{"API Test Co"}, + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour * 24 * 180), + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + der, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + if err != nil { + panic(err) + } + cert, err := x509.ParseCertificate(der) + + if err != nil { + panic(err) + } + + return cert, priv +} diff --git a/tests/authenticator_test.go b/tests/authenticator_test.go index 9431c4ad4..5da0d75fe 100644 --- a/tests/authenticator_test.go +++ b/tests/authenticator_test.go @@ -112,7 +112,7 @@ func Test_Authenticators_AdminUsingAdminEndpoints(t *testing.T) { session, err := authenticator.AuthenticateClientApi(ctx) req.NoError(err) - req.NotEmpty(session.id) + req.NotNil(session.AuthResponse) }) }) @@ -329,7 +329,7 @@ func Test_Authenticators_AdminUsingAdminEndpoints(t *testing.T) { ctx.NoError(err) ctx.NotNil(session) - ctx.NotEmpty(session.token) + ctx.NotEmpty(session.AuthResponse.Token) }) }) @@ -371,7 +371,7 @@ func Test_Authenticators_AdminUsingAdminEndpoints(t *testing.T) { ctx.NoError(err) ctx.NotNil(session) - ctx.NotEmpty(session.token) + ctx.NotEmpty(session.AuthResponse.Token) }) }) }) @@ -639,7 +639,7 @@ func Test_Authenticators_NonAdminUsingSelfServiceEndpoints(t *testing.T) { id, ok := updbAuthenticatorListBody.Search("data").Index(0).Path("identityId").Data().(string) req.True(ok) - req.Equal(updbNonAdminSession.identityId, id) + req.Equal(*updbNonAdminSession.AuthResponse.IdentityID, id) }) t.Run("can get the detail of the authenticator", func(t *testing.T) { diff --git a/tests/ca_test.go b/tests/ca_test.go index d681238da..2dfb27daf 100644 --- a/tests/ca_test.go +++ b/tests/ca_test.go @@ -102,7 +102,7 @@ func Test_CA(t *testing.T) { ctx.Req.NoError(err) - identity := ctx.AdminManagementSession.requireQuery("identities/" + enrolledSession.identityId) + identity := ctx.AdminManagementSession.requireQuery("identities/" + *enrolledSession.AuthResponse.IdentityID) sort.Strings(ca.identityRoles) ctx.pathEqualsStringSlice(identity, ca.identityRoles, path("data", "roleAttributes")) }) @@ -139,7 +139,7 @@ func Test_CA(t *testing.T) { ctx.Req.NoError(err) - identity := ctx.AdminManagementSession.requireQuery("identities/" + enrolledSession.identityId) + identity := ctx.AdminManagementSession.requireQuery("identities/" + *enrolledSession.AuthResponse.IdentityID) ctx.Req.Equal(expectedName, identity.Path("data.name").Data().(string)) }) @@ -178,7 +178,7 @@ func Test_CA(t *testing.T) { ctx.Req.NoError(err) - firstIdentity := ctx.AdminManagementSession.requireQuery("identities/" + firstEnrolledSession.identityId) + firstIdentity := ctx.AdminManagementSession.requireQuery("identities/" + *firstEnrolledSession.AuthResponse.IdentityID) ctx.Req.Equal(firstExpectedName, firstIdentity.Path("data.name").Data().(string)) //second firstIdentity that collides, becomes @@ -189,7 +189,7 @@ func Test_CA(t *testing.T) { ctx.Req.NoError(err) - secondIdentity := ctx.AdminManagementSession.requireQuery("identities/" + secondEnrolledSession.identityId) + secondIdentity := ctx.AdminManagementSession.requireQuery("identities/" + *secondEnrolledSession.AuthResponse.IdentityID) ctx.Req.Equal(secondExpectedName, secondIdentity.Path("data.name").Data().(string)) }) @@ -225,8 +225,8 @@ func Test_CA(t *testing.T) { ctx.Req.NoError(err) - identity := ctx.AdminManagementSession.requireQuery("identities/" + enrolledSession.identityId) - expectedName := fmt.Sprintf("%s - %s - %s - %s - %s", ca.name, ca.id, clientAuthenticator.cert.Subject.CommonName, requestedName, enrolledSession.identityId) + identity := ctx.AdminManagementSession.requireQuery("identities/" + *enrolledSession.AuthResponse.IdentityID) + expectedName := fmt.Sprintf("%s - %s - %s - %s - %s", ca.name, ca.id, clientAuthenticator.cert.Subject.CommonName, requestedName, *enrolledSession.AuthResponse.IdentityID) ctx.Req.Equal(expectedName, identity.Path("data.name").Data().(string)) }) diff --git a/tests/ca_traffic_test.go b/tests/ca_traffic_test.go index 08166a64f..69a6e15cd 100644 --- a/tests/ca_traffic_test.go +++ b/tests/ca_traffic_test.go @@ -15,7 +15,6 @@ import ( nfpem "github.com/openziti/foundation/v2/pem" id "github.com/openziti/identity" "github.com/openziti/sdk-golang/ziti" - sdkconfig "github.com/openziti/sdk-golang/ziti/config" "io" "math/big" "net/http" @@ -30,6 +29,8 @@ func Test_CA_Auth_Two_Identities_Diff_Certs(t *testing.T) { ctx.RequireAdminManagementApiLogin() ctx.CreateEnrollAndStartEdgeRouter() + time.Sleep(2 * time.Second) + t.Run("setup", func(t *testing.T) { ctx.testContextChanged(t) @@ -261,7 +262,7 @@ func Test_CA_Auth_Two_Identities_Diff_Certs(t *testing.T) { go func() { //connect client 1 - client1Config := &sdkconfig.Config{ + client1Config := &ziti.Config{ ZtAPI: "https://" + ctx.ApiHost + EdgeClientApiPath, ID: id.Config{ Key: id.StoragePem + ":" + string(clientKeyPem1), @@ -273,7 +274,9 @@ func Test_CA_Auth_Two_Identities_Diff_Certs(t *testing.T) { }, ConfigTypes: nil, } - client1Context := ziti.NewContextWithConfig(client1Config) + client1Context, err := ziti.NewContext(client1Config) + ctx.Req.NoError(err) + err = client1Context.Authenticate() ctx.Req.NoError(err) @@ -282,8 +285,6 @@ func Test_CA_Auth_Two_Identities_Diff_Certs(t *testing.T) { close(doneClient1) }() - time.Sleep(1 * time.Second) - conn, err := client1Context.Dial(service.Name) ctx.Req.NoError(err) ctx.Req.NotNil(conn) @@ -297,7 +298,7 @@ func Test_CA_Auth_Two_Identities_Diff_Certs(t *testing.T) { go func() { //connect client 2 - client2Config := &sdkconfig.Config{ + client2Config := &ziti.Config{ ZtAPI: "https://" + ctx.ApiHost + EdgeClientApiPath, ID: id.Config{ Key: id.StoragePem + ":" + string(clientKeyPem2), @@ -310,7 +311,9 @@ func Test_CA_Auth_Two_Identities_Diff_Certs(t *testing.T) { ConfigTypes: nil, } - client2Context := ziti.NewContextWithConfig(client2Config) + client2Context, err := ziti.NewContext(client2Config) + ctx.Req.NoError(err) + err = client2Context.Authenticate() ctx.Req.NoError(err) @@ -319,8 +322,6 @@ func Test_CA_Auth_Two_Identities_Diff_Certs(t *testing.T) { close(doneClient2) }() - time.Sleep(1 * time.Second) - conn, err := client2Context.Dial(service.Name) ctx.Req.NoError(err) ctx.Req.NotNil(conn) diff --git a/tests/context.go b/tests/context.go index a48630f75..2081e5652 100644 --- a/tests/context.go +++ b/tests/context.go @@ -41,7 +41,7 @@ import ( nfPem "github.com/openziti/foundation/v2/pem" "github.com/openziti/foundation/v2/versions" "github.com/openziti/identity/certtools" - sdkConfig "github.com/openziti/sdk-golang/ziti/config" + "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/edge" sdkEnroll "github.com/openziti/sdk-golang/ziti/enroll" "github.com/pkg/errors" @@ -88,6 +88,10 @@ func init() { transport.AddAddressParser(tcp.AddressParser{}) } +func ToPtr[T any](in T) *T { + return &in +} + func S(s string) *string { return &s } @@ -382,7 +386,7 @@ func (ctx *TestContext) requireEnrollEdgeRouter(tunneler bool, routerId string) enroller := enroll.NewRestEnroller() ctx.Req.NoError(enroller.LoadConfig(configMap)) - var keyAlg sdkConfig.KeyAlgVar + var keyAlg ziti.KeyAlgVar _ = keyAlg.Set("RSA") ctx.Req.NoError(enroller.Enroll([]byte(jwt), true, "", keyAlg)) } @@ -404,7 +408,7 @@ func (ctx *TestContext) createAndEnrollTransitRouter() *transitRouter { enroller := enroll.NewRestEnroller() ctx.Req.NoError(enroller.LoadConfig(configMap)) - var keyAlg sdkConfig.KeyAlgVar + var keyAlg ziti.KeyAlgVar _ = keyAlg.Set("RSA") ctx.Req.NoError(enroller.Enroll([]byte(jwt), true, "", keyAlg)) @@ -464,7 +468,7 @@ func (ctx *TestContext) startEdgeRouter() { ctx.Req.NoError(ctx.router.Start()) } -func (ctx *TestContext) EnrollIdentity(identityId string) *sdkConfig.Config { +func (ctx *TestContext) EnrollIdentity(identityId string) *ziti.Config { jwt := ctx.AdminManagementSession.getIdentityJwt(identityId) tkn, _, err := sdkEnroll.ParseToken(jwt) ctx.Req.NoError(err) @@ -840,28 +844,28 @@ func (ctx *TestContext) requireNListener(count int, l edge.Listener, timeout tim } } -func (ctx *TestContext) WrapNetConn(conn edge.Conn, err error) *testConn { +func (ctx *TestContext) WrapNetConn(conn edge.Conn, err error) *TestConn { ctx.Req.NoError(err) - return &testConn{ + return &TestConn{ Conn: conn, ctx: ctx, } } -func (ctx *TestContext) WrapConn(conn edge.Conn, err error) *testConn { +func (ctx *TestContext) WrapConn(conn edge.Conn, err error) *TestConn { ctx.Req.NoError(err) - return &testConn{ + return &TestConn{ Conn: conn, ctx: ctx, } } -type testConn struct { +type TestConn struct { edge.Conn ctx *TestContext } -func (conn *testConn) WriteString(val string, timeout time.Duration) { +func (conn *TestConn) WriteString(val string, timeout time.Duration) { conn.ctx.Req.NoError(conn.SetWriteDeadline(time.Now().Add(timeout))) defer func() { _ = conn.SetWriteDeadline(time.Time{}) }() @@ -871,7 +875,7 @@ func (conn *testConn) WriteString(val string, timeout time.Duration) { conn.ctx.Req.Equal(n, len(buf)) } -func (conn *testConn) ReadString(maxSize int, timeout time.Duration) string { +func (conn *TestConn) ReadString(maxSize int, timeout time.Duration) string { conn.ctx.Req.NoError(conn.SetReadDeadline(time.Now().Add(timeout))) defer func() { _ = conn.SetReadDeadline(time.Time{}) }() @@ -881,12 +885,12 @@ func (conn *testConn) ReadString(maxSize int, timeout time.Duration) string { return string(buf[:n]) } -func (conn *testConn) ReadExpected(expected string, timeout time.Duration) { +func (conn *TestConn) ReadExpected(expected string, timeout time.Duration) { val := conn.ReadString(len(expected)+1, timeout) conn.ctx.Req.Equal(expected, val, "read failure on connId=%v", conn.Id()) } -func (conn *testConn) RequireClose() { +func (conn *TestConn) RequireClose() { conn.ctx.Req.NoError(conn.Close()) } diff --git a/tests/data_flow_close_test.go b/tests/data_flow_close_test.go index c28bc7d79..73980a229 100644 --- a/tests/data_flow_close_test.go +++ b/tests/data_flow_close_test.go @@ -1,3 +1,4 @@ +//go:build dataflow // +build dataflow /* @@ -68,7 +69,7 @@ func Test_ServerConnClosePropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContextWithConfig(clientConfig) + clientContext := ziti.NewContext(clientConfig) conn := ctx.WrapConn(clientContext.Dial(service.Name)) defer conn.Close() @@ -133,7 +134,7 @@ func Test_ServerContextClosePropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContextWithConfig(clientConfig) + clientContext := ziti.NewContext(clientConfig) conn := ctx.WrapConn(clientContext.Dial(service.Name)) defer conn.Close() @@ -201,7 +202,7 @@ func Test_ServerCloseListenerPropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContextWithConfig(clientConfig) + clientContext := ziti.NewContext(clientConfig) conn := ctx.WrapConn(clientContext.Dial(service.Name)) defer conn.Close() @@ -233,7 +234,7 @@ func Test_ClientConnClosePropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContextWithConfig(clientConfig) + clientContext := ziti.NewContext(clientConfig) errC := make(chan error, 1) @@ -295,7 +296,7 @@ func Test_ClientContextClosePropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContextWithConfig(clientConfig) + clientContext := ziti.NewContext(clientConfig) errC := make(chan error, 1) @@ -358,7 +359,7 @@ func Test_ServerConnCloseWritePropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContextWithConfig(clientConfig) + clientContext := ziti.NewContext(clientConfig) errC := make(chan error, 1) @@ -452,7 +453,7 @@ func Test_ClientConnCloseWritePropagation(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContextWithConfig(clientConfig) + clientContext := ziti.NewContext(clientConfig) conn := ctx.WrapConn(clientContext.Dial(service.Name)) name := eid.New() diff --git a/tests/data_flow_hs_rotating_test.go b/tests/data_flow_hs_rotating_test.go index 1cfed8fd6..e17696411 100644 --- a/tests/data_flow_hs_rotating_test.go +++ b/tests/data_flow_hs_rotating_test.go @@ -122,7 +122,7 @@ func testClientFirstWithStrategy(t *testing.T, strategy string) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContextWithConfig(clientConfig) + clientContext := ziti.NewContext(clientConfig) logger := pfxlog.Logger() @@ -265,7 +265,7 @@ func testServerFirstWithStrategy(t *testing.T, strategy string) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContextWithConfig(clientConfig) + clientContext := ziti.NewContext(clientConfig) ticker := time.NewTicker(time.Millisecond * 500) defer ticker.Stop() diff --git a/tests/data_flow_hs_test.go b/tests/data_flow_hs_test.go index 1ac574ef8..3feb69813 100644 --- a/tests/data_flow_hs_test.go +++ b/tests/data_flow_hs_test.go @@ -1,3 +1,4 @@ +//go:build dataflow // +build dataflow /* @@ -75,7 +76,7 @@ func Test_HSDataflow(t *testing.T) { clientIdentity := ctx.AdminManagementSession.RequireNewIdentityWithOtt(false) clientConfig := ctx.EnrollIdentity(clientIdentity.Id) - clientContext := ziti.NewContextWithConfig(clientConfig) + clientContext := ziti.NewContext(clientConfig) for i := 0; i < 100; i++ { conn := ctx.WrapConn(clientContext.Dial(service.Name)) diff --git a/tests/enrollment_ca_auto_test.go b/tests/enrollment_ca_auto_test.go index 914f5e105..9d873ca9c 100644 --- a/tests/enrollment_ca_auto_test.go +++ b/tests/enrollment_ca_auto_test.go @@ -130,7 +130,7 @@ func Test_EnrollmetnCaAuto(t *testing.T) { identityGet := &rest_model.DetailIdentityEnvelope{} - resp, err := ctx.AdminManagementSession.newAuthenticatedRequest().SetResult(identityGet).Get("/identities/" + apiSession.identityId) + resp, err := ctx.AdminManagementSession.newAuthenticatedRequest().SetResult(identityGet).Get("/identities/" + *apiSession.AuthResponse.IdentityID) ctx.NoError(err) ctx.Equal(http.StatusOK, resp.StatusCode()) ctx.NotNil(identityGet) diff --git a/tests/enrollment_identity_extend_test.go b/tests/enrollment_identity_extend_test.go index b4cb512be..df9170544 100644 --- a/tests/enrollment_identity_extend_test.go +++ b/tests/enrollment_identity_extend_test.go @@ -29,10 +29,10 @@ import ( "encoding/pem" "fmt" "github.com/openziti/edge-api/rest_model" + "github.com/openziti/edge/controller/env" "github.com/openziti/edge/eid" nfpem "github.com/openziti/foundation/v2/pem" "github.com/openziti/identity/certtools" - "github.com/openziti/sdk-golang/ziti/constants" "gopkg.in/resty.v1" "net/http" "testing" @@ -216,7 +216,7 @@ func Test_EnrollmentIdentityExtend(t *testing.T) { client := resty.New().SetTLSClientConfig(&tls.Config{ InsecureSkipVerify: true, }) - extendResp, err := client.R().SetHeader(constants.ZitiSession, identityApiSession.token).SetBody(csrRequest).Post(resolvedUrl) + extendResp, err := client.R().SetHeader(env.ZitiSession, *identityApiSession.AuthResponse.Token).SetBody(csrRequest).Post(resolvedUrl) ctx.Req.NoError(err) ctx.Req.Equal(401, extendResp.StatusCode()) }) @@ -261,7 +261,7 @@ func Test_EnrollmentIdentityExtend(t *testing.T) { url := fmt.Sprintf("/current-identity/authenticators/%s/extend", *currentAuthenticator.ID) //use second identity http client w/ first identity's API Session - extendResp, err := secondIdentityApiSession.NewRequest().SetHeader(constants.ZitiSession, identityApiSession.token).SetBody(csrRequest).Post(url) + extendResp, err := secondIdentityApiSession.NewRequest().SetHeader(env.ZitiSession, *identityApiSession.AuthResponse.Token).SetBody(csrRequest).Post(url) ctx.Req.NoError(err) ctx.Req.Equal(401, extendResp.StatusCode()) }) diff --git a/tests/enrollment_updb_test.go b/tests/enrollment_updb_test.go index f1f81bb5f..f06aaa2c5 100644 --- a/tests/enrollment_updb_test.go +++ b/tests/enrollment_updb_test.go @@ -117,7 +117,7 @@ func Test_EnrollmentUpdb(t *testing.T) { updbApiSession, err := updbAuth.AuthenticateClientApi(ctx) ctx.Req.NoError(err) ctx.Req.NotEmpty(updbApiSession) - ctx.Req.NotEmpty(updbApiSession.token) + ctx.Req.NotEmpty(updbApiSession.AuthResponse.Token) t.Run("authenticated updb api session can query current api session", func(t *testing.T) { ctx.testContextChanged(t) diff --git a/tests/entities.go b/tests/entities.go index 210ecf47d..245c16420 100644 --- a/tests/entities.go +++ b/tests/entities.go @@ -26,7 +26,7 @@ import ( "crypto/x509/pkix" "encoding/pem" "github.com/openziti/edge/eid" - "github.com/openziti/sdk-golang/ziti/config" + "github.com/openziti/sdk-golang/ziti" "math/big" "sort" "time" @@ -261,7 +261,7 @@ type identity struct { defaultHostingCost int serviceHostingPrecedences map[string]interface{} serviceHostingCosts map[string]uint16 - config *config.Config + config *ziti.Config authPolicyId string } diff --git a/tests/external_jwt_signer_test.go b/tests/external_jwt_signer_test.go index 3be146059..6de2d7c03 100644 --- a/tests/external_jwt_signer_test.go +++ b/tests/external_jwt_signer_test.go @@ -20,17 +20,10 @@ package tests import ( - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/x509" - "crypto/x509/pkix" "github.com/google/uuid" "github.com/openziti/edge-api/rest_model" "github.com/openziti/edge/controller/persistence" nfpem "github.com/openziti/foundation/v2/pem" - "math/big" "net/http" "testing" "time" @@ -724,35 +717,3 @@ func Test_ExternalJWTSigner(t *testing.T) { }) }) } - -func newSelfSignedCert(commonName string) (*x509.Certificate, crypto.PrivateKey) { - priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - panic(err) - } - template := x509.Certificate{ - SerialNumber: big.NewInt(1), - Subject: pkix.Name{ - CommonName: commonName, - Organization: []string{"API Test Co"}, - }, - NotBefore: time.Now(), - NotAfter: time.Now().Add(time.Hour * 24 * 180), - - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, - BasicConstraintsValid: true, - } - - der, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) - if err != nil { - panic(err) - } - cert, err := x509.ParseCertificate(der) - - if err != nil { - panic(err) - } - - return cert, priv -} diff --git a/tests/identity_test.go b/tests/identity_test.go index 536b287f9..62ed15440 100644 --- a/tests/identity_test.go +++ b/tests/identity_test.go @@ -586,7 +586,7 @@ func Test_Identity(t *testing.T) { apiSession, err := certAuthenticator.AuthenticateClientApi(ctx) ctx.Req.NoError(err) ctx.Req.NotNil(apiSession) - ctx.Req.NotEmpty(apiSession.token) + ctx.Req.NotEmpty(apiSession.AuthResponse.Token) t.Run("identity can be disabled", func(t *testing.T) { ctx.testContextChanged(t) diff --git a/tests/mfa_ziti_test.go b/tests/mfa_ziti_test.go index 2e0b34d07..93ada8ed7 100644 --- a/tests/mfa_ziti_test.go +++ b/tests/mfa_ziti_test.go @@ -461,7 +461,7 @@ func Test_MFA(t *testing.T) { t.Run("api session should have posture data with MFA passed", func(t *testing.T) { ctx.testContextChanged(t) postureDataContainer := ctx.AdminManagementSession.requireQuery(fmt.Sprintf("/identities/%s/posture-data", mfaValidatedIdentityId)) - mfaPath := fmt.Sprintf("data.apiSessionPostureData.%s.mfa.passedMfa", mfaValidatedSession.id) + mfaPath := fmt.Sprintf("data.apiSessionPostureData.%s.mfa.passedMfa", *mfaValidatedSession.AuthResponse.ID) postureDataContainer.ExistsP(mfaPath) isMfaPassed, ok := postureDataContainer.Path(mfaPath).Data().(bool) ctx.Req.True(ok, "should be a bool") @@ -687,8 +687,8 @@ func Test_MFA(t *testing.T) { t.Run("api session should have posture data with MFA passed", func(t *testing.T) { ctx.testContextChanged(t) - postureDataContainer := ctx.AdminManagementSession.requireQuery(fmt.Sprintf("/identities/%s/posture-data", newValidatedSession.identityId)) - mfaPath := fmt.Sprintf("data.apiSessionPostureData.%s.mfa.passedMfa", newValidatedSession.id) + postureDataContainer := ctx.AdminManagementSession.requireQuery(fmt.Sprintf("/identities/%s/posture-data", *newValidatedSession.AuthResponse.IdentityID)) + mfaPath := fmt.Sprintf("data.apiSessionPostureData.%s.mfa.passedMfa", *newValidatedSession.AuthResponse.ID) postureDataContainer.ExistsP(mfaPath) isMfaPassed, ok := postureDataContainer.Path(mfaPath).Data().(bool) ctx.Req.True(ok, "should be a bool") @@ -800,8 +800,8 @@ func Test_MFA(t *testing.T) { t.Run("api session should have posture data with MFA passed", func(t *testing.T) { ctx.testContextChanged(t) - postureDataContainer := ctx.AdminManagementSession.requireQuery(fmt.Sprintf("/identities/%s/posture-data", newValidatedSession.identityId)) - mfaPath := fmt.Sprintf("data.apiSessionPostureData.%s.mfa.passedMfa", newValidatedSession.id) + postureDataContainer := ctx.AdminManagementSession.requireQuery(fmt.Sprintf("/identities/%s/posture-data", *newValidatedSession.AuthResponse.IdentityID)) + mfaPath := fmt.Sprintf("data.apiSessionPostureData.%s.mfa.passedMfa", *newValidatedSession.AuthResponse.ID) postureDataContainer.ExistsP(mfaPath) isMfaPassed, ok := postureDataContainer.Path(mfaPath).Data().(bool) ctx.Req.True(ok, "should be a bool") @@ -1048,7 +1048,7 @@ func Test_MFA(t *testing.T) { t.Run("with an empty code it should fail", func(s *testing.T) { ctx.testContextChanged(t) - resp, err := mfa02DeleteSession.newAuthenticatedRequest().SetBody(newMfaCodeBody("")).Delete("/current-identity/mfa") + resp, err := mfa02DeleteSession.newAuthenticatedRequest().Delete("/current-identity/mfa") ctx.Req.NoError(err) standardErrorJsonResponseTests(resp, apierror.MfaInvalidTokenCode, http.StatusBadRequest, t) @@ -1056,7 +1056,7 @@ func Test_MFA(t *testing.T) { t.Run("with an invalid code it should fail", func(s *testing.T) { ctx.testContextChanged(t) - resp, err := mfa02DeleteSession.newAuthenticatedRequest().SetBody(newMfaCodeBody("456456465")).Delete("/current-identity/mfa") + resp, err := mfa02DeleteSession.newAuthenticatedRequest().SetHeader("mfa-validation-code", "44444").Delete("/current-identity/mfa") ctx.Req.NoError(err) standardErrorJsonResponseTests(resp, apierror.MfaInvalidTokenCode, http.StatusBadRequest, t) @@ -1067,7 +1067,7 @@ func Test_MFA(t *testing.T) { code := computeMFACode(mfa02DeleteSecret) - resp, err := mfa02DeleteSession.newAuthenticatedRequest().SetBody(newMfaCodeBody(code)).Delete("/current-identity/mfa") + resp, err := mfa02DeleteSession.newAuthenticatedRequest().SetHeader("mfa-validation-code", code).Delete("/current-identity/mfa") ctx.Req.NoError(err) standardJsonResponseTests(resp, http.StatusOK, t) diff --git a/tests/model_sdk_performance_test.go b/tests/model_sdk_performance_test.go index b2fbc0a4b..b0c6a0a8e 100644 --- a/tests/model_sdk_performance_test.go +++ b/tests/model_sdk_performance_test.go @@ -7,16 +7,18 @@ import ( "fmt" "github.com/google/uuid" "github.com/michaelquigley/pfxlog" + "github.com/openziti/edge-api/rest_client_api_client/current_api_session" + service2 "github.com/openziti/edge-api/rest_client_api_client/service" + apiClientSession "github.com/openziti/edge-api/rest_client_api_client/session" + "github.com/openziti/edge-api/rest_model" "github.com/openziti/edge/controller/model" "github.com/openziti/edge/controller/persistence" "github.com/openziti/edge/eid" "github.com/openziti/fabric/controller/models" "github.com/openziti/foundation/v2/errorz" idloader "github.com/openziti/identity" - "github.com/openziti/sdk-golang/ziti/config" - "github.com/openziti/sdk-golang/ziti/edge" - "github.com/openziti/sdk-golang/ziti/edge/api" - "github.com/openziti/sdk-golang/ziti/sdkinfo" + edge_apis "github.com/openziti/sdk-golang/edge-apis" + "github.com/openziti/sdk-golang/ziti" "github.com/rcrowley/go-metrics" "io" "net/url" @@ -141,7 +143,7 @@ type perfScenarioSpec struct { identities []*model.Identity edgeRouters []*model.EdgeRouter - config *config.Config + config *ziti.Config } func (spec *perfScenarioSpec) generateAllRoleAttributes() { @@ -200,10 +202,10 @@ func (ctx *modelPerf) runScenario(spec *perfScenarioSpec) { ctx.createScenario(spec) - stats := newPerfStats(ctx.TestContext, spec.config, spec.name, spec.services[0].Id, edge.SessionDial) + stats := newPerfStats(ctx.TestContext, spec.config, spec.name, spec.services[0].Id, rest_model.DialBindDial) stats.collectStats(10) - stats = newPerfStats(ctx.TestContext, spec.config, spec.name, spec.services[0].Id, edge.SessionDial) + stats = newPerfStats(ctx.TestContext, spec.config, spec.name, spec.services[0].Id, rest_model.DialBindBind) stats.collectStats(10) ctx.Teardown() @@ -428,22 +430,29 @@ func newHistogram() metrics.Histogram { return metrics.NewHistogram(metrics.NewExpDecaySample(128, 0.015)) } -func newPerfStats(ctx *TestContext, config *config.Config, description string, serviceId string, sessionType edge.SessionType) *perfStats { +func newPerfStats(ctx *TestContext, config *ziti.Config, description string, serviceId string, sessionType rest_model.DialBind) *perfStats { zitiUrl, err := url.Parse(config.ZtAPI) ctx.Req.NoError(err) id, err := idloader.LoadIdentity(config.ID) ctx.Req.NoError(err) - client, err := api.NewClient(zitiUrl, id.ClientTLSConfig(), s("all")) + creds := edge_apis.NewIdentityCredentials(id) + creds.ConfigTypes = []string{"all"} + + caPool, err := ziti.GetControllerWellKnownCaPool(config.ZtAPI) + ctx.Req.NoError(err) + client := edge_apis.NewClientApiClient(zitiUrl, caPool) + return &perfStats{ TestContext: ctx, client: client, description: description, serviceId: serviceId, sessionType: sessionType, + credentials: creds, createApiSession: newHistogram(), refreshApiSession: newHistogram(), getServices: newHistogram(), @@ -456,14 +465,15 @@ type perfStats struct { *TestContext description string serviceId string - client api.RestClient - sessionType edge.SessionType + client *edge_apis.ClientApiClient + sessionType rest_model.DialBind sessionId string createApiSession metrics.Histogram refreshApiSession metrics.Histogram getServices metrics.Histogram createSession metrics.Histogram refreshSession metrics.Histogram + credentials *edge_apis.IdentityCredentials } func (s *perfStats) dumpStatsToStdOut() { @@ -497,7 +507,6 @@ func (s *perfStats) collectStats(iterations int) { s.repeat(iterations, s.timeRefreshApiSession) s.repeat(iterations, s.timeGetServices) s.repeat(iterations, s.timeCreateSession) - s.repeat(iterations, s.timeRefreshSession) } func (s *perfStats) repeat(n int, f func()) { @@ -514,38 +523,44 @@ func (s *perfStats) time(h metrics.Histogram, f func()) { func (s *perfStats) timeCreateApiSession() { s.time(s.createApiSession, func() { - info := sdkinfo.GetSdkInfo() - _, err := s.client.Login(info) + _, err := s.client.Authenticate(s.credentials) s.Req.NoError(err) }) } func (s *perfStats) timeRefreshApiSession() { s.time(s.createApiSession, func() { - _, err := s.client.Refresh() + params := current_api_session.NewGetCurrentAPISessionParams() + _, err := s.client.API.CurrentAPISession.GetCurrentAPISession(params, nil) s.Req.NoError(err) }) } func (s *perfStats) timeGetServices() { s.time(s.getServices, func() { - _, err := s.client.GetServices() + params := service2.NewListServicesParams() + params.Limit = I(500) + _, err := s.client.API.Service.ListServices(params, nil) s.Req.NoError(err) }) } func (s *perfStats) timeCreateSession() { s.time(s.createSession, func() { - session, err := s.client.CreateSession(s.serviceId, s.sessionType) - s.Req.NoError(err) - s.sessionId = session.Id - }) -} + //session, err := s.client.CreateSession(s.serviceId, s.sessionType) -func (s *perfStats) timeRefreshSession() { - s.time(s.createSession, func() { - _, err := s.client.RefreshSession(s.sessionId) - s.Req.NoError(err) + params := apiClientSession.NewCreateSessionParams() + params.Session = &rest_model.SessionCreate{} + params.Session.Type = s.sessionType + params.Session.ServiceID = s.serviceId + + sessionDetail, err := s.client.API.Session.CreateSession(params, nil) + + if err != nil { + s.Req.NoError(err) + } + + s.sessionId = *sessionDetail.Payload.Data.ID }) } diff --git a/tests/posture_check_mfa_test.go b/tests/posture_check_mfa_test.go index ac6d3b2ab..f777c10fb 100644 --- a/tests/posture_check_mfa_test.go +++ b/tests/posture_check_mfa_test.go @@ -144,7 +144,7 @@ func Test_PostureChecks_MFA(t *testing.T) { t.Run("failed service request exist", func(t *testing.T) { ctx.testContextChanged(t) - resp, err := ctx.AdminManagementSession.newAuthenticatedRequest().Get("/identities/" + enrolledIdentitySession.identityId + "/failed-service-requests") + resp, err := ctx.AdminManagementSession.newAuthenticatedRequest().Get("/identities/" + *enrolledIdentitySession.AuthResponse.IdentityID + "/failed-service-requests") ctx.Req.NoError(err) listEnvelop := rest_model.FailedServiceRequestEnvelope{} @@ -284,7 +284,7 @@ func Test_PostureChecks_MFA(t *testing.T) { t.Run("removing MFA while the service requires MFA", func(t *testing.T) { ctx.testContextChanged(t) - resp, err := newSession.newAuthenticatedRequest().SetBody(newMfaCodeBody(computeMFACode(mfaSecret))).Delete("/current-identity/mfa") + resp, err := newSession.newAuthenticatedRequest().SetHeader("mfa-validation-code", computeMFACode(mfaSecret)).Delete("/current-identity/mfa") ctx.Req.NoError(err) ctx.Req.Equal(http.StatusOK, resp.StatusCode()) @@ -416,7 +416,7 @@ func Test_PostureChecks_MFA(t *testing.T) { t.Run("failed service request exist", func(t *testing.T) { ctx.testContextChanged(t) - resp, err := ctx.AdminManagementSession.newAuthenticatedRequest().Get("/identities/" + enrolledIdentitySession.identityId + "/failed-service-requests") + resp, err := ctx.AdminManagementSession.newAuthenticatedRequest().Get("/identities/" + *enrolledIdentitySession.AuthResponse.IdentityID + "/failed-service-requests") ctx.Req.NoError(err) listEnvelop := &rest_model.FailedServiceRequestEnvelope{} diff --git a/tests/posture_check_session_test.go b/tests/posture_check_session_test.go index 26fe79ffe..d2e4742d3 100644 --- a/tests/posture_check_session_test.go +++ b/tests/posture_check_session_test.go @@ -56,7 +56,7 @@ func Test_PostureChecks_Sessions(t *testing.T) { listener, err := hostContext.Listen(service.Name) ctx.Req.NoError(err) - defer listener.Close() + defer func() { _ = listener.Close() }() testServer := newTestServer(listener, func(conn *testServerConn) error { for { @@ -79,14 +79,14 @@ func Test_PostureChecks_Sessions(t *testing.T) { t.Run("a client sdk", func(t *testing.T) { ctx.testContextChanged(t) - var clientContext *ziti.ContextImplTest + var clientContext *ziti.ContextImpl t.Run("can be created", func(t *testing.T) { ctx.testContextChanged(t) _, ztx := ctx.AdminManagementSession.RequireCreateSdkContext(dialIdentityRole) - clientContext = &ziti.ContextImplTest{ - Context: ztx, - } + var ok bool + clientContext, ok = ztx.(*ziti.ContextImpl) + ctx.Req.True(ok) }) defer clientContext.Close() @@ -99,7 +99,7 @@ func Test_PostureChecks_Sessions(t *testing.T) { t.Run("can provide valid posture data and dial the service", func(t *testing.T) { ctx.testContextChanged(t) - postureCache, err := clientContext.GetPostureCache() + postureCache := clientContext.CtrlClt.PostureCache ctx.Req.NoError(err) currentPostureDomain := dialDomain @@ -108,7 +108,7 @@ func Test_PostureChecks_Sessions(t *testing.T) { } clientConn := ctx.WrapConn(clientContext.Dial(service.Name)) - defer clientConn.Close() + defer func() { _ = clientConn.Close() }() t.Run("the dialed service can be sent data", func(t *testing.T) { ctx.testContextChanged(t) diff --git a/tests/sdk_auth_test.go b/tests/sdk_auth_test.go new file mode 100644 index 000000000..4abe1bbfa --- /dev/null +++ b/tests/sdk_auth_test.go @@ -0,0 +1,278 @@ +package tests + +import ( + "crypto/x509" + "github.com/golang-jwt/jwt" + "github.com/google/uuid" + "github.com/openziti/edge-api/rest_management_api_client/auth_policy" + "github.com/openziti/edge-api/rest_management_api_client/external_jwt_signer" + identity2 "github.com/openziti/edge-api/rest_management_api_client/identity" + "github.com/openziti/edge-api/rest_model" + nfpem "github.com/openziti/foundation/v2/pem" + edge_apis "github.com/openziti/sdk-golang/edge-apis" + "net/url" + "testing" + "time" +) + +func TestSdkAuth(t *testing.T) { + ctx := NewTestContext(t) + defer ctx.Teardown() + ctx.StartServer() + + ctx.RequireAdminManagementApiLogin() + testId := ctx.AdminManagementSession.RequireNewIdentityWithOtt(true) + testIdCerts := ctx.completeOttEnrollment(testId.Id) + + clientApiUrl, err := url.Parse("https://" + ctx.ApiHost + EdgeClientApiPath) + ctx.Req.NoError(err) + + managementApiUrl, err := url.Parse("https://" + ctx.ApiHost + EdgeManagementApiPath) + ctx.Req.NoError(err) + + adminCreds := edge_apis.NewUpdbCredentials(ctx.AdminAuthenticator.Username, ctx.AdminAuthenticator.Password) + adminClient := edge_apis.NewManagementApiClient(managementApiUrl, ctx.ControllerConfig.Id.CA()) + apiSession, err := adminClient.Authenticate(adminCreds) + + t.Run("management updb", func(t *testing.T) { + ctx.testContextChanged(t) + + ctx.Req.NoError(err) + ctx.Req.NotNil(adminClient) + ctx.Req.NotNil(apiSession) + ctx.Req.NotNil(apiSession.Token) + }) + + t.Run("client updb, ca pool on client", func(t *testing.T) { + ctx.testContextChanged(t) + + creds := edge_apis.NewUpdbCredentials(ctx.AdminAuthenticator.Username, ctx.AdminAuthenticator.Password) + client := edge_apis.NewClientApiClient(clientApiUrl, ctx.ControllerConfig.Id.CA()) + apiSession, err := client.Authenticate(creds) + + ctx.Req.NoError(err) + ctx.Req.NotNil(client) + ctx.Req.NotNil(apiSession) + ctx.Req.NotNil(apiSession.Token) + }) + + t.Run("client updb, ca pool on cert", func(t *testing.T) { + ctx.testContextChanged(t) + + creds := edge_apis.NewUpdbCredentials(ctx.AdminAuthenticator.Username, ctx.AdminAuthenticator.Password) + creds.CaPool = ctx.ControllerConfig.Id.CA() + + client := edge_apis.NewClientApiClient(clientApiUrl, nil) + apiSession, err := client.Authenticate(creds) + + ctx.Req.NoError(err) + ctx.Req.NotNil(client) + ctx.Req.NotNil(apiSession) + ctx.Req.NotNil(apiSession.Token) + }) + + t.Run("management cert, ca pool on client", func(t *testing.T) { + ctx.testContextChanged(t) + + creds := edge_apis.NewCertCredentials([]*x509.Certificate{testIdCerts.cert}, testIdCerts.key) + client := edge_apis.NewManagementApiClient(managementApiUrl, ctx.ControllerConfig.Id.CA()) + apiSession, err := client.Authenticate(creds) + + ctx.Req.NoError(err) + ctx.Req.NotNil(client) + ctx.Req.NotNil(apiSession) + ctx.Req.NotNil(apiSession.Token) + }) + + t.Run("management cert, ca pool on cert", func(t *testing.T) { + ctx.testContextChanged(t) + + creds := edge_apis.NewCertCredentials([]*x509.Certificate{testIdCerts.cert}, testIdCerts.key) + creds.CaPool = ctx.ControllerConfig.Id.CA() + + client := edge_apis.NewManagementApiClient(managementApiUrl, nil) + apiSession, err := client.Authenticate(creds) + + ctx.Req.NoError(err) + ctx.Req.NotNil(client) + ctx.Req.NotNil(apiSession) + ctx.Req.NotNil(apiSession.Token) + }) + + t.Run("client cert, ca pool on client", func(t *testing.T) { + ctx.testContextChanged(t) + + creds := edge_apis.NewCertCredentials([]*x509.Certificate{testIdCerts.cert}, testIdCerts.key) + + client := edge_apis.NewClientApiClient(clientApiUrl, ctx.ControllerConfig.Id.CA()) + apiSession, err := client.Authenticate(creds) + + ctx.Req.NoError(err) + ctx.Req.NotNil(client) + ctx.Req.NotNil(apiSession) + ctx.Req.NotNil(apiSession.Token) + }) + + t.Run("client cert, ca pool on creds", func(t *testing.T) { + ctx.testContextChanged(t) + + creds := edge_apis.NewCertCredentials([]*x509.Certificate{testIdCerts.cert}, testIdCerts.key) + creds.CaPool = ctx.ControllerConfig.Id.CA() + + client := edge_apis.NewClientApiClient(clientApiUrl, nil) + apiSession, err := client.Authenticate(creds) + + ctx.Req.NoError(err) + ctx.Req.NotNil(client) + ctx.Req.NotNil(apiSession) + ctx.Req.NotNil(apiSession.Token) + }) + + t.Run("ext jwt signer", func(t *testing.T) { + ctx.testContextChanged(t) + + //valid signer with issuer and audience + validJwtSignerCert, validJwtSignerPrivateKey := newSelfSignedCert("valid signer") + validJwtSignerCertPem := nfpem.EncodeToString(validJwtSignerCert) + + validJwtSigner := &rest_model.ExternalJWTSignerCreate{ + CertPem: &validJwtSignerCertPem, + Enabled: B(true), + Name: S("Test JWT Signer - Enabled"), + Kid: S(uuid.NewString()), + Issuer: S("the-very-best-iss"), + Audience: S("the-very-best-aud"), + UseExternalID: B(true), + } + + //valid signed jwt + subjectId := uuid.NewString() + jwtToken := jwt.New(jwt.SigningMethodES256) + jwtToken.Claims = jwt.StandardClaims{ + Audience: *validJwtSigner.Audience, + ExpiresAt: time.Now().Add(2 * time.Hour).Unix(), + Id: time.Now().String(), + IssuedAt: time.Now().Unix(), + Issuer: *validJwtSigner.Issuer, + NotBefore: time.Now().Unix(), + Subject: subjectId, + } + + jwtToken.Header["kid"] = *validJwtSigner.Kid + + jwtStrSigned, err := jwtToken.SignedString(validJwtSignerPrivateKey) + ctx.Req.NoError(err) + ctx.Req.NotEmpty(jwtStrSigned) + + // ext jwt + createExtJwtParams := external_jwt_signer.NewCreateExternalJWTSignerParams() + createExtJwtParams.ExternalJWTSigner = validJwtSigner + + createExtJwtSignerResp, err := adminClient.API.ExternalJWTSigner.CreateExternalJWTSigner(createExtJwtParams, nil) + ctx.Req.NoError(err) + ctx.Req.NotNil(createExtJwtSignerResp) + ctx.Req.NotEmpty(createExtJwtSignerResp.Payload.Data.ID) + + //auth policy + authPolicyCreate := &rest_model.AuthPolicyCreate{ + Name: S(uuid.NewString()), + Primary: &rest_model.AuthPolicyPrimary{ + Cert: &rest_model.AuthPolicyPrimaryCert{Allowed: B(false), AllowExpiredCerts: B(false)}, + ExtJWT: &rest_model.AuthPolicyPrimaryExtJWT{Allowed: B(true), AllowedSigners: []string{createExtJwtSignerResp.Payload.Data.ID}}, + Updb: &rest_model.AuthPolicyPrimaryUpdb{ + Allowed: B(false), + LockoutDurationMinutes: I(0), + MaxAttempts: I(0), + MinPasswordLength: I(5), + RequireMixedCase: B(true), + RequireNumberChar: B(true), + RequireSpecialChar: B(true), + }, + }, + Secondary: &rest_model.AuthPolicySecondary{ + RequireExtJWTSigner: nil, + RequireTotp: B(false), + }, + Tags: &rest_model.Tags{SubTags: rest_model.SubTags{}}, + } + + authPolicyCreateParams := auth_policy.NewCreateAuthPolicyParams() + authPolicyCreateParams.AuthPolicy = authPolicyCreate + + createAuthPolicyResp, err := adminClient.API.AuthPolicy.CreateAuthPolicy(authPolicyCreateParams, nil) + ctx.Req.NoError(err) + ctx.Req.NotNil(createAuthPolicyResp) + ctx.Req.NotEmpty(createAuthPolicyResp.Payload.Data.ID) + + //identity + identityType := rest_model.IdentityTypeUser + idCreate := &rest_model.IdentityCreate{ + AuthPolicyID: S(createAuthPolicyResp.Payload.Data.ID), + ExternalID: S(subjectId), + IsAdmin: B(false), + Name: S(uuid.NewString()), + Type: &identityType, + } + + identityCreateParams := identity2.NewCreateIdentityParams() + identityCreateParams.Identity = idCreate + + idCreateResp, err := adminClient.API.Identity.CreateIdentity(identityCreateParams, nil) + ctx.Req.NoError(err) + ctx.Req.NotNil(idCreateResp) + ctx.Req.NotEmpty(idCreateResp.Payload.Data.ID) + + t.Run("client jwt, ca pool on client", func(t *testing.T) { + ctx.testContextChanged(t) + creds := edge_apis.NewJwtCredentials(jwtStrSigned) + client := edge_apis.NewClientApiClient(clientApiUrl, ctx.ControllerConfig.Id.CA()) + apiSession, err := client.Authenticate(creds) + + ctx.Req.NoError(err) + ctx.Req.NotNil(client) + ctx.Req.NotNil(apiSession) + ctx.Req.NotNil(apiSession.Token) + }) + + t.Run("client jwt, ca pool on creds", func(t *testing.T) { + ctx.testContextChanged(t) + creds := edge_apis.NewJwtCredentials(jwtStrSigned) + creds.CaPool = ctx.ControllerConfig.Id.CA() + + client := edge_apis.NewClientApiClient(clientApiUrl, nil) + apiSession, err := client.Authenticate(creds) + + ctx.Req.NoError(err) + ctx.Req.NotNil(client) + ctx.Req.NotNil(apiSession) + ctx.Req.NotNil(apiSession.Token) + }) + + t.Run("management jwt, ca pool on client", func(t *testing.T) { + ctx.testContextChanged(t) + creds := edge_apis.NewJwtCredentials(jwtStrSigned) + client := edge_apis.NewManagementApiClient(managementApiUrl, ctx.ControllerConfig.Id.CA()) + apiSession, err := client.Authenticate(creds) + + ctx.Req.NoError(err) + ctx.Req.NotNil(client) + ctx.Req.NotNil(apiSession) + ctx.Req.NotNil(apiSession.Token) + }) + + t.Run("management jwt, ca pool on creds", func(t *testing.T) { + ctx.testContextChanged(t) + creds := edge_apis.NewJwtCredentials(jwtStrSigned) + creds.CaPool = ctx.ControllerConfig.Id.CA() + + client := edge_apis.NewManagementApiClient(managementApiUrl, nil) + apiSession, err := client.Authenticate(creds) + + ctx.Req.NoError(err) + ctx.Req.NotNil(client) + ctx.Req.NotNil(apiSession) + ctx.Req.NotNil(apiSession.Token) + }) + }) + +} diff --git a/tests/service_list_refresh_test.go b/tests/service_list_refresh_test.go index 96363115e..26568af07 100644 --- a/tests/service_list_refresh_test.go +++ b/tests/service_list_refresh_test.go @@ -16,7 +16,7 @@ func setupServiceListRefreshTest(ctx *TestContext) (string, *identity, *session) ctx.Req.NoError(err) lastUpdate := nonAdminUserSession.getServiceUpdateTime() - ctx.Req.Equal(nonAdminUserSession.createdAt, lastUpdate) + ctx.Req.Equal(time.Time(*nonAdminUserSession.AuthResponse.CreatedAt), lastUpdate) nonAdminUserSession.requireServiceUpdateTimeUnchanged() diff --git a/tests/service_test.go b/tests/service_test.go index 2df8c6c91..330b91639 100644 --- a/tests/service_test.go +++ b/tests/service_test.go @@ -268,14 +268,14 @@ func Test_ServiceListWithConfigs(t *testing.T) { } configs1 := []serviceConfig{{ServiceId: service4.Id, ConfigId: config1.Id}, {ServiceId: service4.Id, ConfigId: config5.Id}} - ctx.AdminManagementSession.requireAssignIdentityServiceConfigs(session.identityId, configs1...) + ctx.AdminManagementSession.requireAssignIdentityServiceConfigs(*session.AuthResponse.IdentityID, configs1...) configs1 = []serviceConfig{{ServiceId: service4.Id, ConfigId: config1.Id}, {ServiceId: service4.Id, ConfigId: config5.Id}} sort.Sort(sortableServiceConfigSlice(configs1)) - currentConfigs := ctx.AdminManagementSession.listIdentityServiceConfigs(session.identityId) + currentConfigs := ctx.AdminManagementSession.listIdentityServiceConfigs(*session.AuthResponse.IdentityID) ctx.Req.Equal(configs1, currentConfigs) configs2 := []serviceConfig{{ServiceId: service1.Id, ConfigId: config5.Id}, {ServiceId: service3.Id, ConfigId: config1.Id}, {ServiceId: service3.Id, ConfigId: config4.Id}} - ctx.AdminManagementSession.requireAssignIdentityServiceConfigs(session.identityId, configs2...) + ctx.AdminManagementSession.requireAssignIdentityServiceConfigs(*session.AuthResponse.IdentityID, configs2...) checkConfigs := []serviceConfig{ {ServiceId: service4.Id, ConfigId: config1.Id}, {ServiceId: service4.Id, ConfigId: config5.Id}, @@ -284,7 +284,7 @@ func Test_ServiceListWithConfigs(t *testing.T) { {ServiceId: service3.Id, ConfigId: config4.Id}, } sort.Sort(sortableServiceConfigSlice(checkConfigs)) - currentConfigs = ctx.AdminManagementSession.listIdentityServiceConfigs(session.identityId) + currentConfigs = ctx.AdminManagementSession.listIdentityServiceConfigs(*session.AuthResponse.IdentityID) ctx.Req.Equal(checkConfigs, currentConfigs) service1V.configs[configType3.Name] = config5 @@ -297,8 +297,8 @@ func Test_ServiceListWithConfigs(t *testing.T) { service.configs = map[string]*Config{} } - ctx.AdminManagementSession.requireRemoveIdentityServiceConfigs(session.identityId, serviceConfig{ServiceId: service1.Id, ConfigId: config5.Id}, serviceConfig{ServiceId: service3.Id, ConfigId: config1.Id}) - currentConfigs = ctx.AdminManagementSession.listIdentityServiceConfigs(session.identityId) + ctx.AdminManagementSession.requireRemoveIdentityServiceConfigs(*session.AuthResponse.IdentityID, serviceConfig{ServiceId: service1.Id, ConfigId: config5.Id}, serviceConfig{ServiceId: service3.Id, ConfigId: config1.Id}) + currentConfigs = ctx.AdminManagementSession.listIdentityServiceConfigs(*session.AuthResponse.IdentityID) checkConfigs = []serviceConfig{ {ServiceId: service4.Id, ConfigId: config1.Id}, {ServiceId: service4.Id, ConfigId: config5.Id}, @@ -317,8 +317,8 @@ func Test_ServiceListWithConfigs(t *testing.T) { service.configs = map[string]*Config{} } - ctx.AdminManagementSession.requireRemoveIdentityServiceConfigs(session.identityId) - currentConfigs = ctx.AdminManagementSession.listIdentityServiceConfigs(session.identityId) + ctx.AdminManagementSession.requireRemoveIdentityServiceConfigs(*session.AuthResponse.IdentityID) + currentConfigs = ctx.AdminManagementSession.listIdentityServiceConfigs(*session.AuthResponse.IdentityID) ctx.Req.Equal(0, len(currentConfigs)) service2V.configs[configType1.Name] = config1 diff --git a/tunnel/entities/service.go b/tunnel/entities/service.go index d223a08b0..8e14d9fee 100644 --- a/tunnel/entities/service.go +++ b/tunnel/entities/service.go @@ -3,11 +3,12 @@ package entities import ( "fmt" "github.com/michaelquigley/pfxlog" + "github.com/mitchellh/mapstructure" + "github.com/openziti/edge-api/rest_model" "github.com/openziti/edge/health" "github.com/openziti/edge/tunnel" "github.com/openziti/edge/tunnel/utils" "github.com/openziti/foundation/v2/stringz" - "github.com/openziti/sdk-golang/ziti/edge" "github.com/pkg/errors" "net" "reflect" @@ -358,7 +359,7 @@ type TemplateFunc func(sourceAddr net.Addr, destAddr net.Addr) string type Service struct { FabricProvider tunnel.FabricProvider - edge.Service + rest_model.ServiceDetail InterceptV1Config *InterceptV1Config DialTimeout time.Duration @@ -369,6 +370,23 @@ type Service struct { lock sync.Mutex } +func (self *Service) GetConfigOfType(configType string, target interface{}) (bool, error) { + if self.Configs == nil { + pfxlog.Logger().Debugf("no service configs defined for service %v", self.Name) + return false, nil + } + configMap, found := self.Config[configType] + if !found { + pfxlog.Logger().Debugf("no service config of type %v defined for service %v", configType, self.Name) + return false, nil + } + if err := mapstructure.Decode(configMap, target); err != nil { + pfxlog.Logger().WithError(err).Debugf("unable to decode service configuration for of type %v defined for service %v", configType, self.Name) + return true, fmt.Errorf("unable to decode service config structure: %w", err) + } + return true, nil +} + func (self *Service) GetFabricProvider() tunnel.FabricProvider { return self.FabricProvider } @@ -398,7 +416,7 @@ func (self *Service) GetSourceAddr(sourceAddr net.Addr, destAddr net.Addr) strin } func (self *Service) GetName() string { - return self.Name + return *self.ServiceDetail.Name } func (self *Service) GetDialTimeout() time.Duration { diff --git a/tunnel/intercept/hosting.go b/tunnel/intercept/hosting.go index 01860f640..533d19aa5 100644 --- a/tunnel/intercept/hosting.go +++ b/tunnel/intercept/hosting.go @@ -18,13 +18,13 @@ package intercept import ( "github.com/michaelquigley/pfxlog" + "github.com/openziti/edge-api/rest_model" "github.com/openziti/edge/health" "github.com/openziti/edge/tunnel" "github.com/openziti/edge/tunnel/entities" "github.com/openziti/edge/tunnel/router" "github.com/openziti/edge/tunnel/utils" "github.com/openziti/sdk-golang/ziti" - "github.com/openziti/sdk-golang/ziti/edge" "github.com/pkg/errors" "net" "strconv" @@ -37,7 +37,7 @@ type healthChecksProvider interface { GetHttpChecks() []*health.HttpCheckDefinition } -func createHostingContexts(service *entities.Service, identity *edge.CurrentIdentity, tracker AddressTracker) []tunnel.HostingContext { +func createHostingContexts(service *entities.Service, identity *rest_model.IdentityDetail, tracker AddressTracker) []tunnel.HostingContext { var result []tunnel.HostingContext for _, t := range service.HostV2Config.Terminators { context := newDefaultHostingContext(identity, service, t, tracker) @@ -52,7 +52,7 @@ func createHostingContexts(service *entities.Service, identity *edge.CurrentIden return result } -func newDefaultHostingContext(identity *edge.CurrentIdentity, service *entities.Service, config *entities.HostV2Terminator, tracker AddressTracker) *hostingContext { +func newDefaultHostingContext(identity *rest_model.IdentityDetail, service *entities.Service, config *entities.HostV2Terminator, tracker AddressTracker) *hostingContext { log := pfxlog.Logger().WithField("service", service.Name) if config.ForwardProtocol && len(config.AllowedProtocols) < 1 { @@ -111,7 +111,7 @@ type hostingContext struct { } func (self *hostingContext) ServiceName() string { - return self.service.Name + return *self.service.Name } func (self *hostingContext) ListenOptions() *ziti.ListenOptions { @@ -229,11 +229,11 @@ func (self *hostingContext) Dial(options map[string]interface{}) (net.Conn, bool return self.dialAddress(options, protocol, address+":"+port) } -func getDefaultOptions(service *entities.Service, identity *edge.CurrentIdentity, config *entities.HostV2Terminator) (*ziti.ListenOptions, error) { +func getDefaultOptions(service *entities.Service, identity *rest_model.IdentityDetail, config *entities.HostV2Terminator) (*ziti.ListenOptions, error) { options := ziti.DefaultListenOptions() options.ManualStart = true - options.Precedence = ziti.GetPrecedenceForLabel(identity.DefaultHostingPrecedence) - options.Cost = identity.DefaultHostingCost + options.Precedence = ziti.GetPrecedenceForLabel(string(identity.DefaultHostingPrecedence)) + options.Cost = uint16(*identity.DefaultHostingCost) if config.ListenOptions != nil { if config.ListenOptions.Cost != nil { @@ -244,21 +244,17 @@ func getDefaultOptions(service *entities.Service, identity *edge.CurrentIdentity } } - if val, ok := identity.ServiceHostingPrecedences[service.Id]; ok { - if strVal, ok := val.(string); ok { - options.Precedence = ziti.GetPrecedenceForLabel(strVal) - } + if val, ok := identity.ServiceHostingPrecedences[*service.ID]; ok { + options.Precedence = ziti.GetPrecedenceForLabel(string(val)) } - if val, ok := identity.ServiceHostingCosts[service.Id]; ok { - if floatVal, ok := val.(float64); ok { - options.Cost = uint16(floatVal) - } + if val, ok := identity.ServiceHostingCosts[*service.ID]; ok { + options.Cost = uint16(*val) } if config.ListenOptions != nil { if config.ListenOptions.BindUsingEdgeIdentity { - options.Identity = identity.Name + options.Identity = *identity.Name } else if config.ListenOptions.Identity != "" { result, err := replaceTemplatized(config.ListenOptions.Identity, identity) if err != nil { diff --git a/tunnel/intercept/proxy/proxy.go b/tunnel/intercept/proxy/proxy.go index c80ddd382..178b4e6f7 100644 --- a/tunnel/intercept/proxy/proxy.go +++ b/tunnel/intercept/proxy/proxy.go @@ -106,7 +106,7 @@ func New(ip net.IP, serviceList []string) (intercept.Interceptor, error) { func (p *interceptor) Intercept(service *entities.Service, _ dns.Resolver, _ intercept.AddressTracker) error { log := pfxlog.Logger().WithField("service", service.Name) - proxiedService, ok := p.services[service.Name] + proxiedService, ok := p.services[*service.Name] if !ok { log.Debugf("service %v was not specified at initialization. not intercepting", service.Name) return nil @@ -115,7 +115,7 @@ func (p *interceptor) Intercept(service *entities.Service, _ dns.Resolver, _ int proxiedService.TunnelService = service // pre-fetch network session todo move this to service poller? - service.FabricProvider.PrepForUse(service.Id) + service.FabricProvider.PrepForUse(*service.ID) go p.runServiceListener(proxiedService) return nil diff --git a/tunnel/intercept/source_ip_test.go b/tunnel/intercept/source_ip_test.go index 118028294..0cf2e8d44 100644 --- a/tunnel/intercept/source_ip_test.go +++ b/tunnel/intercept/source_ip_test.go @@ -1,9 +1,11 @@ package intercept import ( + "github.com/google/uuid" + "github.com/openziti/edge-api/rest_model" "github.com/openziti/edge/tunnel" "github.com/openziti/edge/tunnel/entities" - "github.com/openziti/sdk-golang/ziti/edge" + "github.com/openziti/foundation/v2/util" "github.com/stretchr/testify/require" "net" "testing" @@ -15,13 +17,17 @@ type testProvider struct { func (self *testProvider) PrepForUse(serviceId string) { } -func (self *testProvider) GetCurrentIdentity() (*edge.CurrentIdentity, error) { - return &edge.CurrentIdentity{ - Name: "foo.bar", - AppData: map[string]interface{}{ - "srcip": "123.456.789.10:5555", - "sourceIp": "15.14.13.12", - "sourcePort": 1999, +func (self *testProvider) GetCurrentIdentity() (*rest_model.IdentityDetail, error) { + cost := rest_model.TerminatorCost(0) + return &rest_model.IdentityDetail{ + Name: util.Ptr("foo.bar"), + DefaultHostingCost: &cost, + AppData: &rest_model.Tags{ + SubTags: map[string]interface{}{ + "srcip": "123.456.789.10:5555", + "sourceIp": "15.14.13.12", + "sourcePort": 1999, + }, }, }, nil } @@ -69,7 +75,14 @@ func Test_SourceIp(t *testing.T) { } func Test_TemplateIdentity(t *testing.T) { - svc := &entities.Service{} + serviceId := uuid.NewString() + svc := &entities.Service{ + ServiceDetail: rest_model.ServiceDetail{ + BaseEntity: rest_model.BaseEntity{ + ID: &serviceId, + }, + }, + } hostTerminator := &entities.HostV2Terminator{ListenOptions: &entities.HostV2ListenOptions{}} provider := &testProvider{} currentIdentity, err := provider.GetCurrentIdentity() diff --git a/tunnel/intercept/svcpoll.go b/tunnel/intercept/svcpoll.go index 6d299393d..b081cf403 100644 --- a/tunnel/intercept/svcpoll.go +++ b/tunnel/intercept/svcpoll.go @@ -19,13 +19,13 @@ package intercept import ( "fmt" "github.com/michaelquigley/pfxlog" + "github.com/openziti/edge-api/rest_model" "github.com/openziti/edge/health" "github.com/openziti/edge/tunnel" "github.com/openziti/edge/tunnel/dns" "github.com/openziti/edge/tunnel/entities" "github.com/openziti/foundation/v2/stringz" "github.com/openziti/sdk-golang/ziti" - "github.com/openziti/sdk-golang/ziti/edge" "github.com/pkg/errors" logrus "github.com/sirupsen/logrus" "net" @@ -139,16 +139,16 @@ func (self *ServiceListener) HandleProviderReady(provider tunnel.FabricProvider) self.provider = provider } -func (self *ServiceListener) HandleServicesChange(eventType ziti.ServiceEventType, service *edge.Service) { +func (self *ServiceListener) HandleServicesChange(eventType ziti.ServiceEventType, service *rest_model.ServiceDetail) { self.Lock() defer self.Unlock() tunnelerService := &entities.Service{ FabricProvider: self.provider, - Service: *service, + ServiceDetail: *service, } - log := logrus.WithField("service", service.Name) + log := logrus.WithField("service", *service.Name) switch eventType { case ziti.ServiceAdded: @@ -169,11 +169,17 @@ func (self *ServiceListener) HandleServicesChange(eventType ziti.ServiceEventTyp } func (self *ServiceListener) addService(svc *entities.Service) { - log := pfxlog.Logger().WithField("serviceId", svc.Id).WithField("serviceName", svc.Name) + log := pfxlog.Logger().WithField("serviceId", *svc.ID).WithField("serviceName", *svc.Name) svc.DialTimeout = 5 * time.Second - if stringz.Contains(svc.Permissions, "Dial") { + var perms []string + + for _, perm := range svc.Permissions { + perms = append(perms, string(perm)) + } + + if stringz.Contains(perms, "Dial") { interceptV1Config := &entities.InterceptV1Config{} found, err := svc.GetConfigOfType(entities.InterceptV1, interceptV1Config) if found { @@ -184,7 +190,7 @@ func (self *ServiceListener) addService(svc *entities.Service) { } if err != nil { - logrus.WithError(err).Errorf("error decoding service config of type %v for service %v", entities.InterceptV1, svc.Name) + logrus.WithError(err).Errorf("error decoding service config of type %v for service %v", entities.InterceptV1, *svc.Name) } if !found { @@ -196,7 +202,7 @@ func (self *ServiceListener) addService(svc *entities.Service) { } if err != nil { - logrus.WithError(err).Errorf("error decoding service config of type %v for service %v", entities.ClientConfigV1, svc.Name) + logrus.WithError(err).Errorf("error decoding service config of type %v for service %v", entities.ClientConfigV1, *svc.Name) } } @@ -208,13 +214,13 @@ func (self *ServiceListener) addService(svc *entities.Service) { } // not all interceptors need a config, specifically proxy doesn't need one - log.Infof("starting tunnel for newly available service %s", svc.Name) + log.Infof("starting tunnel for newly available service %s", *svc.Name) if err := self.interceptor.Intercept(svc, self.resolver, self.addrTracker); err != nil { log.Errorf("failed to intercept service: %v", err) } } - if stringz.Contains(svc.Permissions, "Bind") { + if stringz.Contains(perms, "Bind") { configType := entities.HostConfigV2 hostV2config := &entities.HostV2Config{} found, err := svc.GetConfigOfType(configType, hostV2config) @@ -250,31 +256,31 @@ func (self *ServiceListener) addService(svc *entities.Service) { } if svc.InterceptV1Config != nil || svc.HostV2Config != nil { - self.services[svc.Id] = svc + self.services[*svc.ID] = svc } } func (self *ServiceListener) removeService(svc *entities.Service) { log := pfxlog.Logger() - previousService := self.services[svc.Id] + previousService := self.services[*svc.ID] if previousService != nil { if previousService.InterceptV1Config != nil { - log.Infof("stopping tunnel for unavailable service: %s", previousService.Name) - err := self.interceptor.StopIntercepting(previousService.Name, self.addrTracker) + log.Infof("stopping tunnel for unavailable service: %s", *previousService.Name) + err := self.interceptor.StopIntercepting(*previousService.Name, self.addrTracker) if err != nil { - log.WithError(err).Errorf("failed to stop intercepting service: %v", previousService.Name) + log.WithError(err).Errorf("failed to stop intercepting service: %v", *previousService.Name) } } previousService.RunCleanupActions() - delete(self.services, svc.Id) + delete(self.services, *svc.ID) } } func (self *ServiceListener) host(svc *entities.Service, tracker AddressTracker) { - logger := pfxlog.Logger().WithField("service", svc.Name) + logger := pfxlog.Logger().WithField("service", *svc.Name) currentIdentity, err := self.provider.GetCurrentIdentity() if err != nil { @@ -290,27 +296,27 @@ func (self *ServiceListener) host(svc *entities.Service, tracker AddressTracker) for _, hostControl := range hostControls { _ = hostControl.Close() } - self.healthCheckMgr.UnregisterServiceChecks(svc.Id) + self.healthCheckMgr.UnregisterServiceChecks(*svc.ID) } svc.AddCleanupAction(stopHook) for idx, hostContext := range hostContexts { hostControl, err := self.provider.HostService(hostContext) if err != nil { - logger.WithError(err).WithField("service", svc.Name).Errorf("error listening for service") + logger.WithError(err).WithField("service", *svc.Name).Errorf("error listening for service") return } context := strconv.Itoa(idx) hostContext.SetCloseCallback(func() { - self.healthCheckMgr.UnregisterServiceContextChecks(svc.Name, context) + self.healthCheckMgr.UnregisterServiceContextChecks(*svc.Name, context) }) hostControls = append(hostControls, hostControl) precedence, cost := hostContext.GetInitialHealthState() - serviceState := health.NewServiceStateWithContext(svc.Name, context, precedence, cost, hostControl) + serviceState := health.NewServiceStateWithContext(*svc.Name, context, precedence, cost, hostControl) if err := self.healthCheckMgr.RegisterServiceChecks(serviceState, hostContext.GetHealthChecks()); err != nil { logger.WithError(err).Error("error setting up health checks") @@ -369,8 +375,8 @@ func (self *ServiceListener) getTemplatingProvider(template string) (entities.Te }, nil } -func replaceTemplatized(input string, currentIdentity *edge.CurrentIdentity) (string, error) { - input = strings.ReplaceAll(input, "$tunneler_id.name", currentIdentity.Name) +func replaceTemplatized(input string, currentIdentity *rest_model.IdentityDetail) (string, error) { + input = strings.ReplaceAll(input, "$tunneler_id.name", *currentIdentity.Name) start := "$tunneler_id.appData[" for { index := strings.Index(input, start) @@ -387,7 +393,7 @@ func replaceTemplatized(input string, currentIdentity *edge.CurrentIdentity) (st tagValue := "" logrus.Infof("appData: %v", currentIdentity.AppData) if currentIdentity.AppData != nil { - val, found := currentIdentity.AppData[tagName] + val, found := currentIdentity.AppData.SubTags[tagName] if found { tagValue = fmt.Sprintf("%v", val) } diff --git a/tunnel/intercept/tproxy/tproxy_linux.go b/tunnel/intercept/tproxy/tproxy_linux.go index 05ad96ff3..eb372eb8c 100644 --- a/tunnel/intercept/tproxy/tproxy_linux.go +++ b/tunnel/intercept/tproxy/tproxy_linux.go @@ -30,7 +30,7 @@ import ( "github.com/openziti/foundation/v2/info" "github.com/openziti/foundation/v2/mempool" "github.com/openziti/foundation/v2/stringz" - "github.com/openziti/sdk-golang/ziti/edge/impl" + "github.com/openziti/sdk-golang/ziti/edge/network" cmap "github.com/orcaman/concurrent-map/v2" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -147,7 +147,7 @@ func (self *interceptor) Intercept(service *entities.Service, resolver dns.Resol if err != nil { return err } - self.serviceProxies.Set(service.Name, tproxy) + self.serviceProxies.Set(*service.Name, tproxy) return nil } @@ -182,13 +182,13 @@ func (self *interceptor) newTproxy(service *entities.Service, resolver dns.Resol config := service.InterceptV1Config if config == nil { - return nil, errors.Errorf("service %v has no intercept information", service.Name) + return nil, errors.Errorf("service %v has no intercept information", *service.Name) } if stringz.Contains(config.Protocols, "tcp") { tcpLn, err := listenConfig.Listen(context.Background(), "tcp", "127.0.0.1:") if err != nil { - return nil, errors.Wrapf(err, "failed to create TCP listener for service: %v", service.Name) + return nil, errors.Wrapf(err, "failed to create TCP listener for service: %v", *service.Name) } logrus.Infof("tproxy listening on tcp:%s", tcpLn.Addr().String()) t.tcpLn = tcpLn @@ -197,7 +197,7 @@ func (self *interceptor) newTproxy(service *entities.Service, resolver dns.Resol if stringz.Contains(config.Protocols, "udp") { packetLn, err := listenConfig.ListenPacket(context.Background(), "udp", "127.0.0.1:") if err != nil { - return nil, errors.Wrapf(err, "failed to create UDP listener for service: %v", service.Name) + return nil, errors.Wrapf(err, "failed to create UDP listener for service: %v", *service.Name) } udpLn, ok := packetLn.(*net.UDPConn) if !ok { @@ -208,7 +208,7 @@ func (self *interceptor) newTproxy(service *entities.Service, resolver dns.Resol } if t.tcpLn == nil && t.udpLn == nil { - return nil, errors.Errorf("service %v has no supported protocols (tcp, udp). Serivce protocols: %+v", service.Name, config.Protocols) + return nil, errors.Errorf("service %v has no supported protocols (tcp, udp). Serivce protocols: %+v", *service.Name, config.Protocols) } if t.tcpLn != nil { @@ -385,7 +385,7 @@ func deleteIptablesChain(ipt *iptables.IPTables, table, srcChain, dstChain strin } func (self *tProxy) Stop(tracker intercept.AddressTracker) { - log := pfxlog.Logger().WithField("service", self.service.Name) + log := pfxlog.Logger().WithField("service", *self.service.Name) if self.tcpLn != nil { if err := self.tcpLn.Close(); err != nil { log.WithError(err).Error("failed to close TCP listener") @@ -408,7 +408,7 @@ func (self *tProxy) tcpPort() IPPortAddr { if self.tcpLn != nil { return (*TCPIPPortAddr)(self.tcpLn.Addr().(*net.TCPAddr)) } - logrus.Errorf("invalid state: no tcp listener for tproxy[%s]", self.service.Name) + logrus.Errorf("invalid state: no tcp listener for tproxy[%s]", *self.service.Name) return nil } @@ -417,25 +417,25 @@ func (self *tProxy) udpPort() IPPortAddr { return (*UDPIPPortAddr)(self.udpLn.LocalAddr().(*net.UDPAddr)) } - logrus.Errorf("invalid state: no udp listener for tproxy[%s]", self.service.Name) + logrus.Errorf("invalid state: no udp listener for tproxy[%s]", *self.service.Name) return nil } func (self *tProxy) Intercept(resolver dns.Resolver, tracker intercept.AddressTracker) error { service := self.service if service.InterceptV1Config == nil { - return errors.Errorf("no client configuration for service %v", service.Name) + return errors.Errorf("no client configuration for service %v", *service.Name) } config := service.InterceptV1Config - logrus.Debugf("service %v using intercept.v1", service.Name) + logrus.Debugf("service %v using intercept.v1", *service.Name) var ports []IPPortAddr for _, p := range config.Protocols { if p == "tcp" { - logrus.Debugf("service %v intercepting tcp", service.Name) + logrus.Debugf("service %v intercepting tcp", *service.Name) ports = append(ports, self.tcpPort()) } else if p == "udp" { - logrus.Debugf("service %v intercepting udp", service.Name) + logrus.Debugf("service %v intercepting udp", *service.Name) ports = append(ports, self.udpPort()) } } @@ -444,7 +444,7 @@ func (self *tProxy) Intercept(resolver dns.Resolver, tracker intercept.AddressTr } func (self *tProxy) Apply(addr *intercept.InterceptAddress) { - logrus.Debugf("for service %v, intercepting proto: %v, cidr: %v, ports: %v:%v", self.service.Name, addr.Proto(), addr.IpNet(), addr.LowPort(), addr.HighPort()) + logrus.Debugf("for service %v, intercepting proto: %v, cidr: %v, ports: %v:%v", *self.service.Name, addr.Proto(), addr.IpNet(), addr.LowPort(), addr.HighPort()) var port IPPortAddr switch addr.Proto() { @@ -453,11 +453,11 @@ func (self *tProxy) Apply(addr *intercept.InterceptAddress) { case "udp": port = self.udpPort() default: - logrus.Errorf("unknown proto[%s] for tproxy[%s]", addr.Proto(), self.service.Name) + logrus.Errorf("unknown proto[%s] for tproxy[%s]", addr.Proto(), *self.service.Name) return } if err := self.addInterceptAddr(addr, self.service, port, self.tracker); err != nil { - logrus.Debugf("failed for service %v, intercepting proto: %v, cidr: %v, ports: %v:%v", self.service.Name, addr.Proto(), addr.IpNet(), addr.LowPort(), addr.HighPort()) + logrus.Debugf("failed for service %v, intercepting proto: %v, cidr: %v, ports: %v:%v", *self.service.Name, addr.Proto(), addr.IpNet(), addr.LowPort(), addr.HighPort()) // do we undo the previous succesful ones? // only fail at end and return all that failed? @@ -505,7 +505,7 @@ func (self *tProxy) addInterceptAddr(interceptAddr *intercept.InterceptAddress, } } else { interceptAddr.TproxySpec = []string{ - "-m", "comment", "--comment", service.Name, + "-m", "comment", "--comment", *service.Name, "-d", ipNet.String(), "-p", interceptAddr.Proto(), "--dport", fmt.Sprintf("%v:%v", interceptAddr.LowPort(), interceptAddr.HighPort()), @@ -523,7 +523,7 @@ func (self *tProxy) addInterceptAddr(interceptAddr *intercept.InterceptAddress, if self.interceptor.lanIf != "" { interceptAddr.AcceptSpec = []string{ "-i", self.interceptor.lanIf, - "-m", "comment", "--comment", service.Name, + "-m", "comment", "--comment", *service.Name, "-d", ipNet.String(), "-p", interceptAddr.Proto(), "--dport", fmt.Sprintf("%v:%v", interceptAddr.LowPort(), interceptAddr.HighPort()), @@ -542,7 +542,7 @@ func (self *tProxy) addInterceptAddr(interceptAddr *intercept.InterceptAddress, func (self *tProxy) StopIntercepting(tracker intercept.AddressTracker) error { var errorList []error - log := pfxlog.Logger().WithField("service", self.service.Name) + log := pfxlog.Logger().WithField("service", *self.service.Name) for _, addr := range self.addresses { log := log.WithField("route", addr.IpNet()) @@ -570,14 +570,14 @@ func (self *tProxy) StopIntercepting(tracker intercept.AddressTracker) error { err := self.interceptor.ipt.Delete(mangleTable, dstChain, addr.TproxySpec...) if err != nil { errorList = append(errorList, err) - log.WithError(err).Errorf("failed to remove iptables rule for service %s", self.service.Name) + log.WithError(err).Errorf("failed to remove iptables rule for service %s", *self.service.Name) } if self.interceptor.lanIf != "" { pfxlog.Logger().Infof("Removing rule iptables -t %v -A %v %v", filterTable, dstChain, addr.TproxySpec) err = self.interceptor.ipt.Delete(filterTable, dstChain, addr.AcceptSpec...) if err != nil { errorList = append(errorList, err) - log.WithError(err).Errorf("failed to remove iptables rule for service %s", self.service.Name) + log.WithError(err).Errorf("failed to remove iptables rule for service %s", *self.service.Name) } } } @@ -587,7 +587,7 @@ func (self *tProxy) StopIntercepting(tracker intercept.AddressTracker) error { err := router.RemoveLocalAddress(ipNet, "lo") if err != nil { errorList = append(errorList, err) - log.WithError(err).Errorf("failed to remove route %v for service %s", ipNet, self.service.Name) + log.WithError(err).Errorf("failed to remove route %v for service %s", ipNet, *self.service.Name) } } } @@ -598,7 +598,7 @@ func (self *tProxy) StopIntercepting(tracker intercept.AddressTracker) error { if len(errorList) == 1 { return errorList[0] } - return impl.MultipleErrors(errorList) + return network.MultipleErrors(errorList) } type IPPortAddr interface { diff --git a/tunnel/provider.go b/tunnel/provider.go index 90a291f3e..ba4cd0f99 100644 --- a/tunnel/provider.go +++ b/tunnel/provider.go @@ -2,6 +2,7 @@ package tunnel import ( "encoding/json" + "github.com/openziti/edge-api/rest_model" "github.com/openziti/edge/health" "github.com/openziti/sdk-golang/ziti" "github.com/openziti/sdk-golang/ziti/edge" @@ -30,7 +31,7 @@ type HostControl interface { type FabricProvider interface { PrepForUse(serviceId string) - GetCurrentIdentity() (*edge.CurrentIdentity, error) + GetCurrentIdentity() (*rest_model.IdentityDetail, error) TunnelService(service Service, identity string, conn net.Conn, halfClose bool, appInfo []byte) error HostService(hostCtx HostingContext) (HostControl, error) } diff --git a/tunnel/udp_vconn/manager.go b/tunnel/udp_vconn/manager.go index 6d363d033..39de2f296 100644 --- a/tunnel/udp_vconn/manager.go +++ b/tunnel/udp_vconn/manager.go @@ -91,7 +91,7 @@ func (manager *manager) CreateWriteQueue(targetAddr *net.UDPAddr, srcAddr net.Ad conn := &udpConn{ readC: make(chan mempool.PooledBuffer, 4), closeNotify: make(chan struct{}), - service: service.Name, + service: *service.Name, srcAddr: srcAddr, manager: manager, writeConn: writeConn,