3
0

Fixed node pairing

This commit is contained in:
Peter Grlica
2020-11-16 16:54:16 +01:00
parent 85e615213d
commit 5890cd444a
7 changed files with 47 additions and 28 deletions

View File

@@ -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

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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
}()
}

View File

@@ -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

View File

@@ -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`,
}

View File

@@ -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)
}