mirror of
https://github.com/openziti/ziti.git
synced 2026-10-14 08:10:17 +00:00
Merge pull request #123 from netfoundry/tx.router.extended.base
Tx.router.extended.base
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$id": "http://ziti-edge.netfoundry.io/schemas/fabric-routers.patch.json",
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"name": {
|
||||
"$ref": "definitions.all.json#/definitions/name-null"
|
||||
},
|
||||
"tags": {
|
||||
"$ref": "definitions.all.json#/definitions/tags-null"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"$id": "http://ziti-edge.netfoundry.io/schemas/fabric-routers.post.json",
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"$ref": "definitions.all.json#/definitions/name"
|
||||
},
|
||||
"tags": {
|
||||
"$ref": "definitions.all.json#/definitions/tags-null"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$id": "http://ziti-edge.netfoundry.io/schemas/fabric-routers.put.json",
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"required": [
|
||||
"name",
|
||||
"tags"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"$ref": "definitions.all.json#/definitions/name"
|
||||
},
|
||||
"tags": {
|
||||
"$ref": "definitions.all.json#/definitions/tags"
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+3
@@ -52,6 +52,9 @@ func init() {
|
||||
_ = packr.PackJSONBytes("../embedded", "api-schema/entities/terminator.patch.json", "\"H4sIAAAAAAAA/6yRsW7DMAxE93yFoGZspN1f0T3IoJi0zUCRVIoa0sL/XlBxm3TPYBh3PLwjqO+dMXZPYAdjF5EyeP9FQgeEGV1CmXJLwDdH2ddxwWuoXpCvlIJkdiXIuLhLzcm+K0huBZWUzxcc5e4FABLKKcQPzgVZCKsdjHDDPmf8bMSoGxx3xpy6WZ6juqMGcxPkP/2oO27aGFuFKc29eHNSi9Fu8tT/631qz5RAwy8DBgDGWl8HlDD/owFOoUVRa/0F2D3jpDcHnCj1S1cXYuyv8uafXK+4w6Nt3em3/gQAAP//ec1C3AICAAA=\"")
|
||||
_ = packr.PackJSONBytes("../embedded", "api-schema/entities/terminator.post.json", "\"H4sIAAAAAAAA/4yRMW7rMAyGd5+C0MuYWLtP8fYgg2LRDgNFckmqQBr47oXUuLHRJYMHfv75kZIeDYDZkTcdmIvq1Fn7RUoH9CO2EXVIOXq+t5Ss9Be8ObGKfKPoNHE7JdH2KimaffHofcIiSucr9vrDnPeklKIL/zlNyEoopgPljPU/40cmxrLAsQEAMIL8ST3W9hJIWZGXynnPKGIagFPtn9bWx9awgNVqokxxNBXP2wlvps8UfYF/48dnDb+N+xeJOQTzLE8b4XKkN+erGzdZj4PLQQual3lmxzgUgceBYr1/aV0I9a3+2RW1RXd4LTc35Zu/AwAA//9siIA/FwIAAA==\"")
|
||||
_ = packr.PackJSONBytes("../embedded", "api-schema/entities/terminator.put.json", "\"H4sIAAAAAAAA/4yQsW7DMAxEd38FoWZMrD1f0T3IoFi0w0CRXJIqkAb+90Kq3djo0kHDnXiPBz4bALMjb45grqrj0dovUjqgH7CNqH3K0fOjpWSlu+LdiVXkO0WnidsxibY3SdHsC0cfIxZQutyw0x/PeU9KKbrwzmlEVkIxR1DOWP8ZPzIxlgKnBgDACPIndVjjZSBlRV6U855RxDQA55of19TnJrLoVTNRpjiYak8z8kLRF/Pv+GnW8Bvcv5yYQzCzPG+AS8d/7lc3bGY99i4HLda07DM7xr4APPYU60GldSHU47/ZlWsL7vAqNzXlTd8BAAD//xFy8DDoAQAA\"")
|
||||
_ = packr.PackJSONBytes("../embedded", "api-schema/entities/transitRouter.patch.json", "\"H4sIAAAAAAAA/5zOMW7EIBAF0N6nQCTlGnqfIleYhWE9KxbQMBSbyHePBkuR6xQUfPQf/2cxxn5StJuxu0jbvP8moRXjA11BSXWUyG9H1few4wu6T3BnCivXIcjdNZCwu2evxd4Uk3dD1er9iUHODGIkoVogf3FtyELY7WaEB873dk11kjG2wAv/bjqSMakbMVGZWneQ8/z5w19Sr821jJzt7B63ExR49P+B2ryCi55j+Q0AAP//uFLZijwBAAA=\"")
|
||||
_ = packr.PackJSONBytes("../embedded", "api-schema/entities/transitRouter.post.json", "\"H4sIAAAAAAAA/5yPsXIDIQxEe75CQ1L6oL+vSJ9JgQ+dLQ9GRBKF4/G/ZzjHM1enoGCXfbvcHYB/p+xn8GezNsf4Q0YT5hOGirZyr1lugTjqcsZr0rimo9AyCXdD0dBYLVyUqz8Mlt0aDhgfL7jYU0s5kxHXVD6EG4oRqp/BpOPmC353EhwjPh0AgK/pit4BfG1+26fuuxev2/iD4Dp6M65UtzYNqZRt2VvcqfHFBngcnixLJ/0faySn2kv5A7pxHu43AAD//+YEIOVWAQAA\"")
|
||||
_ = packr.PackJSONBytes("../embedded", "api-schema/entities/transitRouter.put.json", "\"H4sIAAAAAAAA/5yPsW7EIAyGd57Coh17sOcpulcduGDuHCVAjRnSKO9eQRWJ+QYGjP/v/zgUgH4nryfQT5E8WftLQjf0DzQRJaQaPe+Gki3zEzdXbHB3pvnGqQpyMbmKWUqK+qOhZM/YWOm+4Cz/M+c9CaXo1k9OGVkIi55AuGJ/Z/ypxNgcvhQAgI5uw55tRPcoWgF89908Eo5h+7q17zCG5uAxUOzNxbh17ZZvdpjanuyxc2x7iXV5ApyqnVP9BQAA//+mADgbXAEAAA==\"")
|
||||
_ = packr.PackJSONBytes("../embedded", "db/postgres/migrations/20180828083820_init-schema.down.sql", "\"H4sIAAAAAAAA/1SNMcvCMBiE9/dX3BDI9y3+geJQk7c2YFNpInYrQaNmaAuayV8vtCB4yw13D49uIQTteG8sEWAqcG+cd3+EJY4PrDxel0ccwzCFMaLq2gZpus3PMeQ0T8M6btbKAeeaO/5BtpDvlNMQr/coCfgnwNdsFwn3rE6eIXXXHuFUzU2J7x2qdKrULAsC2GqYqiBiq0mI4hMAAP//7wIpBL4AAAA=\"")
|
||||
_ = packr.PackJSONBytes("../embedded", "db/postgres/migrations/20180828083820_init-schema.up.sql", "\"H4sIAAAAAAAA/2SNsUrGMBzE9/9T3BCILr5AcIjJ1Qb8UkkiflsJGjVD+4F28umFFgTxlhvufvz8BKXkjvchigBhAM8hl3wl2JP5QFfw9fLRljqvdWkY0nRCX98un0vd+mWdj/HmqK3ieWTiH+QW+rtvfW6v700LcC1AGRl3Cc90T4XQPk2PyG7kyeL3Dmezs57aCMDoEQYjwuhFKSPiEm3hP8r8BAAA//+lS2Hg2AAAAA==\"")
|
||||
_ = packr.PackJSONBytes("../embedded", "db/postgres/migrations/20180905100347_initial-tables.down.sql", "\"H4sIAAAAAAAA/wEAAP//AAAAAAAAAAA=\"")
|
||||
|
||||
Vendored
+1
@@ -149,6 +149,7 @@ type Schemes struct {
|
||||
EnrollUpdb *BasicEntitySchema
|
||||
EdgeRouter *BasicEntitySchema
|
||||
EdgeRouterPolicy *BasicEntitySchema
|
||||
TransitRouter *BasicEntitySchema
|
||||
Identity *IdentityEntitySchema
|
||||
Service *BasicEntitySchema
|
||||
ServiceEdgeRouterPolicy *BasicEntitySchema
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -150,17 +150,40 @@ func MapEdgeRouterToApiList(ae *env.AppEnv, i *model.EdgeRouter) (*EdgeRouterApi
|
||||
BaseApi: env.FromBaseModelEntity(i),
|
||||
Name: &i.Name,
|
||||
RoleAttributes: i.RoleAttributes,
|
||||
EnrollmentToken: i.EnrollmentToken,
|
||||
EnrollmentCreatedAt: i.EnrollmentCreatedAt,
|
||||
EnrollmentExpiresAt: i.EnrollmentExpiresAt,
|
||||
EnrollmentToken: nil,
|
||||
EnrollmentCreatedAt: nil,
|
||||
EnrollmentExpiresAt: nil,
|
||||
EnrollmentJwt: nil,
|
||||
IsOnline: &isOnline,
|
||||
IsVerified: &i.IsVerified,
|
||||
Fingerprint: i.Fingerprint,
|
||||
EnrollmentJwt: i.EnrollmentJwt,
|
||||
Hostname: &hostname,
|
||||
SupportedProtocols: protocols,
|
||||
}
|
||||
|
||||
if !i.IsVerified {
|
||||
var enrollments []*model.Enrollment
|
||||
|
||||
err := ae.GetHandlers().EdgeRouter.CollectEnrollments(i.Id, func(entity *model.Enrollment) error {
|
||||
enrollments = append(enrollments, entity)
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(enrollments) != 1 {
|
||||
return nil, fmt.Errorf("expected enrollment not found for unverified edge router %s", i.Id)
|
||||
}
|
||||
enrollment := enrollments[0]
|
||||
|
||||
ret.EnrollmentExpiresAt = enrollment.ExpiresAt
|
||||
ret.EnrollmentCreatedAt = &enrollment.CreatedAt
|
||||
ret.EnrollmentJwt = &enrollment.Jwt
|
||||
ret.EnrollmentToken = &enrollment.Token
|
||||
}
|
||||
|
||||
ret.PopulateLinks()
|
||||
|
||||
return ret, nil
|
||||
|
||||
@@ -31,11 +31,13 @@ const EntityNameEnrollment = "enrollments"
|
||||
|
||||
type EnrollmentApiList struct {
|
||||
*env.BaseApi
|
||||
Token *string `json:"token"`
|
||||
Method *string `json:"method"`
|
||||
ExpiresAt *time.Time `json:"expiresAt"`
|
||||
Identity *EntityApiRef `json:"identity"`
|
||||
Details interface{} `json:"details"`
|
||||
Token *string `json:"token"`
|
||||
Method *string `json:"method"`
|
||||
ExpiresAt *time.Time `json:"expiresAt"`
|
||||
Identity *EntityApiRef `json:"identity"`
|
||||
Details interface{} `json:"details"`
|
||||
EdgeRouter *EntityApiRef `json:"edgeRouter"`
|
||||
TransitRouter *EntityApiRef `json:"transitRouter"`
|
||||
}
|
||||
|
||||
func (e *EnrollmentApiList) GetSelfLink() *response.Link {
|
||||
@@ -101,19 +103,35 @@ func MapEnrollmentToApiEntity(appEnv *env.AppEnv, context *response.RequestConte
|
||||
}
|
||||
|
||||
func MapToEnrollmentApiList(ae *env.AppEnv, enrollment *model.Enrollment) (*EnrollmentApiList, error) {
|
||||
|
||||
identity, err := ae.Handlers.Identity.Read(enrollment.IdentityId)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := &EnrollmentApiList{
|
||||
BaseApi: env.FromBaseModelEntity(enrollment),
|
||||
Token: &enrollment.Token,
|
||||
Method: &enrollment.Method,
|
||||
ExpiresAt: enrollment.ExpiresAt,
|
||||
Identity: NewIdentityEntityRef(identity),
|
||||
}
|
||||
|
||||
if enrollment.IdentityId != nil {
|
||||
identity, err := ae.Handlers.Identity.Read(*enrollment.IdentityId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.Identity = NewIdentityEntityRef(identity)
|
||||
}
|
||||
|
||||
if enrollment.EdgeRouterId != nil {
|
||||
edgeRouter, err := ae.Handlers.EdgeRouter.Read(*enrollment.EdgeRouterId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.EdgeRouter = NewEdgeRouterEntityRef(edgeRouter)
|
||||
}
|
||||
|
||||
if enrollment.TransitRouterId != nil {
|
||||
transitRouter, err := ae.Handlers.TransitRouter.Read(*enrollment.TransitRouterId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret.TransitRouter = NewTransitRouterEntityRef(transitRouter)
|
||||
}
|
||||
|
||||
ret.PopulateLinks()
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"github.com/netfoundry/ziti-edge/controller/env"
|
||||
"github.com/netfoundry/ziti-edge/controller/model"
|
||||
"github.com/netfoundry/ziti-edge/controller/response"
|
||||
"github.com/netfoundry/ziti-fabric/controller/models"
|
||||
"time"
|
||||
)
|
||||
|
||||
const EntityNameTransitRouter = "transit-routers"
|
||||
|
||||
func NewTransitRouterEntityRef(entity *model.TransitRouter) *EntityApiRef {
|
||||
links := &response.Links{
|
||||
"self": NewTransitRouterLink(entity.Id),
|
||||
}
|
||||
|
||||
return &EntityApiRef{
|
||||
Entity: EntityNameEdgeRouter,
|
||||
Id: entity.Id,
|
||||
Name: &entity.Name,
|
||||
Links: links,
|
||||
}
|
||||
}
|
||||
|
||||
func NewTransitRouterLink(id string) *response.Link {
|
||||
return response.NewLink(fmt.Sprintf("./%s/%s", EntityNameTransitRouter, id))
|
||||
}
|
||||
|
||||
type TransitRouterApi struct {
|
||||
Name string `json:"name"`
|
||||
Tags map[string]interface{} `json:"tags"`
|
||||
}
|
||||
|
||||
func (i TransitRouterApi) ToModel(id string) *model.TransitRouter {
|
||||
ret := &model.TransitRouter{
|
||||
BaseEntity: models.BaseEntity{
|
||||
Tags: i.Tags,
|
||||
Id: id,
|
||||
},
|
||||
Name: i.Name,
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type TransitRouterApiList struct {
|
||||
*env.BaseApi
|
||||
Name string `json:"name"`
|
||||
Fingerprint string `json:"fingerprint"`
|
||||
IsVerified bool `json:"isVerified"`
|
||||
IsOnline bool `json:"isOnline"`
|
||||
EnrollmentToken *string `json:"enrollmentToken"`
|
||||
EnrollmentJwt *string `json:"enrollmentJwt"`
|
||||
EnrollmentCreatedAt *time.Time `json:"enrollmentCreatedAt"`
|
||||
EnrollmentExpiresAt *time.Time `json:"enrollmentExpiresAt"`
|
||||
}
|
||||
|
||||
func (e TransitRouterApiList) GetSelfLink() *response.Link {
|
||||
return e.BuildSelfLink(e.Id)
|
||||
}
|
||||
|
||||
func (e TransitRouterApiList) PopulateLinks() {
|
||||
if e.Links == nil {
|
||||
e.Links = &response.Links{
|
||||
EntityNameSelf: e.GetSelfLink(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (e TransitRouterApiList) ToEntityApiRef() *EntityApiRef {
|
||||
e.PopulateLinks()
|
||||
return &EntityApiRef{
|
||||
Entity: EntityNameTransitRouter,
|
||||
Name: nil,
|
||||
Id: e.Id,
|
||||
Links: e.Links,
|
||||
}
|
||||
}
|
||||
|
||||
func (e TransitRouterApiList) BuildSelfLink(id string) *response.Link {
|
||||
return NewTransitRouterLink(id)
|
||||
}
|
||||
|
||||
func MapTransitRouterToApiEntity(appEnv *env.AppEnv, context *response.RequestContext, entity models.Entity) (BaseApiEntity, error) {
|
||||
txRouter, ok := entity.(*model.TransitRouter)
|
||||
|
||||
if !ok {
|
||||
err := fmt.Errorf("entity is not a transit router \"%s\"", entity.GetId())
|
||||
log := pfxlog.Logger()
|
||||
log.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := &TransitRouterApiList{
|
||||
BaseApi: env.FromBaseModelEntity(entity),
|
||||
Name: txRouter.Name,
|
||||
Fingerprint: txRouter.Fingerprint,
|
||||
IsVerified: txRouter.IsVerified,
|
||||
IsOnline: appEnv.GetHandlers().Router.IsConnected(entity.GetId()),
|
||||
}
|
||||
|
||||
if !txRouter.IsBase && !txRouter.IsVerified {
|
||||
var enrollments []*model.Enrollment
|
||||
|
||||
err := appEnv.GetHandlers().TransitRouter.CollectEnrollments(txRouter.Id, func(entity *model.Enrollment) error {
|
||||
enrollments = append(enrollments, entity)
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(enrollments) != 1 {
|
||||
return nil, fmt.Errorf("expected enrollment not found for unverified transit router %s", txRouter.Id)
|
||||
}
|
||||
enrollment := enrollments[0]
|
||||
|
||||
ret.EnrollmentExpiresAt = enrollment.ExpiresAt
|
||||
ret.EnrollmentCreatedAt = &enrollment.CreatedAt
|
||||
ret.EnrollmentJwt = &enrollment.Jwt
|
||||
ret.EnrollmentToken = &enrollment.Token
|
||||
}
|
||||
|
||||
ret.PopulateLinks()
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright NetFoundry, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package routes
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-edge/controller/env"
|
||||
"github.com/netfoundry/ziti-edge/controller/internal/permissions"
|
||||
"github.com/netfoundry/ziti-edge/controller/response"
|
||||
)
|
||||
|
||||
func init() {
|
||||
r := NewTransitRouterRouter()
|
||||
env.AddRouter(r)
|
||||
}
|
||||
|
||||
type TransitRouterRouter struct {
|
||||
BasePath string
|
||||
IdType response.IdType
|
||||
}
|
||||
|
||||
func NewTransitRouterRouter() *TransitRouterRouter {
|
||||
return &TransitRouterRouter{
|
||||
BasePath: "/" + EntityNameTransitRouter,
|
||||
IdType: response.IdTypeUuid,
|
||||
}
|
||||
}
|
||||
|
||||
func (ir *TransitRouterRouter) Register(ae *env.AppEnv) {
|
||||
_ = registerCrudRouter(ae, ae.RootRouter, ir.BasePath, ir, &crudResolvers{
|
||||
Create: permissions.IsAdmin(),
|
||||
Read: permissions.IsAdmin(),
|
||||
Update: permissions.IsAdmin(),
|
||||
Delete: permissions.IsAdmin(),
|
||||
Default: permissions.IsAdmin(),
|
||||
})
|
||||
}
|
||||
|
||||
func (ir *TransitRouterRouter) List(ae *env.AppEnv, rc *response.RequestContext) {
|
||||
ListWithHandler(ae, rc, ae.Handlers.TransitRouter, MapTransitRouterToApiEntity)
|
||||
}
|
||||
|
||||
func (ir *TransitRouterRouter) Detail(ae *env.AppEnv, rc *response.RequestContext) {
|
||||
DetailWithHandler(ae, rc, ae.Handlers.TransitRouter, MapTransitRouterToApiEntity, ir.IdType)
|
||||
}
|
||||
|
||||
func (ir *TransitRouterRouter) Create(ae *env.AppEnv, rc *response.RequestContext) {
|
||||
transitRouterCreate := &TransitRouterApi{}
|
||||
Create(rc, rc.RequestResponder, ae.Schemes.TransitRouter.Post, transitRouterCreate, (&TransitRouterApiList{}).BuildSelfLink, func() (string, error) {
|
||||
return ae.Handlers.TransitRouter.Create(transitRouterCreate.ToModel(""))
|
||||
})
|
||||
}
|
||||
|
||||
func (ir *TransitRouterRouter) Delete(ae *env.AppEnv, rc *response.RequestContext) {
|
||||
DeleteWithHandler(rc, ir.IdType, ae.Handlers.TransitRouter)
|
||||
}
|
||||
|
||||
func (ir *TransitRouterRouter) Update(ae *env.AppEnv, rc *response.RequestContext) {
|
||||
transitRouterUpdate := &TransitRouterApi{}
|
||||
Update(rc, ae.Schemes.TransitRouter.Put, ir.IdType, transitRouterUpdate, func(id string) error {
|
||||
return ae.Handlers.TransitRouter.Update(transitRouterUpdate.ToModel(id))
|
||||
})
|
||||
}
|
||||
|
||||
func (ir *TransitRouterRouter) Patch(ae *env.AppEnv, rc *response.RequestContext) {
|
||||
transitRouterUpdate := &TransitRouterApi{}
|
||||
Patch(rc, ae.Schemes.TransitRouter.Patch, ir.IdType, transitRouterUpdate, func(id string, fields JsonFields) error {
|
||||
return ae.Handlers.TransitRouter.Patch(transitRouterUpdate.ToModel(id), fields.ConcatNestedNames().FilterMaps("tags"))
|
||||
})
|
||||
}
|
||||
@@ -18,6 +18,8 @@ package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"github.com/netfoundry/ziti-edge/controller/persistence"
|
||||
"github.com/netfoundry/ziti-fabric/controller/models"
|
||||
"github.com/netfoundry/ziti-foundation/storage/boltz"
|
||||
@@ -49,7 +51,14 @@ func (handler *EdgeRouterHandler) newModelEntity() boltEntitySink {
|
||||
}
|
||||
|
||||
func (handler *EdgeRouterHandler) Create(modelEntity *EdgeRouter) (string, error) {
|
||||
return handler.createEntity(modelEntity)
|
||||
enrollment := &Enrollment{
|
||||
BaseEntity: models.BaseEntity{},
|
||||
Method: MethodEnrollEdgeRouterOtt,
|
||||
}
|
||||
|
||||
id, _, err := handler.CreateWithEnrollment(modelEntity, enrollment)
|
||||
|
||||
return id, err
|
||||
}
|
||||
|
||||
func (handler *EdgeRouterHandler) Read(id string) (*EdgeRouter, error) {
|
||||
@@ -154,6 +163,77 @@ func (handler *EdgeRouterHandler) QueryRoleAttributes(queryString string) ([]str
|
||||
return handler.queryRoleAttributes(index, queryString)
|
||||
}
|
||||
|
||||
func (handler *EdgeRouterHandler) CreateWithEnrollment(edgeRouter *EdgeRouter, enrollment *Enrollment) (string, string, error) {
|
||||
if edgeRouter.Id == "" {
|
||||
edgeRouter.Id = uuid.New().String()
|
||||
}
|
||||
|
||||
if enrollment.Id == "" {
|
||||
enrollment.Id = uuid.New().String()
|
||||
}
|
||||
|
||||
err := handler.GetDb().Update(func(tx *bbolt.Tx) error {
|
||||
ctx := boltz.NewMutateContext(tx)
|
||||
boltEdgeRouter, err := edgeRouter.toBoltEntityForCreate(tx, handler.impl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handler.GetStore().Create(ctx, boltEdgeRouter); err != nil {
|
||||
pfxlog.Logger().WithError(err).Errorf("could not create %v in bolt storage", handler.GetStore().GetSingularEntityType())
|
||||
return err
|
||||
}
|
||||
|
||||
enrollment.EdgeRouterId = &edgeRouter.Id
|
||||
|
||||
err = enrollment.FillJwtInfo(handler.env, edgeRouter.Id)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = handler.env.GetHandlers().Enrollment.createEntityInTx(ctx, enrollment)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return edgeRouter.Id, enrollment.Id, nil
|
||||
}
|
||||
|
||||
func (handler *EdgeRouterHandler) CollectEnrollments(id string, collector func(entity *Enrollment) error) error {
|
||||
return handler.GetDb().View(func(tx *bbolt.Tx) error {
|
||||
return handler.collectEnrollmentsInTx(tx, id, collector)
|
||||
})
|
||||
}
|
||||
|
||||
func (handler *EdgeRouterHandler) collectEnrollmentsInTx(tx *bbolt.Tx, id string, collector func(entity *Enrollment) error) error {
|
||||
_, err := handler.readInTx(tx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
associationIds := handler.GetStore().GetRelatedEntitiesIdList(tx, id, persistence.FieldEdgeRouterEnrollments)
|
||||
for _, enrollmentId := range associationIds {
|
||||
enrollment, err := handler.env.GetHandlers().Enrollment.readInTx(tx, enrollmentId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = collector(enrollment)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type EdgeRouterListResult struct {
|
||||
handler *EdgeRouterHandler
|
||||
EdgeRouters []*EdgeRouter
|
||||
|
||||
@@ -17,17 +17,12 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/google/uuid"
|
||||
"github.com/netfoundry/ziti-edge/controller/persistence"
|
||||
"github.com/netfoundry/ziti-fabric/controller/models"
|
||||
"github.com/netfoundry/ziti-foundation/storage/boltz"
|
||||
"github.com/netfoundry/ziti-sdk-golang/ziti/config"
|
||||
"github.com/pkg/errors"
|
||||
"go.etcd.io/bbolt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type EdgeRouter struct {
|
||||
@@ -37,57 +32,19 @@ type EdgeRouter struct {
|
||||
IsVerified bool
|
||||
Fingerprint *string
|
||||
CertPem *string
|
||||
EnrollmentToken *string
|
||||
Hostname *string
|
||||
EnrollmentJwt *string
|
||||
EnrollmentCreatedAt *time.Time
|
||||
EnrollmentExpiresAt *time.Time
|
||||
EdgeRouterProtocols map[string]string
|
||||
}
|
||||
|
||||
func (entity *EdgeRouter) toBoltEntityForCreate(_ *bbolt.Tx, handler Handler) (boltz.Entity, error) {
|
||||
et := uuid.New().String()
|
||||
|
||||
boltEntity := &persistence.EdgeRouter{
|
||||
BaseExtEntity: *boltz.NewExtEntity(entity.Id, entity.Tags),
|
||||
Name: entity.Name,
|
||||
RoleAttributes: entity.RoleAttributes,
|
||||
Fingerprint: nil,
|
||||
IsVerified: false,
|
||||
EnrollmentToken: &et,
|
||||
BaseExtEntity: *boltz.NewExtEntity(entity.Id, entity.Tags),
|
||||
Name: entity.Name,
|
||||
RoleAttributes: entity.RoleAttributes,
|
||||
Fingerprint: nil,
|
||||
IsVerified: false,
|
||||
}
|
||||
env := handler.GetEnv()
|
||||
|
||||
now := time.Now()
|
||||
exp := now.Add(env.GetConfig().Enrollment.EdgeRouter.DurationMinutes)
|
||||
|
||||
boltEntity.EnrollmentCreatedAt = &now
|
||||
boltEntity.EnrollmentExpiresAt = &exp
|
||||
|
||||
enrollmentMethod := "erott"
|
||||
|
||||
claims := &config.EnrollmentClaims{
|
||||
EnrollmentMethod: enrollmentMethod,
|
||||
StandardClaims: jwt.StandardClaims{
|
||||
ExpiresAt: exp.Unix(),
|
||||
Id: *boltEntity.EnrollmentToken,
|
||||
Issuer: fmt.Sprintf(`https://%s`, env.GetConfig().Api.Advertise),
|
||||
Subject: boltEntity.Id,
|
||||
},
|
||||
}
|
||||
mapClaims, err := claims.ToMapClaims()
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not convert edge router enrollment claims to interface map: %s", err)
|
||||
}
|
||||
|
||||
jwtJson, err := env.GetEnrollmentJwtGenerator().Generate(boltEntity.Id, boltEntity.Id, mapClaims)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
boltEntity.EnrollmentJwt = &jwtJson
|
||||
|
||||
return boltEntity, nil
|
||||
}
|
||||
@@ -100,11 +57,7 @@ func (entity *EdgeRouter) toBoltEntityForUpdate(_ *bbolt.Tx, _ Handler) (boltz.E
|
||||
IsVerified: entity.IsVerified,
|
||||
Fingerprint: entity.Fingerprint,
|
||||
CertPem: entity.CertPem,
|
||||
EnrollmentToken: entity.EnrollmentToken,
|
||||
Hostname: entity.Hostname,
|
||||
EnrollmentJwt: entity.EnrollmentJwt,
|
||||
EnrollmentCreatedAt: entity.EnrollmentCreatedAt,
|
||||
EnrollmentExpiresAt: entity.EnrollmentExpiresAt,
|
||||
EdgeRouterProtocols: entity.EdgeRouterProtocols,
|
||||
}, nil
|
||||
}
|
||||
@@ -125,11 +78,7 @@ func (entity *EdgeRouter) fillFrom(_ Handler, _ *bbolt.Tx, boltEntity boltz.Enti
|
||||
entity.IsVerified = boltEdgeRouter.IsVerified
|
||||
entity.Fingerprint = boltEdgeRouter.Fingerprint
|
||||
entity.CertPem = boltEdgeRouter.CertPem
|
||||
entity.EnrollmentToken = boltEdgeRouter.EnrollmentToken
|
||||
entity.Hostname = boltEdgeRouter.Hostname
|
||||
entity.EnrollmentJwt = boltEdgeRouter.EnrollmentJwt
|
||||
entity.EnrollmentCreatedAt = boltEdgeRouter.EnrollmentCreatedAt
|
||||
entity.EnrollmentExpiresAt = boltEdgeRouter.EnrollmentExpiresAt
|
||||
entity.EdgeRouterProtocols = boltEdgeRouter.EdgeRouterProtocols
|
||||
|
||||
return nil
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/netfoundry/ziti-edge/controller/apierror"
|
||||
"github.com/netfoundry/ziti-edge/controller/persistence"
|
||||
"github.com/netfoundry/ziti-foundation/storage/boltz"
|
||||
@@ -57,22 +56,11 @@ func (handler *EnrollmentHandler) getEnrollmentMethod(ctx EnrollmentContext) (st
|
||||
}
|
||||
|
||||
if enrollment == nil {
|
||||
edgeRouter, err := handler.env.GetHandlers().EdgeRouter.ReadOneByQuery(fmt.Sprintf("enrollmentToken = \"%v\"", ctx.GetToken()))
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if edgeRouter != nil {
|
||||
method = MethodEnrollErOtt
|
||||
} else {
|
||||
return "", apierror.NewInvalidEnrollmentToken()
|
||||
}
|
||||
|
||||
} else {
|
||||
method = enrollment.Method
|
||||
return "", apierror.NewInvalidEnrollmentToken()
|
||||
}
|
||||
|
||||
method = enrollment.Method
|
||||
|
||||
return method, nil
|
||||
}
|
||||
|
||||
@@ -142,3 +130,11 @@ func (handler *EnrollmentHandler) readInTx(tx *bbolt.Tx, id string) (*Enrollment
|
||||
func (handler *EnrollmentHandler) Delete(id string) error {
|
||||
return handler.deleteEntity(id)
|
||||
}
|
||||
|
||||
func (handler *EnrollmentHandler) Read(id string) (*Enrollment, error) {
|
||||
entity := &Enrollment{}
|
||||
if err := handler.readEntity(id, entity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return entity, nil
|
||||
}
|
||||
|
||||
@@ -31,8 +31,7 @@ import (
|
||||
const (
|
||||
EdgeRouterEnrollmentCommonNameInvalidCode = "EDGE_ROUTER_ENROLL_COMMON_NAME_INVALID"
|
||||
EdgeRouterEnrollmentCommonNameInvalidMessage = "The edge router CSR enrollment must have a common name that matches the edge router's id"
|
||||
|
||||
MethodEnrollErOtt = "erott"
|
||||
MethodEnrollEdgeRouterOtt = "erott"
|
||||
)
|
||||
|
||||
type EnrollModuleEr struct {
|
||||
@@ -41,10 +40,10 @@ type EnrollModuleEr struct {
|
||||
fingerprintGenerator cert.FingerprintGenerator
|
||||
}
|
||||
|
||||
func NewEnrollModuleEr(env Env) *EnrollModuleEr {
|
||||
func NewEnrollModuleEdgeRouterOtt(env Env) *EnrollModuleEr {
|
||||
handler := &EnrollModuleEr{
|
||||
env: env,
|
||||
method: MethodEnrollErOtt,
|
||||
method: MethodEnrollEdgeRouterOtt,
|
||||
fingerprintGenerator: cert.NewFingerprintGenerator(),
|
||||
}
|
||||
|
||||
@@ -56,18 +55,23 @@ func (module *EnrollModuleEr) CanHandle(method string) bool {
|
||||
}
|
||||
|
||||
func (module *EnrollModuleEr) Process(context EnrollmentContext) (*EnrollmentResult, error) {
|
||||
query := fmt.Sprintf(`isVerified = false and enrollmentToken = "%v"`, context.GetToken())
|
||||
gw, err := module.env.GetHandlers().EdgeRouter.ReadOneByQuery(query)
|
||||
enrollment, err := module.env.GetHandlers().Enrollment.ReadByToken(context.GetToken())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gw == nil {
|
||||
if enrollment == nil || enrollment.EdgeRouterId == nil {
|
||||
return nil, apierror.NewInvalidEnrollmentToken()
|
||||
}
|
||||
|
||||
if time.Now().After(*gw.EnrollmentExpiresAt) {
|
||||
edgeRouter, err := module.env.GetHandlers().EdgeRouter.Read(*enrollment.EdgeRouterId)
|
||||
|
||||
if edgeRouter == nil {
|
||||
return nil, apierror.NewInvalidEnrollmentToken()
|
||||
}
|
||||
|
||||
if time.Now().After(*enrollment.ExpiresAt) {
|
||||
return nil, apierror.NewEnrollmentExpired()
|
||||
}
|
||||
|
||||
@@ -136,7 +140,7 @@ func (module *EnrollModuleEr) Process(context EnrollmentContext) (*EnrollmentRes
|
||||
URIs: cr.URIs,
|
||||
}
|
||||
|
||||
if cr.Subject.CommonName != gw.Id {
|
||||
if cr.Subject.CommonName != edgeRouter.Id {
|
||||
|
||||
return nil, &apierror.ApiError{
|
||||
Code: EdgeRouterEnrollmentCommonNameInvalidCode,
|
||||
@@ -162,16 +166,16 @@ func (module *EnrollModuleEr) Process(context EnrollmentContext) (*EnrollmentRes
|
||||
|
||||
cltFp := module.fingerprintGenerator.FromPem(cltPem)
|
||||
|
||||
gw.IsVerified = true
|
||||
gw.EnrollmentCreatedAt = nil
|
||||
gw.EnrollmentExpiresAt = nil
|
||||
gw.EnrollmentJwt = nil
|
||||
gw.EnrollmentToken = nil
|
||||
gw.Fingerprint = &cltFp
|
||||
if err := module.env.GetHandlers().EdgeRouter.Update(gw, false); err != nil {
|
||||
edgeRouter.IsVerified = true
|
||||
edgeRouter.Fingerprint = &cltFp
|
||||
if err := module.env.GetHandlers().EdgeRouter.Update(edgeRouter, false); err != nil {
|
||||
return nil, fmt.Errorf("could not update edge router: %s", err)
|
||||
}
|
||||
|
||||
if err := module.env.GetHandlers().Enrollment.Delete(enrollment.Id); err != nil {
|
||||
return nil, fmt.Errorf("could not delete enrollment: %s", err)
|
||||
}
|
||||
|
||||
if err := module.createRouter(cr.Subject.CommonName, cltFp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -51,11 +51,11 @@ func (module *EnrollModuleOtt) Process(ctx EnrollmentContext) (*EnrollmentResult
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if enrollment == nil {
|
||||
if enrollment == nil || enrollment.IdentityId == nil {
|
||||
return nil, apierror.NewInvalidEnrollmentToken()
|
||||
}
|
||||
|
||||
identity, err := module.env.GetHandlers().Identity.Read(enrollment.IdentityId)
|
||||
identity, err := module.env.GetHandlers().Identity.Read(*enrollment.IdentityId)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -86,7 +86,7 @@ func (module *EnrollModuleOtt) Process(ctx EnrollmentContext) (*EnrollmentResult
|
||||
Id: uuid.New().String(),
|
||||
},
|
||||
Method: persistence.MethodAuthenticatorCert,
|
||||
IdentityId: enrollment.IdentityId,
|
||||
IdentityId: *enrollment.IdentityId,
|
||||
SubType: &AuthenticatorCert{
|
||||
Fingerprint: fp,
|
||||
Pem: string(certPem),
|
||||
|
||||
@@ -51,11 +51,11 @@ func (module *EnrollModuleOttCa) Process(ctx EnrollmentContext) (*EnrollmentResu
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if enrollment == nil {
|
||||
if enrollment == nil || enrollment.IdentityId == nil {
|
||||
return nil, apierror.NewInvalidEnrollmentToken()
|
||||
}
|
||||
|
||||
identity, err := module.env.GetHandlers().Identity.Read(enrollment.IdentityId)
|
||||
identity, err := module.env.GetHandlers().Identity.Read(*enrollment.IdentityId)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
Copyright NetFoundry, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/netfoundry/ziti-edge/controller/apierror"
|
||||
"github.com/netfoundry/ziti-edge/controller/validation"
|
||||
"github.com/netfoundry/ziti-edge/internal/cert"
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
MethodEnrollTransitRouterOtt = "trott"
|
||||
)
|
||||
|
||||
type EnrollModuleRouterOtt struct {
|
||||
env Env
|
||||
method string
|
||||
fingerprintGenerator cert.FingerprintGenerator
|
||||
}
|
||||
|
||||
func NewEnrollModuleTransitRouterOtt(env Env) *EnrollModuleRouterOtt {
|
||||
handler := &EnrollModuleRouterOtt{
|
||||
env: env,
|
||||
method: MethodEnrollTransitRouterOtt,
|
||||
fingerprintGenerator: cert.NewFingerprintGenerator(),
|
||||
}
|
||||
|
||||
return handler
|
||||
}
|
||||
|
||||
func (module *EnrollModuleRouterOtt) CanHandle(method string) bool {
|
||||
return method == module.method
|
||||
}
|
||||
|
||||
func (module *EnrollModuleRouterOtt) Process(context EnrollmentContext) (*EnrollmentResult, error) {
|
||||
enrollment, err := module.env.GetHandlers().Enrollment.ReadByToken(context.GetToken())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if enrollment == nil || enrollment.TransitRouterId == nil {
|
||||
return nil, apierror.NewInvalidEnrollmentToken()
|
||||
}
|
||||
|
||||
txRouter, err := module.env.GetHandlers().TransitRouter.Read(*enrollment.TransitRouterId)
|
||||
|
||||
if txRouter == nil {
|
||||
return nil, apierror.NewInvalidEnrollmentToken()
|
||||
}
|
||||
|
||||
if time.Now().After(*enrollment.ExpiresAt) {
|
||||
return nil, apierror.NewEnrollmentExpired()
|
||||
}
|
||||
enrollData := context.GetDataAsMap()
|
||||
result, err := module.env.GetSchemas().GetEnrollErPost().Validate(gojsonschema.NewGoLoader(enrollData))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !result.Valid() {
|
||||
var errs []*validation.SchemaValidationError
|
||||
for _, re := range result.Errors() {
|
||||
errs = append(errs, validation.NewValidationError(re))
|
||||
}
|
||||
apiError := apierror.NewCouldNotValidate()
|
||||
|
||||
if len(errs) > 0 {
|
||||
apiError.Cause = errs[0]
|
||||
apiError.AppendCause = true
|
||||
}
|
||||
|
||||
return nil, apiError
|
||||
}
|
||||
|
||||
sr, err := cert.ParseCsr([]byte(enrollData["serverCertCsr"].(string)))
|
||||
|
||||
if err != nil {
|
||||
apiErr := apierror.NewCouldNotProcessCsr()
|
||||
apiErr.Cause = err
|
||||
apiErr.AppendCause = true
|
||||
return nil, apiErr
|
||||
}
|
||||
|
||||
so := &cert.SigningOpts{
|
||||
DNSNames: sr.DNSNames,
|
||||
EmailAddresses: sr.EmailAddresses,
|
||||
IPAddresses: sr.IPAddresses,
|
||||
URIs: sr.URIs,
|
||||
}
|
||||
|
||||
srvCert, err := module.env.GetApiServerCsrSigner().Sign([]byte(enrollData["serverCertCsr"].(string)), so)
|
||||
|
||||
if err != nil {
|
||||
return nil, apierror.NewCouldNotProcessCsr()
|
||||
}
|
||||
|
||||
srvPem, err := module.env.GetApiServerCsrSigner().ToPem(srvCert)
|
||||
|
||||
srvChain := string(srvPem) + module.env.GetApiServerCsrSigner().SigningCertPEM()
|
||||
|
||||
if err != nil {
|
||||
return nil, apierror.NewCouldNotProcessCsr()
|
||||
}
|
||||
|
||||
cr, err := cert.ParseCsr([]byte(enrollData["certCsr"].(string)))
|
||||
|
||||
if err != nil {
|
||||
return nil, apierror.NewCouldNotProcessCsr()
|
||||
}
|
||||
|
||||
so = &cert.SigningOpts{
|
||||
DNSNames: cr.DNSNames,
|
||||
EmailAddresses: cr.EmailAddresses,
|
||||
IPAddresses: cr.IPAddresses,
|
||||
URIs: cr.URIs,
|
||||
}
|
||||
|
||||
cr.Subject.CommonName = txRouter.Id
|
||||
|
||||
cltCert, err := module.env.GetControlClientCsrSigner().Sign([]byte(enrollData["certCsr"].(string)), so)
|
||||
|
||||
if err != nil {
|
||||
return nil, apierror.NewCouldNotProcessCsr()
|
||||
}
|
||||
|
||||
cltPem, err := module.env.GetControlClientCsrSigner().ToPem(cltCert)
|
||||
|
||||
if err != nil {
|
||||
return nil, apierror.NewCouldNotProcessCsr()
|
||||
}
|
||||
|
||||
cltFp := module.fingerprintGenerator.FromPem(cltPem)
|
||||
|
||||
txRouter.IsVerified = true
|
||||
txRouter.Fingerprint = cltFp
|
||||
|
||||
if err := module.env.GetHandlers().TransitRouter.Update(txRouter); err != nil {
|
||||
return nil, fmt.Errorf("could not update edge router: %s", err)
|
||||
}
|
||||
|
||||
if err := module.env.GetHandlers().Enrollment.Delete(enrollment.Id); err != nil {
|
||||
return nil, fmt.Errorf("could not delete enrollment: %s", err)
|
||||
}
|
||||
|
||||
content, err := json.Marshal(&map[string]interface{}{
|
||||
"serverCert": srvChain,
|
||||
"cert": string(cltPem),
|
||||
"ca": string(module.env.GetConfig().CaPems()),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EnrollmentResult{
|
||||
Identity: nil,
|
||||
Authenticator: nil,
|
||||
Content: content,
|
||||
ContentType: "application/json",
|
||||
Status: 200,
|
||||
}, nil
|
||||
}
|
||||
@@ -54,11 +54,11 @@ func (module *EnrollModuleUpdb) Process(ctx EnrollmentContext) (*EnrollmentResul
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if enrollment == nil {
|
||||
if enrollment == nil || enrollment.IdentityId == nil {
|
||||
return nil, apierror.NewInvalidEnrollmentToken()
|
||||
}
|
||||
|
||||
identity, err := module.env.GetHandlers().Identity.Read(enrollment.IdentityId)
|
||||
identity, err := module.env.GetHandlers().Identity.Read(*enrollment.IdentityId)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -98,7 +98,7 @@ func (module *EnrollModuleUpdb) Process(ctx EnrollmentContext) (*EnrollmentResul
|
||||
Id: uuid.New().String(),
|
||||
},
|
||||
Method: persistence.MethodAuthenticatorUpdb,
|
||||
IdentityId: enrollment.IdentityId,
|
||||
IdentityId: *enrollment.IdentityId,
|
||||
SubType: &AuthenticatorUpdb{
|
||||
Username: *enrollment.Username,
|
||||
Password: encodedPassword,
|
||||
|
||||
@@ -33,17 +33,19 @@ import (
|
||||
|
||||
type Enrollment struct {
|
||||
models.BaseEntity
|
||||
Method string
|
||||
IdentityId string
|
||||
Token string
|
||||
IssuedAt *time.Time
|
||||
ExpiresAt *time.Time
|
||||
Jwt string
|
||||
CaId *string
|
||||
Username *string
|
||||
Method string
|
||||
IdentityId *string
|
||||
TransitRouterId *string
|
||||
EdgeRouterId *string
|
||||
Token string
|
||||
IssuedAt *time.Time
|
||||
ExpiresAt *time.Time
|
||||
Jwt string
|
||||
CaId *string
|
||||
Username *string
|
||||
}
|
||||
|
||||
func (entity *Enrollment) FillJwtInfo(env Env) error {
|
||||
func (entity *Enrollment) FillJwtInfo(env Env, subject string) error {
|
||||
now := time.Now()
|
||||
expiresAt := now.Add(env.GetConfig().Enrollment.EdgeIdentity.DurationMinutes)
|
||||
entity.IssuedAt = &now
|
||||
@@ -61,7 +63,7 @@ func (entity *Enrollment) FillJwtInfo(env Env) error {
|
||||
Id: entity.Token,
|
||||
Issuer: fmt.Sprintf("https://%s", env.GetConfig().Api.Advertise),
|
||||
NotBefore: 0,
|
||||
Subject: entity.IdentityId,
|
||||
Subject: subject,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -71,7 +73,7 @@ func (entity *Enrollment) FillJwtInfo(env Env) error {
|
||||
return err
|
||||
}
|
||||
|
||||
signedJwt, err := env.GetEnrollmentJwtGenerator().Generate(entity.IdentityId, entity.Id, mapClaims)
|
||||
signedJwt, err := env.GetEnrollmentJwtGenerator().Generate(subject, entity.Id, mapClaims)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -90,6 +92,8 @@ func (entity *Enrollment) fillFrom(_ Handler, _ *bbolt.Tx, boltEntity boltz.Enti
|
||||
entity.FillCommon(boltEnrollment)
|
||||
entity.Method = boltEnrollment.Method
|
||||
entity.IdentityId = boltEnrollment.IdentityId
|
||||
entity.TransitRouterId = boltEnrollment.TransitRouterId
|
||||
entity.EdgeRouterId = boltEnrollment.EdgeRouterId
|
||||
entity.CaId = boltEnrollment.CaId
|
||||
entity.Username = boltEnrollment.Username
|
||||
entity.Token = boltEnrollment.Token
|
||||
@@ -120,15 +124,17 @@ func (entity *Enrollment) toBoltEntity(handler Handler) (boltz.Entity, error) {
|
||||
}
|
||||
|
||||
boltEntity := &persistence.Enrollment{
|
||||
BaseExtEntity: *boltz.NewExtEntity(entity.Id, entity.Tags),
|
||||
Method: entity.Method,
|
||||
IdentityId: entity.IdentityId,
|
||||
Token: entity.Token,
|
||||
IssuedAt: entity.IssuedAt,
|
||||
ExpiresAt: entity.ExpiresAt,
|
||||
Jwt: entity.Jwt,
|
||||
CaId: entity.CaId,
|
||||
Username: entity.Username,
|
||||
BaseExtEntity: *boltz.NewExtEntity(entity.Id, entity.Tags),
|
||||
Method: entity.Method,
|
||||
IdentityId: entity.IdentityId,
|
||||
EdgeRouterId: entity.EdgeRouterId,
|
||||
TransitRouterId: entity.TransitRouterId,
|
||||
Token: entity.Token,
|
||||
IssuedAt: entity.IssuedAt,
|
||||
ExpiresAt: entity.ExpiresAt,
|
||||
Jwt: entity.Jwt,
|
||||
CaId: entity.CaId,
|
||||
Username: entity.Username,
|
||||
}
|
||||
|
||||
return boltEntity, nil
|
||||
|
||||
@@ -33,6 +33,7 @@ type Handlers struct {
|
||||
EdgeRouterPolicy *EdgeRouterPolicyHandler
|
||||
EdgeService *EdgeServiceHandler
|
||||
EventLog *EventLogHandler
|
||||
TransitRouter *TransitRouterHandler
|
||||
GeoRegion *GeoRegionHandler
|
||||
Identity *IdentityHandler
|
||||
IdentityType *IdentityTypeHandler
|
||||
@@ -64,6 +65,7 @@ func InitHandlers(env Env) *Handlers {
|
||||
handlers.Identity = NewIdentityHandler(env)
|
||||
handlers.IdentityType = NewIdentityTypeHandler(env)
|
||||
handlers.EdgeService = NewEdgeServiceHandler(env)
|
||||
handlers.TransitRouter = NewTransitRouterHandler(env)
|
||||
handlers.ServiceEdgeRouterPolicy = NewServiceEdgeRouterPolicyHandler(env)
|
||||
handlers.ServicePolicy = NewServicePolicyHandler(env)
|
||||
handlers.Session = NewSessionHandler(env)
|
||||
|
||||
@@ -104,9 +104,9 @@ func (handler *IdentityHandler) CreateWithEnrollments(identityModel *Identity, e
|
||||
}
|
||||
|
||||
for _, enrollmentModel := range enrollmentsModels {
|
||||
enrollmentModel.IdentityId = identityModel.Id
|
||||
enrollmentModel.IdentityId = &identityModel.Id
|
||||
|
||||
err := enrollmentModel.FillJwtInfo(handler.env)
|
||||
err := enrollmentModel.FillJwtInfo(handler.env, identityModel.Id)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
Copyright NetFoundry, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/michaelquigley/pfxlog"
|
||||
"github.com/netfoundry/ziti-edge/controller/persistence"
|
||||
"github.com/netfoundry/ziti-fabric/controller/models"
|
||||
"github.com/netfoundry/ziti-foundation/storage/boltz"
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
func NewTransitRouterHandler(env Env) *TransitRouterHandler {
|
||||
handler := &TransitRouterHandler{
|
||||
baseHandler: newBaseHandler(env, env.GetStores().TransitRouter),
|
||||
}
|
||||
handler.impl = handler
|
||||
return handler
|
||||
}
|
||||
|
||||
type TransitRouterHandler struct {
|
||||
baseHandler
|
||||
}
|
||||
|
||||
func (handler *TransitRouterHandler) Delete(id string) error {
|
||||
return handler.deleteEntity(id)
|
||||
}
|
||||
|
||||
func (handler *TransitRouterHandler) newModelEntity() boltEntitySink {
|
||||
return &TransitRouter{}
|
||||
}
|
||||
|
||||
func (handler *TransitRouterHandler) Create(entity *TransitRouter) (string, error) {
|
||||
enrollment := &Enrollment{
|
||||
BaseEntity: models.BaseEntity{},
|
||||
Method: MethodEnrollTransitRouterOtt,
|
||||
}
|
||||
|
||||
id, _, err := handler.CreateWithEnrollment(entity, enrollment)
|
||||
return id, err
|
||||
}
|
||||
|
||||
func (handler *TransitRouterHandler) CreateWithEnrollment(txRouter *TransitRouter, enrollment *Enrollment) (string, string, error) {
|
||||
|
||||
if txRouter.Id == "" {
|
||||
txRouter.Id = uuid.New().String()
|
||||
}
|
||||
var enrollmentId string
|
||||
|
||||
err := handler.GetDb().Update(func(tx *bbolt.Tx) error {
|
||||
ctx := boltz.NewMutateContext(tx)
|
||||
boltEntity, err := txRouter.toBoltEntityForCreate(tx, handler.impl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := handler.GetStore().Create(ctx, boltEntity); err != nil {
|
||||
pfxlog.Logger().WithError(err).Errorf("could not create %v in bolt storage", handler.GetStore().GetSingularEntityType())
|
||||
return err
|
||||
}
|
||||
|
||||
enrollment.TransitRouterId = &txRouter.Id
|
||||
|
||||
err = enrollment.FillJwtInfo(handler.env, txRouter.Id)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
enrollmentId, err = handler.env.GetHandlers().Enrollment.createEntityInTx(ctx, enrollment)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
return txRouter.Id, enrollmentId, nil
|
||||
}
|
||||
|
||||
func (handler *TransitRouterHandler) Update(entity *TransitRouter) error {
|
||||
return handler.updateEntity(entity, nil)
|
||||
}
|
||||
|
||||
func (handler *TransitRouterHandler) Patch(entity *TransitRouter, checker boltz.FieldChecker) error {
|
||||
return handler.patchEntity(entity, checker)
|
||||
}
|
||||
|
||||
func (handler *TransitRouterHandler) ReadOneByQuery(query string) (*TransitRouter, error) {
|
||||
result, err := handler.readEntityByQuery(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return result.(*TransitRouter), nil
|
||||
}
|
||||
|
||||
func (handler *TransitRouterHandler) Read(id string) (*TransitRouter, error) {
|
||||
result := &TransitRouter{}
|
||||
|
||||
if err := handler.readEntity(id, result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (handler *TransitRouterHandler) readInTx(tx *bbolt.Tx, id string) (*TransitRouter, error) {
|
||||
modelEntity := &TransitRouter{}
|
||||
if err := handler.readEntityInTx(tx, id, modelEntity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return modelEntity, nil
|
||||
}
|
||||
|
||||
func (handler *TransitRouterHandler) CollectEnrollments(id string, collector func(entity *Enrollment) error) error {
|
||||
return handler.GetDb().View(func(tx *bbolt.Tx) error {
|
||||
return handler.collectEnrollmentsInTx(tx, id, collector)
|
||||
})
|
||||
}
|
||||
|
||||
func (handler *TransitRouterHandler) collectEnrollmentsInTx(tx *bbolt.Tx, id string, collector func(entity *Enrollment) error) error {
|
||||
_, err := handler.readInTx(tx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
associationIds := handler.GetStore().GetRelatedEntitiesIdList(tx, id, persistence.FieldTransitRouterEnrollments)
|
||||
for _, enrollmentId := range associationIds {
|
||||
enrollment, err := handler.env.GetHandlers().Enrollment.readInTx(tx, enrollmentId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = collector(enrollment)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
Copyright NetFoundry, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/netfoundry/ziti-edge/controller/persistence"
|
||||
"github.com/netfoundry/ziti-fabric/controller/db"
|
||||
"github.com/netfoundry/ziti-fabric/controller/models"
|
||||
"github.com/netfoundry/ziti-foundation/storage/boltz"
|
||||
"github.com/pkg/errors"
|
||||
"go.etcd.io/bbolt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type TransitRouter struct {
|
||||
models.BaseEntity
|
||||
Name string
|
||||
Fingerprint string
|
||||
IsVerified bool
|
||||
IsBase bool
|
||||
}
|
||||
|
||||
func (entity *TransitRouter) toBoltEntityForCreate(tx *bbolt.Tx, handler Handler) (boltz.Entity, error) {
|
||||
boltEntity := &persistence.TransitRouter{
|
||||
Router: db.Router{
|
||||
BaseExtEntity: *boltz.NewExtEntity(entity.Id, entity.Tags),
|
||||
Fingerprint: entity.Fingerprint,
|
||||
},
|
||||
Name: entity.Name,
|
||||
IsVerified: false,
|
||||
}
|
||||
|
||||
return boltEntity, nil
|
||||
}
|
||||
|
||||
func (entity *TransitRouter) toBoltEntityForUpdate(tx *bbolt.Tx, handler Handler) (boltz.Entity, error) {
|
||||
ret := &persistence.TransitRouter{
|
||||
Router: db.Router{
|
||||
BaseExtEntity: *boltz.NewExtEntity(entity.Id, entity.Tags),
|
||||
},
|
||||
Name: entity.Name,
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (entity *TransitRouter) toBoltEntityForPatch(tx *bbolt.Tx, handler Handler) (boltz.Entity, error) {
|
||||
return entity.toBoltEntityForUpdate(tx, handler)
|
||||
}
|
||||
|
||||
func (entity *TransitRouter) fillFrom(_ Handler, _ *bbolt.Tx, boltEntity boltz.Entity) error {
|
||||
boltTransitRouter, ok := boltEntity.(*persistence.TransitRouter)
|
||||
if !ok {
|
||||
return errors.Errorf("unexpected type %v when filling model transitRouter", reflect.TypeOf(boltEntity))
|
||||
}
|
||||
entity.FillCommon(boltTransitRouter)
|
||||
entity.Name = boltTransitRouter.Name
|
||||
entity.IsVerified = boltTransitRouter.IsVerified
|
||||
entity.IsBase = boltTransitRouter.IsBase
|
||||
entity.Fingerprint = boltTransitRouter.Fingerprint
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -26,6 +26,7 @@ const (
|
||||
EntityTypeConfigs = "configs"
|
||||
EntityTypeConfigTypes = "configTypes"
|
||||
EntityTypeEdgeRouters = "edgeRouters"
|
||||
EntityTypeTransitRouters = "transitRouters"
|
||||
EntityTypeEdgeRouterPolicies = "edgeRouterPolicies"
|
||||
EntityTypeEventLogs = "eventLogs"
|
||||
EntityTypeGeoRegions = "geoRegions"
|
||||
|
||||
@@ -64,6 +64,12 @@ func newChildBaseStore(stores *stores, parent boltz.CrudStore, entityType string
|
||||
}
|
||||
}
|
||||
|
||||
func newExtendedBaseStore(stores *stores, parent boltz.CrudStore, entityType string) *baseStore {
|
||||
store := newChildBaseStore(stores, parent, entityType)
|
||||
store.BaseStore.Extended()
|
||||
return store
|
||||
}
|
||||
|
||||
type baseStore struct {
|
||||
stores *stores
|
||||
*boltz.BaseStore
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package persistence
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"github.com/netfoundry/ziti-foundation/storage/ast"
|
||||
"github.com/netfoundry/ziti-foundation/storage/boltz"
|
||||
@@ -26,16 +27,15 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
FieldEdgeRouterFingerprint = "fingerprint"
|
||||
FieldEdgeRouterCertPEM = "certPem"
|
||||
FieldEdgeRouterCluster = "cluster"
|
||||
FieldEdgeRouterIsVerified = "isVerified"
|
||||
FieldEdgeRouterEnrollmentToken = "enrollmentToken"
|
||||
FieldEdgeRouterHostname = "hostname"
|
||||
FieldEdgeRouterEnrollmentJwt = "enrollmentJwt"
|
||||
FieldEdgeRouterEnrollmentCreatedAt = "enrollmentCreatedAt"
|
||||
FieldEdgeRouterEnrollmentExpiresAt = "enrollmentExpiresAt"
|
||||
FieldEdgeRouterProtocols = "protocols"
|
||||
FieldEdgeRouterFingerprint = "fingerprint"
|
||||
FieldEdgeRouterCertPEM = "certPem"
|
||||
FieldEdgeRouterCluster = "cluster"
|
||||
FieldEdgeRouterIsVerified = "isVerified"
|
||||
FieldEdgeRouterHostname = "hostname"
|
||||
FieldEdgeRouterProtocols = "protocols"
|
||||
FieldEdgeRouterEnrollments = "enrollments"
|
||||
|
||||
MethodEnrollEdgeRouterOtt = "erott"
|
||||
)
|
||||
|
||||
func newEdgeRouter(name string, roleAttributes ...string) *EdgeRouter {
|
||||
@@ -53,13 +53,16 @@ type EdgeRouter struct {
|
||||
IsVerified bool
|
||||
Fingerprint *string
|
||||
CertPem *string
|
||||
EnrollmentToken *string
|
||||
Hostname *string
|
||||
EdgeRouterProtocols map[string]string
|
||||
RoleAttributes []string
|
||||
Enrollments []string
|
||||
|
||||
//old v4, migrations only
|
||||
EnrollmentToken *string
|
||||
EnrollmentJwt *string
|
||||
EnrollmentCreatedAt *time.Time
|
||||
EnrollmentExpiresAt *time.Time
|
||||
EdgeRouterProtocols map[string]string
|
||||
RoleAttributes []string
|
||||
}
|
||||
|
||||
var edgeRouterFieldMappings = map[string]string{FieldEdgeRouterCluster: "clusterId"}
|
||||
@@ -72,11 +75,9 @@ func (entity *EdgeRouter) LoadValues(_ boltz.CrudStore, bucket *boltz.TypedBucke
|
||||
entity.ClusterId = bucket.GetString(FieldEdgeRouterCluster)
|
||||
entity.IsVerified = bucket.GetBoolWithDefault(FieldEdgeRouterIsVerified, false)
|
||||
|
||||
entity.EnrollmentToken = bucket.GetString(FieldEdgeRouterEnrollmentToken)
|
||||
//old v4, migrations only
|
||||
entity.Enrollments = bucket.GetStringList(FieldEdgeRouterEnrollments)
|
||||
entity.Hostname = bucket.GetString(FieldEdgeRouterHostname)
|
||||
entity.EnrollmentJwt = bucket.GetString(FieldEdgeRouterEnrollmentJwt)
|
||||
entity.EnrollmentCreatedAt = bucket.GetTime(FieldEdgeRouterEnrollmentCreatedAt)
|
||||
entity.EnrollmentExpiresAt = bucket.GetTime(FieldEdgeRouterEnrollmentExpiresAt)
|
||||
entity.EdgeRouterProtocols = toStringStringMap(bucket.GetMap(FieldEdgeRouterProtocols))
|
||||
entity.RoleAttributes = bucket.GetStringList(FieldRoleAttributes)
|
||||
}
|
||||
@@ -91,13 +92,10 @@ func (entity *EdgeRouter) SetValues(ctx *boltz.PersistContext) {
|
||||
ctx.SetStringP(FieldEdgeRouterCertPEM, entity.CertPem)
|
||||
ctx.SetStringP(FieldEdgeRouterCluster, entity.ClusterId)
|
||||
ctx.SetBool(FieldEdgeRouterIsVerified, entity.IsVerified)
|
||||
ctx.SetStringP(FieldEdgeRouterEnrollmentToken, entity.EnrollmentToken)
|
||||
ctx.SetStringP(FieldEdgeRouterHostname, entity.Hostname)
|
||||
ctx.SetStringP(FieldEdgeRouterEnrollmentJwt, entity.EnrollmentJwt)
|
||||
ctx.SetTimeP(FieldEdgeRouterEnrollmentCreatedAt, entity.EnrollmentCreatedAt)
|
||||
ctx.SetTimeP(FieldEdgeRouterEnrollmentExpiresAt, entity.EnrollmentExpiresAt)
|
||||
ctx.SetMap(FieldEdgeRouterProtocols, toStringInterfaceMap(entity.EdgeRouterProtocols))
|
||||
ctx.SetStringList(FieldRoleAttributes, entity.RoleAttributes)
|
||||
ctx.SetLinkedIds(FieldEdgeRouterEnrollments, entity.Enrollments)
|
||||
|
||||
// index change won't fire if we don't have any roles on create, but we need to evaluate if we match any #all roles
|
||||
if ctx.IsCreate && len(entity.RoleAttributes) == 0 {
|
||||
@@ -137,6 +135,7 @@ type edgeRouterStoreImpl struct {
|
||||
|
||||
symbolEdgeRouterPolicies boltz.EntitySetSymbol
|
||||
symbolServiceEdgeRouterPolicies boltz.EntitySetSymbol
|
||||
symbolEnrollments boltz.EntitySetSymbol
|
||||
}
|
||||
|
||||
func (store *edgeRouterStoreImpl) NewStoreEntity() boltz.Entity {
|
||||
@@ -155,9 +154,7 @@ func (store *edgeRouterStoreImpl) initializeLocal() {
|
||||
|
||||
store.AddSymbol(FieldEdgeRouterFingerprint, ast.NodeTypeString)
|
||||
store.AddSymbol(FieldEdgeRouterIsVerified, ast.NodeTypeBool)
|
||||
store.AddSymbol(FieldEdgeRouterEnrollmentToken, ast.NodeTypeString)
|
||||
store.AddSymbol(FieldEdgeRouterEnrollmentCreatedAt, ast.NodeTypeString)
|
||||
store.AddSymbol(FieldEdgeRouterEnrollmentExpiresAt, ast.NodeTypeString)
|
||||
store.symbolEnrollments = store.AddFkSetSymbol(FieldEdgeRouterEnrollments, store.stores.enrollment)
|
||||
store.symbolEdgeRouterPolicies = store.AddFkSetSymbol(EntityTypeEdgeRouterPolicies, store.stores.edgeRouterPolicy)
|
||||
store.symbolServiceEdgeRouterPolicies = store.AddFkSetSymbol(EntityTypeServiceEdgeRouterPolicies, store.stores.serviceEdgeRouterPolicy)
|
||||
|
||||
@@ -181,6 +178,7 @@ func (store *edgeRouterStoreImpl) rolesChanged(tx *bbolt.Tx, rowId []byte, _ []b
|
||||
func (store *edgeRouterStoreImpl) initializeLinked() {
|
||||
store.AddLinkCollection(store.symbolEdgeRouterPolicies, store.stores.edgeRouterPolicy.symbolEdgeRouters)
|
||||
store.AddLinkCollection(store.symbolServiceEdgeRouterPolicies, store.stores.serviceEdgeRouterPolicy.symbolEdgeRouters)
|
||||
store.AddLinkCollection(store.symbolEnrollments, store.stores.enrollment.symbolEdgeRouter)
|
||||
}
|
||||
|
||||
func (store *edgeRouterStoreImpl) GetNameIndex() boltz.ReadIndex {
|
||||
@@ -213,6 +211,11 @@ func (store *edgeRouterStoreImpl) DeleteById(ctx boltz.MutateContext, id string)
|
||||
if err := store.deleteEntityReferences(ctx.Tx(), entity, store.stores.serviceEdgeRouterPolicy.symbolEdgeRouterRoles); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Remove outstanding enrollments
|
||||
if err := store.stores.enrollment.DeleteWhere(ctx, fmt.Sprintf(`edgeRouter="%s"`, entity.Id)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if store.stores.Router.IsEntityPresent(ctx.Tx(), id) {
|
||||
|
||||
@@ -27,6 +27,8 @@ const (
|
||||
FieldEnrollmentToken = "token"
|
||||
FieldEnrollmentMethod = "method"
|
||||
FieldEnrollIdentity = "identity"
|
||||
FieldEnrollEdgeRouter = "edgeRouter"
|
||||
FieldEnrollTransitRouter = "transitRouter"
|
||||
FieldEnrollmentExpiresAt = "expiresAt"
|
||||
FieldEnrollmentIssuedAt = "issuedAt"
|
||||
FieldEnrollmentCaId = "caId"
|
||||
@@ -41,22 +43,30 @@ const (
|
||||
|
||||
type Enrollment struct {
|
||||
boltz.BaseExtEntity
|
||||
Token string
|
||||
Method string
|
||||
IdentityId string
|
||||
ExpiresAt *time.Time
|
||||
IssuedAt *time.Time
|
||||
CaId *string
|
||||
Username *string
|
||||
Jwt string
|
||||
Token string
|
||||
Method string
|
||||
IdentityId *string
|
||||
TransitRouterId *string
|
||||
EdgeRouterId *string
|
||||
ExpiresAt *time.Time
|
||||
IssuedAt *time.Time
|
||||
CaId *string
|
||||
Username *string
|
||||
Jwt string
|
||||
}
|
||||
|
||||
var enrollmentFieldMappings = map[string]string{FieldEnrollIdentity: "identityId"}
|
||||
var enrollmentFieldMappings = map[string]string{
|
||||
FieldEnrollIdentity: "identityId",
|
||||
FieldEnrollEdgeRouter: "edgeRouterId",
|
||||
FieldEnrollTransitRouter: "transitRouterId",
|
||||
}
|
||||
|
||||
func (entity *Enrollment) LoadValues(_ boltz.CrudStore, bucket *boltz.TypedBucket) {
|
||||
entity.Token = bucket.GetStringWithDefault(FieldEnrollmentToken, "")
|
||||
entity.Method = bucket.GetStringWithDefault(FieldEnrollmentMethod, "")
|
||||
entity.IdentityId = bucket.GetStringOrError(FieldEnrollIdentity)
|
||||
entity.IdentityId = bucket.GetString(FieldEnrollIdentity)
|
||||
entity.EdgeRouterId = bucket.GetString(FieldEnrollEdgeRouter)
|
||||
entity.TransitRouterId = bucket.GetString(FieldEnrollTransitRouter)
|
||||
entity.ExpiresAt = bucket.GetTime(FieldEnrollmentExpiresAt)
|
||||
entity.IssuedAt = bucket.GetTime(FieldEnrollmentIssuedAt)
|
||||
entity.CaId = bucket.GetString(FieldEnrollmentCaId)
|
||||
@@ -70,7 +80,9 @@ func (entity *Enrollment) SetValues(ctx *boltz.PersistContext) {
|
||||
ctx.SetString(FieldEnrollmentToken, entity.Token)
|
||||
ctx.SetString(FieldEnrollmentMethod, entity.Method)
|
||||
ctx.SetTimeP(FieldEnrollmentExpiresAt, entity.ExpiresAt)
|
||||
ctx.SetString(FieldEnrollIdentity, entity.IdentityId)
|
||||
ctx.SetStringP(FieldEnrollIdentity, entity.IdentityId)
|
||||
ctx.SetStringP(FieldEnrollEdgeRouter, entity.EdgeRouterId)
|
||||
ctx.SetStringP(FieldEnrollTransitRouter, entity.TransitRouterId)
|
||||
ctx.SetStringP(FieldEnrollmentCaId, entity.CaId)
|
||||
ctx.SetStringP(FieldEnrollmentUsername, entity.Username)
|
||||
ctx.SetTimeP(FieldEnrollmentIssuedAt, entity.IssuedAt)
|
||||
@@ -99,8 +111,10 @@ func newEnrollmentStore(stores *stores) *enrollmentStoreImpl {
|
||||
|
||||
type enrollmentStoreImpl struct {
|
||||
*baseStore
|
||||
tokenIndex boltz.ReadIndex
|
||||
symbolIdentityId boltz.EntitySymbol
|
||||
tokenIndex boltz.ReadIndex
|
||||
symbolIdentity boltz.EntitySymbol
|
||||
symbolEdgeRouter boltz.EntitySymbol
|
||||
symbolTransitRouter boltz.EntitySymbol
|
||||
}
|
||||
|
||||
func (store *enrollmentStoreImpl) NewStoreEntity() boltz.Entity {
|
||||
@@ -109,14 +123,18 @@ func (store *enrollmentStoreImpl) NewStoreEntity() boltz.Entity {
|
||||
|
||||
func (store *enrollmentStoreImpl) initializeLocal() {
|
||||
store.AddExtEntitySymbols()
|
||||
|
||||
symbolToken := store.AddSymbol(FieldEnrollmentToken, ast.NodeTypeString)
|
||||
store.tokenIndex = store.AddUniqueIndex(symbolToken)
|
||||
|
||||
store.symbolIdentityId = store.AddFkSymbol(FieldEnrollIdentity, store.stores.identity)
|
||||
store.symbolIdentity = store.AddFkSymbol(FieldEnrollIdentity, store.stores.identity)
|
||||
store.symbolEdgeRouter = store.AddFkSymbol(FieldEnrollEdgeRouter, store.stores.edgeRouter)
|
||||
store.symbolTransitRouter = store.AddFkSymbol(FieldEnrollTransitRouter, store.stores.transitRouter)
|
||||
}
|
||||
|
||||
func (store *enrollmentStoreImpl) initializeLinked() {
|
||||
store.AddFkIndex(store.symbolIdentityId, store.stores.identity.symbolEnrollments)
|
||||
store.AddNullableFkIndex(store.symbolIdentity, store.stores.identity.symbolEnrollments)
|
||||
store.AddNullableFkIndex(store.symbolEdgeRouter, store.stores.edgeRouter.symbolEnrollments)
|
||||
store.AddNullableFkIndex(store.symbolTransitRouter, store.stores.transitRouter.symbolEnrollments)
|
||||
}
|
||||
|
||||
func (store *enrollmentStoreImpl) LoadOneById(tx *bbolt.Tx, id string) (*Enrollment, error) {
|
||||
|
||||
@@ -179,7 +179,7 @@ func (store *identityStoreImpl) rolesChanged(tx *bbolt.Tx, rowId []byte, _ []bol
|
||||
|
||||
func (store *identityStoreImpl) initializeLinked() {
|
||||
store.AddLinkCollection(store.symbolAuthenticators, store.stores.authenticator.symbolIdentityId)
|
||||
store.AddLinkCollection(store.symbolEnrollments, store.stores.enrollment.symbolIdentityId)
|
||||
store.AddLinkCollection(store.symbolEnrollments, store.stores.enrollment.symbolIdentity)
|
||||
store.AddLinkCollection(store.symbolEdgeRouterPolicies, store.stores.edgeRouterPolicy.symbolIdentities)
|
||||
store.AddLinkCollection(store.symbolServicePolicies, store.stores.servicePolicy.symbolIdentities)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright NetFoundry, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package persistence
|
||||
|
||||
import (
|
||||
|
||||
"github.com/netfoundry/ziti-foundation/storage/boltz"
|
||||
)
|
||||
|
||||
func (m *Migrations) createEnrollmentsForEdgeRouters(step *boltz.MigrationStep) {
|
||||
edgeRouterIds, _, err := m.stores.EdgeRouter.QueryIds(step.Ctx.Tx(), "true")
|
||||
step.SetError(err)
|
||||
|
||||
for _, edgeRouterId := range edgeRouterIds {
|
||||
edgeRouter, err := m.stores.EdgeRouter.LoadOneById(step.Ctx.Tx(), edgeRouterId)
|
||||
if step.SetError(err) {
|
||||
return
|
||||
}
|
||||
if edgeRouter.EnrollmentJwt == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
enrollment := &Enrollment{
|
||||
Token: *edgeRouter.EnrollmentToken,
|
||||
Method: MethodEnrollEdgeRouterOtt,
|
||||
EdgeRouterId: &edgeRouter.Id,
|
||||
ExpiresAt: edgeRouter.EnrollmentExpiresAt,
|
||||
IssuedAt: edgeRouter.EnrollmentCreatedAt,
|
||||
Jwt: *edgeRouter.EnrollmentJwt,
|
||||
}
|
||||
|
||||
step.SetError(m.stores.Enrollment.Create(step.Ctx, enrollment))
|
||||
|
||||
edgeRouter.EnrollmentJwt = nil
|
||||
edgeRouter.EnrollmentCreatedAt = nil
|
||||
edgeRouter.EnrollmentExpiresAt = nil
|
||||
edgeRouter.EnrollmentToken = nil
|
||||
|
||||
step.SetError(m.stores.EdgeRouter.Update(step.Ctx, edgeRouter, nil))
|
||||
}
|
||||
}
|
||||
@@ -63,9 +63,13 @@ func (m *Migrations) migrate(step *boltz.MigrationStep) int {
|
||||
return 4
|
||||
}
|
||||
|
||||
// current version
|
||||
if step.CurrentVersion == 4 {
|
||||
return 4
|
||||
m.createEnrollmentsForEdgeRouters(step)
|
||||
return 5
|
||||
}
|
||||
// current version
|
||||
if step.CurrentVersion == 5 {
|
||||
return 5
|
||||
}
|
||||
|
||||
step.SetError(errors.Errorf("Unsupported edge datastore version: %v", step.CurrentVersion))
|
||||
|
||||
@@ -149,7 +149,7 @@ func (m *Migrations) migrateEnrollmentsFromPG(step *boltz.MigrationStep) error {
|
||||
BaseExtEntity: *toBaseBoltEntity(&pgEnrollment.BaseDbEntity),
|
||||
Token: *pgEnrollment.Token,
|
||||
Method: *pgEnrollment.Method,
|
||||
IdentityId: *pgEnrollment.IdentityID,
|
||||
IdentityId: pgEnrollment.IdentityID,
|
||||
ExpiresAt: pgEnrollment.ExpiresAt,
|
||||
IssuedAt: pgEnrollment.CreatedAt,
|
||||
CaId: nil,
|
||||
|
||||
@@ -51,6 +51,7 @@ type Stores struct {
|
||||
Session SessionStore
|
||||
ServiceEdgeRouterPolicy ServiceEdgeRouterPolicyStore
|
||||
ServicePolicy ServicePolicyStore
|
||||
TransitRouter TransitRouterStore
|
||||
Enrollment EnrollmentStore
|
||||
Authenticator AuthenticatorStore
|
||||
|
||||
@@ -108,6 +109,7 @@ type stores struct {
|
||||
serviceEdgeRouterPolicy *serviceEdgeRouterPolicyStoreImpl
|
||||
servicePolicy *servicePolicyStoreImpl
|
||||
session *sessionStoreImpl
|
||||
transitRouter *transitRouterStoreImpl
|
||||
enrollment *enrollmentStoreImpl
|
||||
authenticator *authenticatorStoreImpl
|
||||
}
|
||||
@@ -134,6 +136,7 @@ func NewBoltStores(dbProvider DbProvider) (*Stores, error) {
|
||||
internalStores.edgeRouterPolicy = newEdgeRouterPolicyStore(internalStores)
|
||||
internalStores.edgeService = newEdgeServiceStore(internalStores)
|
||||
internalStores.eventLog = newEventLogStore(internalStores)
|
||||
internalStores.transitRouter = newTransitRouterStore(internalStores)
|
||||
internalStores.geoRegion = newGeoRegionStore(internalStores)
|
||||
internalStores.identity = newIdentityStore(internalStores)
|
||||
internalStores.identityType = newIdentityTypeStore(internalStores)
|
||||
@@ -159,6 +162,7 @@ func NewBoltStores(dbProvider DbProvider) (*Stores, error) {
|
||||
EdgeRouterPolicy: internalStores.edgeRouterPolicy,
|
||||
EdgeService: internalStores.edgeService,
|
||||
EventLog: internalStores.eventLog,
|
||||
TransitRouter: internalStores.transitRouter,
|
||||
GeoRegion: internalStores.geoRegion,
|
||||
Identity: internalStores.identity,
|
||||
IdentityType: internalStores.identityType,
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
Copyright NetFoundry, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package persistence
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"github.com/netfoundry/ziti-fabric/controller/db"
|
||||
"github.com/netfoundry/ziti-foundation/storage/boltz"
|
||||
"go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
const (
|
||||
FieldTransitRouterIsVerified = "isVerified"
|
||||
FieldTransitRouterEnrollments = "enrollments"
|
||||
|
||||
//old
|
||||
FieldTransitRouterEnrollmentToken = "enrollmentToken"
|
||||
FieldTransitRouterEnrollmentJwt = "enrollmentJwt"
|
||||
FieldTransitRouterEnrollmentCreatedAt = "enrollmentCreatedAt"
|
||||
FieldTransitRouterEnrollmentExpiresAt = "enrollmentExpiresAt"
|
||||
)
|
||||
|
||||
type TransitRouter struct {
|
||||
db.Router
|
||||
Name string
|
||||
IsVerified bool
|
||||
Enrollments []string
|
||||
IsBase bool
|
||||
}
|
||||
|
||||
func (entity *TransitRouter) GetId() string {
|
||||
return entity.Id
|
||||
}
|
||||
|
||||
func (entity *TransitRouter) SetId(id string) {
|
||||
entity.Id = id
|
||||
}
|
||||
|
||||
func newTransitRouter(name string, roleAttributes ...string) *TransitRouter {
|
||||
return &TransitRouter{
|
||||
Router: db.Router{
|
||||
BaseExtEntity: boltz.BaseExtEntity{Id: uuid.New().String()},
|
||||
},
|
||||
Name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (entity *TransitRouter) LoadValues(store boltz.CrudStore, bucket *boltz.TypedBucket) {
|
||||
_, err := store.GetParentStore().BaseLoadOneById(bucket.Tx(), entity.Id, &entity.Router)
|
||||
bucket.SetError(err)
|
||||
|
||||
if bucket.Bucket == nil {
|
||||
entity.IsVerified = true
|
||||
entity.IsBase = true
|
||||
return
|
||||
}
|
||||
entity.LoadBaseValues(bucket)
|
||||
entity.Name = bucket.GetStringOrError(FieldName)
|
||||
entity.IsVerified = bucket.GetBoolWithDefault(FieldTransitRouterIsVerified, false)
|
||||
entity.Enrollments = bucket.GetStringList(FieldTransitRouterEnrollments)
|
||||
}
|
||||
|
||||
func (entity *TransitRouter) SetValues(ctx *boltz.PersistContext) {
|
||||
entity.Router.SetValues(ctx.GetParentContext())
|
||||
entity.SetBaseValues(ctx)
|
||||
ctx.SetString(FieldName, entity.Name)
|
||||
}
|
||||
|
||||
func (entity *TransitRouter) GetEntityType() string {
|
||||
return EntityTypeTransitRouters
|
||||
}
|
||||
|
||||
func (entity *TransitRouter) GetName() string {
|
||||
return entity.Name
|
||||
}
|
||||
|
||||
type TransitRouterStore interface {
|
||||
NameIndexedStore
|
||||
LoadOneById(tx *bbolt.Tx, id string) (*TransitRouter, error)
|
||||
LoadOneByName(tx *bbolt.Tx, id string) (*TransitRouter, error)
|
||||
}
|
||||
|
||||
func newTransitRouterStore(stores *stores) *transitRouterStoreImpl {
|
||||
store := &transitRouterStoreImpl{
|
||||
baseStore: newExtendedBaseStore(stores, stores.Router, EntityTypeTransitRouters),
|
||||
}
|
||||
store.InitImpl(store)
|
||||
return store
|
||||
}
|
||||
|
||||
type transitRouterStoreImpl struct {
|
||||
*baseStore
|
||||
indexName boltz.ReadIndex
|
||||
symbolEnrollments boltz.EntitySetSymbol
|
||||
}
|
||||
|
||||
func (store *transitRouterStoreImpl) NewStoreEntity() boltz.Entity {
|
||||
return &TransitRouter{}
|
||||
}
|
||||
|
||||
func (store *transitRouterStoreImpl) initializeLocal() {
|
||||
store.AddExtEntitySymbols()
|
||||
store.GetParentStore().GrantSymbols(store)
|
||||
|
||||
store.indexName = store.addUniqueNameField()
|
||||
store.symbolEnrollments = store.AddFkSetSymbol(FieldTransitRouterEnrollments, store.stores.enrollment)
|
||||
}
|
||||
|
||||
func (store *transitRouterStoreImpl) initializeLinked() {
|
||||
store.AddLinkCollection(store.symbolEnrollments, store.stores.enrollment.symbolIdentity)
|
||||
}
|
||||
|
||||
func (store *transitRouterStoreImpl) CleanupExternal(ctx boltz.MutateContext, id string) error {
|
||||
entity, err := store.LoadOneById(ctx.Tx(), id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//no edge cleanup
|
||||
if entity.IsBase {
|
||||
return nil
|
||||
}
|
||||
|
||||
//edge cleanup
|
||||
if err = store.stores.enrollment.DeleteWhere(ctx, fmt.Sprintf(`transitRouter="%s"`, id)); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return store.BaseStore.CleanupExternal(ctx, id)
|
||||
}
|
||||
|
||||
func (store *transitRouterStoreImpl) GetNameIndex() boltz.ReadIndex {
|
||||
return store.indexName
|
||||
}
|
||||
|
||||
func (store *transitRouterStoreImpl) LoadOneById(tx *bbolt.Tx, id string) (*TransitRouter, error) {
|
||||
entity := &TransitRouter{}
|
||||
if err := store.baseLoadOneById(tx, id, entity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return entity, nil
|
||||
}
|
||||
|
||||
func (store *transitRouterStoreImpl) LoadOneByName(tx *bbolt.Tx, name string) (*TransitRouter, error) {
|
||||
id := store.indexName.Read(tx, []byte(name))
|
||||
if id != nil {
|
||||
return store.LoadOneById(tx, string(id))
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (store *transitRouterStoreImpl) LoadOneByQuery(tx *bbolt.Tx, query string) (*TransitRouter, error) {
|
||||
entity := &TransitRouter{}
|
||||
if found, err := store.BaseLoadOneByQuery(tx, query, entity); !found || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return entity, nil
|
||||
}
|
||||
|
||||
func (store *transitRouterStoreImpl) DeleteById(ctx boltz.MutateContext, id string) error {
|
||||
if entity, _ := store.LoadOneById(ctx.Tx(), id); entity != nil {
|
||||
// Remove outstanding enrollments
|
||||
if err := store.stores.enrollment.DeleteWhere(ctx, fmt.Sprintf(`transitRouter="%s"`, entity.Id)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return store.BaseStore.DeleteById(ctx, id)
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/netfoundry/ziti-edge/controller/apierror"
|
||||
"github.com/netfoundry/ziti-edge/controller/model"
|
||||
"net/http"
|
||||
)
|
||||
@@ -59,13 +58,13 @@ func (rc *RequestContext) GetIdFromRequest(idType IdType) (string, error) {
|
||||
return "", fmt.Errorf("id property '%s' not found in request", IdPropertyName)
|
||||
}
|
||||
|
||||
if idType == IdTypeUuid {
|
||||
_, err := uuid.Parse(id)
|
||||
|
||||
if err != nil {
|
||||
return "", apierror.NewInvalidUuid(id)
|
||||
}
|
||||
}
|
||||
//if idType == IdTypeUuid {
|
||||
// _, err := uuid.Parse(id)
|
||||
//
|
||||
// if err != nil {
|
||||
// return "", apierror.NewInvalidUuid(id)
|
||||
// }
|
||||
//}
|
||||
|
||||
return id, nil
|
||||
}
|
||||
|
||||
@@ -188,7 +188,8 @@ func (c *Controller) initializeAuthModules() {
|
||||
c.AppEnv.EnrollRegistry.Add(model.NewEnrollModuleCa(c.AppEnv))
|
||||
c.AppEnv.EnrollRegistry.Add(model.NewEnrollModuleOttCa(c.AppEnv))
|
||||
c.AppEnv.EnrollRegistry.Add(model.NewEnrollModuleOtt(c.AppEnv))
|
||||
c.AppEnv.EnrollRegistry.Add(model.NewEnrollModuleEr(c.AppEnv))
|
||||
c.AppEnv.EnrollRegistry.Add(model.NewEnrollModuleEdgeRouterOtt(c.AppEnv))
|
||||
c.AppEnv.EnrollRegistry.Add(model.NewEnrollModuleTransitRouterOtt(c.AppEnv))
|
||||
c.AppEnv.EnrollRegistry.Add(model.NewEnrollModuleUpdb(c.AppEnv))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func NewRestEnroller() Enroller {
|
||||
|
||||
func (re *RestEnroller) parseCfgMap(cfgmap map[interface{}]interface{}) (*gateway.Config, error) {
|
||||
config := gateway.NewConfig()
|
||||
if err := config.LoadConfigFromMap(cfgmap); err != nil {
|
||||
if err := config.LoadConfigFromMapForEnrollment(cfgmap); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,32 @@ func NewConfig() *Config {
|
||||
return &Config{}
|
||||
}
|
||||
|
||||
func (config *Config) LoadConfigFromMapForEnrollment(configMap map[interface{}]interface{}) error {
|
||||
//enrollment config loading is more lax on where the CSR section lives (i.e. under edge: or at the root level)
|
||||
|
||||
if val, ok := configMap["edge"]; ok && val != nil {
|
||||
var edgeConfigMap map[interface{}]interface{} = nil
|
||||
config.Enabled = true
|
||||
if edgeConfigMap, ok = val.(map[interface{}]interface{}); !ok {
|
||||
return fmt.Errorf("expected map as edge configuration")
|
||||
}
|
||||
|
||||
if err := config.loadCsr(edgeConfigMap, "edge"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if val, ok := configMap["csr"]; ok && val != nil {
|
||||
if err := config.loadCsr(configMap, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("expected enrollment CSR section")
|
||||
}
|
||||
|
||||
config.loadIdentity(configMap)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (config *Config) LoadConfigFromMap(configMap map[interface{}]interface{}) error {
|
||||
var err error
|
||||
config.Enabled = false
|
||||
@@ -72,7 +98,7 @@ func (config *Config) LoadConfigFromMap(configMap map[interface{}]interface{}) e
|
||||
return err
|
||||
}
|
||||
|
||||
if err = config.loadCsr(edgeConfigMap); err != nil {
|
||||
if err = config.loadCsr(edgeConfigMap, "edge"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -186,22 +212,26 @@ func (config *Config) loadListener(rootConfigMap map[interface{}]interface{}) er
|
||||
return nil
|
||||
}
|
||||
|
||||
func (config *Config) loadCsr(edgeConfigMap map[interface{}]interface{}) error {
|
||||
func (config *Config) loadCsr(configMap map[interface{}]interface{}, pathPrefix string) error {
|
||||
config.Csr = Csr{}
|
||||
|
||||
if value, found := edgeConfigMap["csr"]; found {
|
||||
if pathPrefix != "" {
|
||||
pathPrefix = pathPrefix + "."
|
||||
}
|
||||
|
||||
if value, found := configMap["csr"]; found {
|
||||
submap := value.(map[interface{}]interface{})
|
||||
|
||||
if submap == nil {
|
||||
return errors.New("required section [edge.csr] is not a map")
|
||||
return fmt.Errorf("required section [%scsr] is not a map", pathPrefix)
|
||||
}
|
||||
|
||||
if err := mapstructure.Decode(submap, &config.Csr); err != nil {
|
||||
return fmt.Errorf("failed to load [edge.csr]: %s", err)
|
||||
return fmt.Errorf("failed to load [%scsr]: %s", pathPrefix, err)
|
||||
}
|
||||
|
||||
} else {
|
||||
return errors.New("required section [edge.csr] not found")
|
||||
return fmt.Errorf("required section [%scsr] not found", pathPrefix)
|
||||
}
|
||||
|
||||
for _, uristr := range config.Csr.Sans.UriAddresses {
|
||||
|
||||
+206
-31
@@ -2488,6 +2488,133 @@ paths:
|
||||
'409':
|
||||
$ref: '#/responses/cannotDeleteReferencedResourceResponse'
|
||||
|
||||
###################################################################
|
||||
# Transit Routers
|
||||
##################################################################
|
||||
'/transit-routers':
|
||||
get:
|
||||
summary: List transit routers
|
||||
description: |
|
||||
Retrieves a list of transit router resources; supports filtering, sorting, and pagination. Requires admin access.
|
||||
security:
|
||||
- ztSession: []
|
||||
tags:
|
||||
- Transit Router
|
||||
operationId: listTransitRouters
|
||||
parameters:
|
||||
- $ref: '#/parameters/limit'
|
||||
- $ref: '#/parameters/offset'
|
||||
- $ref: '#/parameters/filter'
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/responses/listTransitRouters'
|
||||
'401':
|
||||
$ref: '#/responses/unauthorizedResponse'
|
||||
post:
|
||||
summary: Create a transit router resource
|
||||
description: Create a transit router resource. Requires admin access.
|
||||
security:
|
||||
- ztSession: []
|
||||
tags:
|
||||
- Transit Router
|
||||
operationId: createTransitRouter
|
||||
parameters:
|
||||
- name: Body
|
||||
in: body
|
||||
required: true
|
||||
description: A transit router to create
|
||||
schema:
|
||||
$ref: '#/definitions/transitRouterCreate'
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/responses/createResponse'
|
||||
'400':
|
||||
$ref: '#/responses/badRequestResponse'
|
||||
'401':
|
||||
$ref: '#/responses/unauthorizedResponse'
|
||||
'/transit-routers/{id}':
|
||||
parameters:
|
||||
- $ref: '#/parameters/id'
|
||||
get:
|
||||
summary: Retrieves a single transit router
|
||||
description: Retrieves a single transit router by id. Requires admin access.
|
||||
security:
|
||||
- ztSession: []
|
||||
tags:
|
||||
- Transit Router
|
||||
operationId: detailTransitRouter
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/responses/detailTransitRouter'
|
||||
'404':
|
||||
$ref: '#/responses/notFoundResponse'
|
||||
'401':
|
||||
$ref: '#/responses/unauthorizedResponse'
|
||||
put:
|
||||
summary: Update all fields on a transit router
|
||||
description: Update all fields on a transit router by id. Requires admin access.
|
||||
security:
|
||||
- ztSession: []
|
||||
tags:
|
||||
- Transit Router
|
||||
operationId: updateTransitRouter
|
||||
parameters:
|
||||
- name: Body
|
||||
in: body
|
||||
required: true
|
||||
description: A transit router update object
|
||||
schema:
|
||||
$ref: '#/definitions/transitRouterUpdate'
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/responses/updateResponse'
|
||||
'400':
|
||||
$ref: '#/responses/badRequestResponse'
|
||||
'404':
|
||||
$ref: '#/responses/notFoundResponse'
|
||||
'401':
|
||||
$ref: '#/responses/unauthorizedResponse'
|
||||
patch:
|
||||
summary: Update the supplied fields on a transit router
|
||||
description: Update the supplied fields on a transit router. Requires admin access.
|
||||
security:
|
||||
- ztSession: []
|
||||
tags:
|
||||
- Transit Router
|
||||
operationId: patchTransitRouter
|
||||
parameters:
|
||||
- name: Body
|
||||
in: body
|
||||
required: true
|
||||
description: A transit router patch object
|
||||
schema:
|
||||
$ref: '#/definitions/transitRouterPatch'
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/responses/patchResponse'
|
||||
'400':
|
||||
$ref: '#/responses/badRequestResponse'
|
||||
'404':
|
||||
$ref: '#/responses/notFoundResponse'
|
||||
'401':
|
||||
$ref: '#/responses/unauthorizedResponse'
|
||||
delete:
|
||||
summary: Delete a transit router
|
||||
description: Delete a transit router by id. Requires admin access.
|
||||
security:
|
||||
- ztSession: []
|
||||
tags:
|
||||
- Transit Router
|
||||
operationId: deleteTransitRouter
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/responses/deleteResponse'
|
||||
'400':
|
||||
$ref: '#/responses/badRequestResponse'
|
||||
'401':
|
||||
$ref: '#/responses/unauthorizedResponse'
|
||||
'409':
|
||||
$ref: '#/responses/cannotDeleteReferencedResourceResponse'
|
||||
#######################################################################################################################
|
||||
#
|
||||
# Parameters - Reusable parameters
|
||||
@@ -2962,6 +3089,17 @@ responses:
|
||||
description: Returns the document that represents the specification
|
||||
schema:
|
||||
$ref: '#/definitions/detailSpecBodyEnvelope'
|
||||
###################################################################
|
||||
# Transit Routers
|
||||
##################################################################
|
||||
listTransitRouters:
|
||||
description: A list of specifications
|
||||
schema:
|
||||
$ref: '#/definitions/listTransitRoutersEnvelope'
|
||||
detailTransitRouter:
|
||||
description: A single transit router
|
||||
schema:
|
||||
$ref: '#/definitions/detailTransitRouterEnvelope'
|
||||
#######################################################################################################################
|
||||
#
|
||||
# Definitions - In & Out Models Only
|
||||
@@ -3050,31 +3188,6 @@ definitions:
|
||||
$ref: '#/definitions/sdkInfo'
|
||||
configTypes:
|
||||
$ref: '#/definitions/configTypes'
|
||||
authenticateUPDB:
|
||||
type: object
|
||||
description: A username and password pair
|
||||
required: [username, password]
|
||||
properties:
|
||||
username:
|
||||
$ref: '#/definitions/username'
|
||||
password:
|
||||
$ref: '#/definitions/password'
|
||||
envInfo:
|
||||
$ref: '#/definitions/envInfo'
|
||||
sdkInfo:
|
||||
$ref: '#/definitions/sdkInfo'
|
||||
configTypes:
|
||||
$ref: '#/definitions/configTypes'
|
||||
authenticateCert:
|
||||
type: object
|
||||
description: A cert based authentication request. The certificate used by the client as its TLS client certificate will be interrogated for authentication
|
||||
properties:
|
||||
envInfo:
|
||||
$ref: '#/definitions/envInfo'
|
||||
sdkInfo:
|
||||
$ref: '#/definitions/sdkInfo'
|
||||
configTypes:
|
||||
$ref: '#/definitions/configTypes'
|
||||
###################################################################
|
||||
# Current Session
|
||||
##################################################################
|
||||
@@ -4694,17 +4807,17 @@ definitions:
|
||||
tags:
|
||||
$ref: '#/definitions/tags'
|
||||
serviceId:
|
||||
type: "string"
|
||||
type: string
|
||||
service:
|
||||
$ref: '#/definitions/entityRef'
|
||||
routerId:
|
||||
type: "string"
|
||||
type: string
|
||||
router:
|
||||
$ref: '#/definitions/entityRef'
|
||||
binding:
|
||||
type: "string"
|
||||
type: string
|
||||
address:
|
||||
type: "string"
|
||||
type: string
|
||||
terminatorCreate:
|
||||
type: object
|
||||
required:
|
||||
@@ -4798,7 +4911,69 @@ definitions:
|
||||
tags:
|
||||
$ref: '#/definitions/tags'
|
||||
name:
|
||||
type: "string"
|
||||
|
||||
type: string
|
||||
specBodyDetail:
|
||||
type: string
|
||||
###################################################################
|
||||
# Transit Routers
|
||||
##################################################################
|
||||
listTransitRoutersEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
meta:
|
||||
$ref: '#/definitions/meta'
|
||||
data:
|
||||
$ref: '#/definitions/transitRouterList'
|
||||
detailTransitRouterEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
meta:
|
||||
$ref: '#/definitions/meta'
|
||||
data:
|
||||
$ref: '#/definitions/transitRouterDetail'
|
||||
transitRouterList:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/transitRouterDetail'
|
||||
transitRouterDetail:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
createdAt:
|
||||
type: string
|
||||
format: date-time
|
||||
updatedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
_links:
|
||||
$ref: '#/definitions/links'
|
||||
tags:
|
||||
$ref: '#/definitions/tags'
|
||||
name:
|
||||
type: string
|
||||
fingerprint:
|
||||
type: string
|
||||
isVerified:
|
||||
type: boolean
|
||||
isOnline:
|
||||
type: boolean
|
||||
transitRouterCreate:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
transitRouterUpdate:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
transitRouterPatch:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
@@ -0,0 +1,62 @@
|
||||
v: 2
|
||||
|
||||
# (required) The certificates, ca chains, and private key used to represent this routers identity
|
||||
#
|
||||
# If the 'edge" section is enabled and enrollment is run, the files in this section will be written to with the results.
|
||||
# The "key" value can be provided through any of the support private key engines (file, etc.).
|
||||
#
|
||||
# If the 'key' value is a file and that file exists; it is expected to a pre-generated private key. It will be used for
|
||||
# the enrollment process and it will back the certificates generated during enrollment. If the file does not exist, it
|
||||
# will be generated.
|
||||
#
|
||||
# The 'cert', 'server_cert', and 'ca' files will be overwritten with the results of the enrollment process.
|
||||
#
|
||||
# When running the ziti-router the files/values in this section will be read and used. The 'cert' value will be used
|
||||
# as the client certificate to connect to the controller. The 'server_cert' is used for all servers/listeners. The
|
||||
# 'ca' value is used to populate an internally Trusted CA pool.
|
||||
identity:
|
||||
cert: testdata/transit-router/transit-router-client.cert.pem
|
||||
server_cert: testdata/transit-router/transit-router-server.cert.pem
|
||||
key: testdata/transit-router/transit-router.key.pem
|
||||
ca: testdata/transit-router/transit-router-ca-chain.cert.pem
|
||||
|
||||
#trace:
|
||||
# path: 001.trace
|
||||
|
||||
#profile:
|
||||
# memory:
|
||||
# path: 001.memprof
|
||||
# cpu:
|
||||
# path: 001.cpuprof
|
||||
|
||||
ctrl:
|
||||
endpoint: tls:127.0.0.1:6262
|
||||
|
||||
|
||||
csr:
|
||||
country: US
|
||||
province: NC
|
||||
locality: Charlotte
|
||||
organization: NetFoundry
|
||||
organizationalUnit: Ziti
|
||||
sans:
|
||||
dns:
|
||||
- "localhost"
|
||||
- "test-network"
|
||||
- "test-network.localhost"
|
||||
- "ziti-dev-ingress01"
|
||||
email:
|
||||
- "admin@example.com"
|
||||
ip:
|
||||
- "127.0.0.1"
|
||||
uri:
|
||||
- "ziti://ziti-dev-gateway01/made/up/example"
|
||||
|
||||
dialers:
|
||||
- binding: udp
|
||||
- binding: transport
|
||||
|
||||
listeners:
|
||||
- binding: transport
|
||||
address: tls:0.0.0.0:7099
|
||||
|
||||
+39
-27
@@ -239,9 +239,9 @@ func (request *authenticatedRequests) requireCreateIdentity(name string, isAdmin
|
||||
request.testContext.setJsonValue(entityData, enrollments, "enrollment")
|
||||
|
||||
entityJson := entityData.String()
|
||||
httpCode, body := request.createEntityOfType("identities", entityJson)
|
||||
request.testContext.req.Equal(http.StatusCreated, httpCode)
|
||||
id := request.testContext.getEntityId(body)
|
||||
resp := request.createEntityOfType("identities", entityJson)
|
||||
request.testContext.req.Equal(http.StatusCreated, resp.StatusCode())
|
||||
id := request.testContext.getEntityId(resp.Body())
|
||||
return id
|
||||
}
|
||||
|
||||
@@ -263,9 +263,9 @@ func (request *authenticatedRequests) requireCreateIdentityWithUpdbEnrollment(na
|
||||
request.testContext.setJsonValue(entityData, enrollments, "enrollment")
|
||||
|
||||
entityJson := entityData.String()
|
||||
httpCode, body := request.createEntityOfType("identities", entityJson)
|
||||
request.testContext.req.Equal(http.StatusCreated, httpCode)
|
||||
id := request.testContext.getEntityId(body)
|
||||
resp := request.createEntityOfType("identities", entityJson)
|
||||
request.testContext.req.Equal(http.StatusCreated, resp.StatusCode())
|
||||
id := request.testContext.getEntityId(resp.Body())
|
||||
request.testContext.completeUpdbEnrollment(id, password)
|
||||
return id, userAuth
|
||||
}
|
||||
@@ -283,9 +283,9 @@ func (request *authenticatedRequests) requireCreateIdentityOttEnrollment(name st
|
||||
request.testContext.setJsonValue(entityData, enrollments, "enrollment")
|
||||
|
||||
entityJson := entityData.String()
|
||||
httpCode, body := request.createEntityOfType("identities", entityJson)
|
||||
request.testContext.req.Equal(http.StatusCreated, httpCode)
|
||||
id := request.testContext.getEntityId(body)
|
||||
resp := request.createEntityOfType("identities", entityJson)
|
||||
request.testContext.req.Equal(http.StatusCreated, resp.StatusCode())
|
||||
id := request.testContext.getEntityId(resp.Body())
|
||||
return id, request.testContext.completeOttEnrollment(id)
|
||||
}
|
||||
|
||||
@@ -307,6 +307,12 @@ func (request *authenticatedRequests) requireNewEdgeRouter(roleAttributes ...str
|
||||
return edgeRouter
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) requireNewTransitRouter() *transitRouter {
|
||||
transitRouter := newTestTransitRouter()
|
||||
request.requireCreateEntity(transitRouter)
|
||||
return transitRouter
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) requireNewServicePolicy(policyType string, serviceRoles, identityRoles []string) *servicePolicy {
|
||||
policy := newServicePolicy(policyType, nil, serviceRoles, identityRoles)
|
||||
request.requireCreateEntity(policy)
|
||||
@@ -357,21 +363,21 @@ func (request *authenticatedRequests) requireNewIdentityWithOtt(isAdmin bool, ro
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) requireCreateEntity(entity entity) string {
|
||||
httpStatus, body := request.createEntity(entity)
|
||||
request.testContext.req.Equal(http.StatusCreated, httpStatus)
|
||||
id := request.testContext.getEntityId(body)
|
||||
resp := request.createEntity(entity)
|
||||
standardJsonResponseTests(resp, http.StatusCreated, request.testContext.testing)
|
||||
id := request.testContext.getEntityId(resp.Body())
|
||||
entity.setId(id)
|
||||
return id
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) requireDeleteEntity(entity entity) {
|
||||
httpStatus, _ := request.deleteEntityOfType(entity.getEntityType(), entity.getId())
|
||||
request.testContext.req.Equal(http.StatusOK, httpStatus)
|
||||
resp := request.deleteEntityOfType(entity.getEntityType(), entity.getId())
|
||||
standardJsonResponseTests(resp, http.StatusOK, request.testContext.testing)
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) requireUpdateEntity(entity entity) {
|
||||
httpStatus, _ := request.updateEntity(entity)
|
||||
request.testContext.req.Equal(http.StatusOK, httpStatus)
|
||||
resp := request.updateEntity(entity)
|
||||
standardJsonResponseTests(resp, http.StatusOK, request.testContext.testing)
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) requireList(url string) []string {
|
||||
@@ -409,14 +415,14 @@ func (request *authenticatedRequests) requireRemoveAssociation(url string, ids .
|
||||
request.testContext.req.Equal(http.StatusOK, httpStatus)
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) createEntityOfType(entityType string, body string) (int, []byte) {
|
||||
func (request *authenticatedRequests) createEntityOfType(entityType string, body string) *resty.Response {
|
||||
resp, err := request.newAuthenticatedRequest().
|
||||
SetBody(body).
|
||||
Post("/" + entityType)
|
||||
|
||||
request.testContext.req.NoError(err)
|
||||
request.testContext.logJson(resp.Body())
|
||||
return resp.StatusCode(), resp.Body()
|
||||
return resp
|
||||
}
|
||||
|
||||
type serviceConfig struct {
|
||||
@@ -490,24 +496,24 @@ func (request *authenticatedRequests) updateIdentityServiceConfigs(method string
|
||||
return resp.StatusCode(), resp.Body()
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) createEntity(entity entity) (int, []byte) {
|
||||
func (request *authenticatedRequests) createEntity(entity entity) *resty.Response {
|
||||
return request.createEntityOfType(entity.getEntityType(), entity.toJson(true, request.testContext))
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) deleteEntityOfType(entityType string, id string) (int, []byte) {
|
||||
func (request *authenticatedRequests) deleteEntityOfType(entityType string, id string) *resty.Response {
|
||||
resp, err := request.newAuthenticatedRequest().Delete("/" + entityType + "/" + id)
|
||||
|
||||
request.testContext.req.NoError(err)
|
||||
request.testContext.logJson(resp.Body())
|
||||
|
||||
return resp.StatusCode(), resp.Body()
|
||||
return resp
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) updateEntity(entity entity) (int, []byte) {
|
||||
func (request *authenticatedRequests) updateEntity(entity entity) *resty.Response {
|
||||
return request.updateEntityOfType(entity.getId(), entity.getEntityType(), entity.toJson(false, request.testContext), false)
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) updateEntityOfType(id string, entityType string, body string, patch bool) (int, []byte) {
|
||||
func (request *authenticatedRequests) updateEntityOfType(id string, entityType string, body string, patch bool) *resty.Response {
|
||||
if request.testContext.enabledJsonLogging {
|
||||
fmt.Printf("update body:\n%v\n", body)
|
||||
}
|
||||
@@ -528,7 +534,7 @@ func (request *authenticatedRequests) updateEntityOfType(id string, entityType s
|
||||
|
||||
request.testContext.req.NoError(err)
|
||||
request.testContext.logJson(resp.Body())
|
||||
return resp.StatusCode(), resp.Body()
|
||||
return resp
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) query(url string) (int, []byte) {
|
||||
@@ -660,11 +666,11 @@ func (request *authenticatedRequests) requireCreateNewConfigType() *configType {
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) requirePatchEntity(entity entity, fields ...string) {
|
||||
httpStatus, _ := request.patchEntity(entity, fields...)
|
||||
request.testContext.req.Equal(http.StatusOK, httpStatus)
|
||||
resp := request.patchEntity(entity, fields...)
|
||||
standardJsonResponseTests(resp, http.StatusOK, request.testContext.testing)
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) patchEntity(entity entity, fields ...string) (int, []byte) {
|
||||
func (request *authenticatedRequests) patchEntity(entity entity, fields ...string) *resty.Response {
|
||||
return request.updateEntityOfType(entity.getId(), entity.getEntityType(), entity.toJson(false, request.testContext, fields...), true)
|
||||
}
|
||||
|
||||
@@ -674,6 +680,12 @@ func (request *authenticatedRequests) getEdgeRouterJwt(edgeRouterId string) stri
|
||||
return data.Data().(string)
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) getTransitRouterJwt(transitRouterId string) string {
|
||||
jsonBody := request.requireQuery("transit-routers/" + transitRouterId)
|
||||
data := request.testContext.requirePath(jsonBody, "data", "enrollmentJwt")
|
||||
return data.Data().(string)
|
||||
}
|
||||
|
||||
func (request *authenticatedRequests) getIdentityJwt(identityId string) string {
|
||||
request.testContext.enabledJsonLogging = true
|
||||
jsonBody := request.requireQuery("identities/" + identityId)
|
||||
|
||||
+10
-10
@@ -42,30 +42,30 @@ func Test_Configs(t *testing.T) {
|
||||
configType := ctx.AdminSession.requireCreateNewConfigType()
|
||||
config := ctx.newConfig(configType.id, map[string]interface{}{"port": 22})
|
||||
config.name = ""
|
||||
httpCode, body := ctx.AdminSession.createEntity(config)
|
||||
ctx.requireFieldError(httpCode, body, apierror.CouldNotValidateCode, "name")
|
||||
resp := ctx.AdminSession.createEntity(config)
|
||||
ctx.requireFieldError(resp.StatusCode(), resp.Body(), apierror.CouldNotValidateCode, "name")
|
||||
})
|
||||
|
||||
t.Run("create without data should fail", func(t *testing.T) {
|
||||
ctx.testContextChanged(t)
|
||||
configType := ctx.AdminSession.requireCreateNewConfigType()
|
||||
config := ctx.newConfig(configType.id, nil)
|
||||
httpCode, body := ctx.AdminSession.createEntity(config)
|
||||
ctx.requireFieldError(httpCode, body, apierror.CouldNotValidateCode, "data")
|
||||
resp := ctx.AdminSession.createEntity(config)
|
||||
ctx.requireFieldError(resp.StatusCode(), resp.Body(), apierror.CouldNotValidateCode, "data")
|
||||
})
|
||||
|
||||
t.Run("create without type should fail", func(t *testing.T) {
|
||||
ctx.testContextChanged(t)
|
||||
config := ctx.newConfig("", map[string]interface{}{"port": 22})
|
||||
httpCode, body := ctx.AdminSession.createEntity(config)
|
||||
ctx.requireFieldError(httpCode, body, apierror.CouldNotValidateCode, "type")
|
||||
resp := ctx.AdminSession.createEntity(config)
|
||||
ctx.requireFieldError(resp.StatusCode(), resp.Body(), apierror.CouldNotValidateCode, "type")
|
||||
})
|
||||
|
||||
t.Run("create with invalid config type should fail", func(t *testing.T) {
|
||||
ctx.testContextChanged(t)
|
||||
config := ctx.newConfig(uuid.New().String(), map[string]interface{}{"port": 22})
|
||||
httpCode, body := ctx.AdminSession.createEntity(config)
|
||||
ctx.requireFieldError(httpCode, body, apierror.InvalidFieldCode, "type")
|
||||
resp := ctx.AdminSession.createEntity(config)
|
||||
ctx.requireFieldError(resp.StatusCode(), resp.Body(), apierror.InvalidFieldCode, "type")
|
||||
})
|
||||
|
||||
t.Run("create should pass", func(t *testing.T) {
|
||||
@@ -248,8 +248,8 @@ func Test_Configs(t *testing.T) {
|
||||
configType.id = ctx.AdminSession.requireCreateEntity(configType)
|
||||
|
||||
config := ctx.newConfig(configType.id, map[string]interface{}{"port": 22})
|
||||
httpCode, body := ctx.AdminSession.createEntity(config)
|
||||
ctx.requireFieldError(httpCode, body, apierror.CouldNotValidateCode, "(root)")
|
||||
resp := ctx.AdminSession.createEntity(config)
|
||||
ctx.requireFieldError(resp.StatusCode(), resp.Body(), apierror.CouldNotValidateCode, "(root)")
|
||||
|
||||
now := time.Now()
|
||||
config = ctx.newConfig(configType.id, map[string]interface{}{
|
||||
|
||||
@@ -41,8 +41,8 @@ func Test_ConfigTypes(t *testing.T) {
|
||||
ctx.testContextChanged(t)
|
||||
configType := ctx.newConfigType()
|
||||
configType.name = ""
|
||||
httpCode, body := ctx.AdminSession.createEntity(configType)
|
||||
ctx.requireFieldError(httpCode, body, apierror.CouldNotValidateCode, "name")
|
||||
resp := ctx.AdminSession.createEntity(configType)
|
||||
ctx.requireFieldError(resp.StatusCode(), resp.Body(), apierror.CouldNotValidateCode, "name")
|
||||
})
|
||||
|
||||
t.Run("create config type without schema should pass", func(t *testing.T) {
|
||||
@@ -74,8 +74,8 @@ func Test_ConfigTypes(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
httpCode, body := ctx.AdminSession.createEntity(configType)
|
||||
ctx.requireFieldError(httpCode, body, apierror.InvalidFieldCode, "schema")
|
||||
resp := ctx.AdminSession.createEntity(configType)
|
||||
ctx.requireFieldError(resp.StatusCode(), resp.Body(), apierror.InvalidFieldCode, "schema")
|
||||
})
|
||||
|
||||
t.Run("create config type with schema should pass", func(t *testing.T) {
|
||||
|
||||
+34
-5
@@ -60,8 +60,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
ControllerConfFile = "ats-ctrl.yml"
|
||||
EdgeRouterConfFile = "ats-edge.router.yml"
|
||||
ControllerConfFile = "ats-ctrl.yml"
|
||||
EdgeRouterConfFile = "ats-edge.router.yml"
|
||||
TransitRouterConfFile = "ats-transit.router.yml"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -84,8 +85,10 @@ type TestContext struct {
|
||||
client *resty.Client
|
||||
enabledJsonLogging bool
|
||||
|
||||
edgeRouterEntity *edgeRouter
|
||||
router *router.Router
|
||||
edgeRouterEntity *edgeRouter
|
||||
transitRouterEntity *transitRouter
|
||||
router *router.Router
|
||||
testing *testing.T
|
||||
}
|
||||
|
||||
var defaultTestContext = &TestContext{
|
||||
@@ -96,7 +99,7 @@ var defaultTestContext = &TestContext{
|
||||
}
|
||||
|
||||
func NewTestContext(t *testing.T) *TestContext {
|
||||
return &TestContext{
|
||||
ret := &TestContext{
|
||||
ApiHost: "127.0.0.1:1281",
|
||||
AdminAuthenticator: &updbAuthenticator{
|
||||
Username: uuid.New().String(),
|
||||
@@ -104,6 +107,9 @@ func NewTestContext(t *testing.T) *TestContext {
|
||||
},
|
||||
req: require.New(t),
|
||||
}
|
||||
ret.testContextChanged(t)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func GetTestContext() *TestContext {
|
||||
@@ -111,6 +117,7 @@ func GetTestContext() *TestContext {
|
||||
}
|
||||
|
||||
func (ctx *TestContext) testContextChanged(t *testing.T) {
|
||||
ctx.testing = t
|
||||
ctx.req = require.New(t)
|
||||
}
|
||||
|
||||
@@ -238,6 +245,28 @@ func (ctx *TestContext) createAndEnrollEdgeRouter(roleAttributes ...string) *edg
|
||||
return ctx.edgeRouterEntity
|
||||
}
|
||||
|
||||
func (ctx *TestContext) createAndEnrollTransitRouter() *transitRouter {
|
||||
// If a tx router has already been created, delete it and create a new one
|
||||
if ctx.transitRouterEntity != nil {
|
||||
ctx.AdminSession.requireDeleteEntity(ctx.transitRouterEntity)
|
||||
ctx.transitRouterEntity = nil
|
||||
}
|
||||
|
||||
_ = os.MkdirAll("testdata/transit-router", os.FileMode(0755))
|
||||
|
||||
ctx.transitRouterEntity = ctx.AdminSession.requireNewTransitRouter()
|
||||
jwt := ctx.AdminSession.getTransitRouterJwt(ctx.transitRouterEntity.id)
|
||||
|
||||
cfgmap, err := router.LoadConfigMap(TransitRouterConfFile)
|
||||
ctx.req.NoError(err)
|
||||
|
||||
enroller := enroll.NewRestEnroller()
|
||||
ctx.req.NoError(enroller.LoadConfig(cfgmap))
|
||||
ctx.req.NoError(enroller.Enroll([]byte(jwt), true, ""))
|
||||
|
||||
return ctx.transitRouterEntity
|
||||
}
|
||||
|
||||
func (ctx *TestContext) createEnrollAndStartEdgeRouter(roleAttributes ...string) {
|
||||
ctx.createAndEnrollEdgeRouter(roleAttributes...)
|
||||
|
||||
|
||||
@@ -90,4 +90,12 @@ func Test_EdgeRouter(t *testing.T) {
|
||||
ctx.req.True(stringz.ContainsAll(list, role1, role2, role3, role4))
|
||||
ctx.req.False(stringz.Contains(list, role5))
|
||||
})
|
||||
|
||||
t.Run("newly created edge routers that is deleted", func(t *testing.T) {
|
||||
ctx.testContextChanged(t)
|
||||
|
||||
edgeRouter := ctx.AdminSession.requireNewEdgeRouter()
|
||||
|
||||
ctx.AdminSession.requireDeleteEntity(edgeRouter)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -570,6 +570,45 @@ func (entity *configValidatingService) validate(ctx *TestContext, c *gabs.Contai
|
||||
}
|
||||
}
|
||||
|
||||
func newTestTransitRouter() *transitRouter {
|
||||
return &transitRouter{
|
||||
name: uuid.New().String(),
|
||||
}
|
||||
}
|
||||
|
||||
type transitRouter struct {
|
||||
id string
|
||||
name string
|
||||
tags map[string]interface{}
|
||||
}
|
||||
|
||||
func (entity *transitRouter) getId() string {
|
||||
return entity.id
|
||||
}
|
||||
|
||||
func (entity *transitRouter) setId(id string) {
|
||||
entity.id = id
|
||||
}
|
||||
|
||||
func (entity *transitRouter) getEntityType() string {
|
||||
return "transit-routers"
|
||||
}
|
||||
|
||||
func (entity *transitRouter) toJson(_ bool, ctx *TestContext, _ ...string) string {
|
||||
entityData := gabs.New()
|
||||
ctx.setJsonValue(entityData, entity.name, "name")
|
||||
ctx.setJsonValue(entityData, entity.tags, "tags")
|
||||
|
||||
return entityData.String()
|
||||
}
|
||||
|
||||
func (entity *transitRouter) validate(ctx *TestContext, c *gabs.Container) {
|
||||
if entity.tags == nil {
|
||||
entity.tags = map[string]interface{}{}
|
||||
}
|
||||
ctx.pathEquals(c, entity.name, path("name"))
|
||||
ctx.pathEquals(c, entity.tags, path("tags"))
|
||||
}
|
||||
type ca struct {
|
||||
id string
|
||||
name string `json:"name"`
|
||||
|
||||
@@ -44,8 +44,8 @@ func Test_Services(t *testing.T) {
|
||||
ctx.testContextChanged(t)
|
||||
service := ctx.newService(nil, nil)
|
||||
service.name = ""
|
||||
httpCode, body := ctx.AdminSession.createEntity(service)
|
||||
ctx.requireFieldError(httpCode, body, apierror.CouldNotValidateCode, "name")
|
||||
resp := ctx.AdminSession.createEntity(service)
|
||||
ctx.requireFieldError(resp.StatusCode(), resp.Body(), apierror.CouldNotValidateCode, "name")
|
||||
})
|
||||
|
||||
t.Run("create should pass", func(t *testing.T) {
|
||||
@@ -353,8 +353,8 @@ func Test_ServiceListWithConfigDuplicate(t *testing.T) {
|
||||
})
|
||||
|
||||
service := ctx.newService(nil, s(config1.id, config2.id))
|
||||
httpCode, body := ctx.AdminSession.createEntity(service)
|
||||
ctx.requireFieldError(httpCode, body, apierror.InvalidFieldCode, "configs")
|
||||
resp := ctx.AdminSession.createEntity(service)
|
||||
ctx.requireFieldError(resp.StatusCode(), resp.Body(), apierror.InvalidFieldCode, "configs")
|
||||
}
|
||||
|
||||
func Test_ServiceRoleAttributes(t *testing.T) {
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
ctrl.db*
|
||||
edge-router/
|
||||
transit-router/
|
||||
@@ -0,0 +1,47 @@
|
||||
// +build apitests
|
||||
|
||||
/*
|
||||
Copyright NetFoundry, Inc.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package tests
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_TransitRouters(t *testing.T) {
|
||||
ctx := NewTestContext(t)
|
||||
defer ctx.teardown()
|
||||
ctx.startServer()
|
||||
ctx.requireAdminLogin()
|
||||
|
||||
t.Run("transit routers can be created and enrolled", func(t *testing.T) {
|
||||
ctx.testContextChanged(t)
|
||||
ctx.createAndEnrollTransitRouter()
|
||||
})
|
||||
|
||||
t.Run("create transit router, then delete", func(t *testing.T) {
|
||||
ctx.testContextChanged(t)
|
||||
router := ctx.AdminSession.requireNewTransitRouter()
|
||||
ctx.AdminSession.requireDeleteEntity(router)
|
||||
})
|
||||
|
||||
t.Run("create & enroll transit router, then delete", func(t *testing.T) {
|
||||
ctx.testContextChanged(t)
|
||||
router := ctx.createAndEnrollTransitRouter()
|
||||
ctx.AdminSession.requireDeleteEntity(router)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user