diff --git a/federation/rest.yaml b/federation/rest.yaml index 255b7dc6a..cc5f177a3 100644 --- a/federation/rest.yaml +++ b/federation/rest.yaml @@ -129,7 +129,7 @@ endpoints: parameters: path: [ { name: nodeID, type: uint64, required: true, title: NodeID } ] post: - - name: tokenA + - name: authToken type: string required: true title: Node A token diff --git a/federation/rest/node.go b/federation/rest/node.go index 1680e997d..e95e25ae0 100644 --- a/federation/rest/node.go +++ b/federation/rest/node.go @@ -2,6 +2,7 @@ package rest import ( "context" + "github.com/cortezaproject/corteza-server/federation/rest/request" "github.com/cortezaproject/corteza-server/federation/service" "github.com/cortezaproject/corteza-server/federation/types" @@ -103,7 +104,7 @@ func (ctrl Node) HandshakeConfirm(ctx context.Context, r *request.NodeHandshakeC } func (ctrl Node) HandshakeComplete(ctx context.Context, r *request.NodeHandshakeComplete) (interface{}, error) { - return api.OK(), ctrl.svcNode.HandshakeComplete(ctx, r.NodeID, r.TokenA) + return api.OK(), ctrl.svcNode.HandshakeComplete(ctx, r.NodeID, r.AuthToken) } func (ctrl Node) makePayload(ctx context.Context, m *types.Node, err error) (*nodePayload, error) { diff --git a/federation/rest/request/node.go b/federation/rest/request/node.go index d2504c0a3..12d9d872f 100644 --- a/federation/rest/request/node.go +++ b/federation/rest/request/node.go @@ -123,10 +123,10 @@ type ( // NodeID NodeID uint64 `json:",string"` - // TokenA POST parameter + // AuthToken POST parameter // // Node A token - TokenA string + AuthToken string } ) @@ -618,8 +618,8 @@ func NewNodeHandshakeComplete() *NodeHandshakeComplete { // Auditable returns all auditable/loggable parameters func (r NodeHandshakeComplete) Auditable() map[string]interface{} { return map[string]interface{}{ - "nodeID": r.NodeID, - "tokenA": r.TokenA, + "nodeID": r.NodeID, + "authToken": r.AuthToken, } } @@ -629,8 +629,8 @@ func (r NodeHandshakeComplete) GetNodeID() uint64 { } // Auditable returns all auditable/loggable parameters -func (r NodeHandshakeComplete) GetTokenA() string { - return r.TokenA +func (r NodeHandshakeComplete) GetAuthToken() string { + return r.AuthToken } // Fill processes request and fills internal variables @@ -653,8 +653,8 @@ func (r *NodeHandshakeComplete) Fill(req *http.Request) (err error) { // POST params - if val, ok := req.Form["tokenA"]; ok && len(val) > 0 { - r.TokenA, err = val[0], nil + if val, ok := req.Form["authToken"]; ok && len(val) > 0 { + r.AuthToken, err = val[0], nil if err != nil { return err } diff --git a/federation/service/node.go b/federation/service/node.go index d173599a3..ee5c0b772 100644 --- a/federation/service/node.go +++ b/federation/service/node.go @@ -53,13 +53,8 @@ func Node(s store.Storer, u service.UserService, al actionlog.Recorder, th auth. sysUser: u, actionlog: al, tokenEncoder: th, - - // name of this node - // @todo read this from settings - name: "Server A", - - // @todo read this from settings - host: options.Host, + name: options.Label, + host: options.Host, // @todo use HTTP_API_BASE_URL (HTTPServerOpt.ApiBaseUrl) to prefix URI path baseURL: "/federation", @@ -267,7 +262,7 @@ func (svc node) Pair(ctx context.Context, nodeID uint64) error { func (svc node) HandshakeInit(ctx context.Context, nodeID uint64, pairToken string, sharedNodeID uint64, authToken string) error { _, err := svc.updater( ctx, - nodeID, + sharedNodeID, NodeActionHandshakeInit, func(ctx context.Context, n *types.Node) error { // @todo need to check node status before we can proceed with initialization @@ -320,15 +315,25 @@ func (svc node) HandshakeConfirm(ctx context.Context, nodeID uint64) error { } // HandshakeComplete is used by server B to handle handshake confirmation -func (svc node) HandshakeComplete(ctx context.Context, nodeID uint64, token string) error { - _, err := svc.updater(ctx, nodeID, NodeActionHandshakeComplete, func(ctx context.Context, n *types.Node) error { - n.Status = types.NodeStatusPaired +func (svc node) HandshakeComplete(ctx context.Context, sharedNodeID uint64, token string) error { + var ( + n *types.Node + err error + ) + if n, err = store.LookupFederationNodeBySharedNodeID(ctx, svc.store, sharedNodeID); err != nil { + return err + } + + _, err = svc.updater(ctx, n.ID, NodeActionHandshakeComplete, func(ctx context.Context, n *types.Node) error { + n.AuthToken = token + n.Status = types.NodeStatusPaired n.UpdatedBy = auth.GetIdentityFromContext(ctx).Identity() n.UpdatedAt = now() return nil }, nil) + return err } @@ -437,7 +442,7 @@ func (node) decodePairingURI(uri string) (*types.Node, error) { } n.Name = parsedURI.Query().Get("name") - n.BaseURL = fmt.Sprintf("https://%s/%s", parsedURI.Host, strings.Trim(parsedURI.Path, "/")) + n.BaseURL = fmt.Sprintf("%s://%s/%s", parsedURI.Scheme, parsedURI.Host, strings.Trim(parsedURI.Path, "/")) return nil }() } diff --git a/federation/service/node_handshaker.go b/federation/service/node_handshaker.go index b9d02443c..9cc3883c5 100644 --- a/federation/service/node_handshaker.go +++ b/federation/service/node_handshaker.go @@ -5,9 +5,10 @@ import ( "context" "encoding/json" "fmt" - "github.com/cortezaproject/corteza-server/federation/types" "net/http" "strconv" + + "github.com/cortezaproject/corteza-server/federation/types" ) type ( @@ -40,7 +41,7 @@ func (h httpNodeHandshake) Init(ctx context.Context, n *types.Node, authToken st // Share auth token for the federation service user for this node "authToken": authToken, - "sharedNodeID": strconv.FormatUint(n.ID, 10), + "sharedNodeID": strconv.FormatUint(n.SharedNodeID, 10), } ) @@ -60,6 +61,9 @@ func (h httpNodeHandshake) Complete(ctx context.Context, n *types.Node, authToke } ) + // use n.AuthToken in context + ctx = context.WithValue(ctx, "authToken", n.AuthToken) + return h.send(ctx, endpoint, payload) } @@ -74,6 +78,12 @@ func (h httpNodeHandshake) send(ctx context.Context, endpoint string, payload ma return err } + req.Header.Set("Content-Type", "application/json") + + if authToken := ctx.Value("authToken"); authToken != nil { + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", authToken)) + } + rsp, err := h.httpClient.Do(req.WithContext(ctx)) if err != nil { return err diff --git a/pkg/options/federation.go b/pkg/options/federation.go index fbb04d4f2..5bf77fee2 100644 --- a/pkg/options/federation.go +++ b/pkg/options/federation.go @@ -3,6 +3,7 @@ package options type ( FederationOpt struct { Enabled bool `env:"FEDERATION_ENABLED"` + Label string `env:"FEDERATION_LABEL"` Host string `env:"FEDERATION_HOST"` } ) @@ -11,6 +12,7 @@ func Federation() (o *FederationOpt) { o = &FederationOpt{ Enabled: false, + Label: `Example host`, Host: `example.tld`, } diff --git a/tests/federation/main_test.go b/tests/federation/main_test.go index b24d4d39a..d83c8b5ef 100644 --- a/tests/federation/main_test.go +++ b/tests/federation/main_test.go @@ -3,10 +3,13 @@ package federation import ( "context" "errors" + "os" + "testing" + "github.com/cortezaproject/corteza-server/app" "github.com/cortezaproject/corteza-server/federation/rest" "github.com/cortezaproject/corteza-server/federation/service" - "github.com/cortezaproject/corteza-server/pkg/api" + "github.com/cortezaproject/corteza-server/pkg/api/server" "github.com/cortezaproject/corteza-server/pkg/auth" "github.com/cortezaproject/corteza-server/pkg/cli" "github.com/cortezaproject/corteza-server/pkg/eventbus" @@ -20,8 +23,6 @@ import ( "github.com/steinfletcher/apitest" "github.com/stretchr/testify/require" "go.uber.org/zap" - "os" - "testing" ) type ( @@ -60,7 +61,7 @@ func InitTestApp() { if r == nil { r = chi.NewRouter() - r.Use(api.BaseMiddleware(logger.Default())...) + r.Use(server.BaseMiddleware(false, logger.Default())...) helpers.BindAuthMiddleware(r) rest.MountRoutes(r) }