Skip to content

Commit

Permalink
Merge pull request #40 from nodeset-org/daemon-auth
Browse files Browse the repository at this point in the history
Added JWT authentication to the API
  • Loading branch information
jclapis authored Oct 2, 2024
2 parents aef4db5 + c4cb951 commit 3101b38
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 15 deletions.
5 changes: 3 additions & 2 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/http/httptrace"
"net/url"

"github.com/nodeset-org/hyperdrive-daemon/shared/auth"
"github.com/rocket-pool/node-manager-core/api/client"
)

Expand All @@ -19,8 +20,8 @@ type ApiClient struct {
}

// Creates a new API client instance
func NewApiClient(apiUrl *url.URL, logger *slog.Logger, tracer *httptrace.ClientTrace) *ApiClient {
context := client.NewNetworkRequesterContext(apiUrl, logger, tracer)
func NewApiClient(apiUrl *url.URL, logger *slog.Logger, tracer *httptrace.ClientTrace, authMgr *auth.AuthorizationManager) *ApiClient {
context := client.NewNetworkRequesterContext(apiUrl, logger, tracer, authMgr.AddAuthHeader)

client := &ApiClient{
context: context,
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ require (
github.com/goccy/go-json v0.10.3
github.com/google/uuid v1.6.0
github.com/gorilla/mux v1.8.1
github.com/nodeset-org/hyperdrive-daemon v1.1.0-b1.0.20241001192501-b11ba9e5209f
github.com/nodeset-org/hyperdrive-daemon v1.1.0-b1.0.20241002180757-b219ff53a2a0
github.com/nodeset-org/nodeset-client-go v1.0.1-0.20240927160821-e348e05e2363
github.com/nodeset-org/osha v0.3.1-0.20240927160812-d66358d4e091
github.com/rocket-pool/batch-query v1.0.0
github.com/rocket-pool/node-manager-core v0.5.2-0.20241001041416-40f4fb819f98
github.com/rocket-pool/node-manager-core v0.5.2-0.20241002072934-89c9cc081cf6
github.com/stretchr/testify v1.9.0
github.com/urfave/cli/v2 v2.27.2
github.com/wealdtech/go-eth2-types/v2 v2.8.2
Expand Down Expand Up @@ -71,6 +71,7 @@ require (
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-viper/mapstructure/v2 v2.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/go-cmp v0.6.0 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,8 @@ github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOEL
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nodeset-org/hyperdrive-daemon v1.1.0-b1.0.20241001192501-b11ba9e5209f h1:iAxCtnQkT8UGunXIyGNdhsVcqwQve0SefNMdoja3kCc=
github.com/nodeset-org/hyperdrive-daemon v1.1.0-b1.0.20241001192501-b11ba9e5209f/go.mod h1:KCZ/EptpaWrk/O2jYAUH2hDYt6Mrcjf68fVOeT8fuew=
github.com/nodeset-org/hyperdrive-daemon v1.1.0-b1.0.20241002180757-b219ff53a2a0 h1:BpCDh8auXyG3Qc4e/0jNKjzA8r2iqgDL5W0qfy05CDE=
github.com/nodeset-org/hyperdrive-daemon v1.1.0-b1.0.20241002180757-b219ff53a2a0/go.mod h1:VXYiN0ZrXbeNALJLa0sin4AzlSrFuGH8gW1YSywoVoI=
github.com/nodeset-org/nodeset-client-go v1.0.1-0.20240927160821-e348e05e2363 h1:iivCknAFZlpxPwbIDjPc9E2bnj55c2STrXT9MvuMzQM=
github.com/nodeset-org/nodeset-client-go v1.0.1-0.20240927160821-e348e05e2363/go.mod h1:slpwejkJ/vYU9SKA3SYw4hIPJLzDUeQxcx+Cm04kkIA=
github.com/nodeset-org/osha v0.3.1-0.20240927160812-d66358d4e091 h1:oAs4/Yx4jnsNdWh3vTKum1sXC8VCvsY1H2VFSRRkgjc=
Expand Down Expand Up @@ -443,8 +443,8 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rocket-pool/batch-query v1.0.0 h1:5HejmT1n1fIdLIqUhTNwbkG2PGOPl3IVjCpFQcQZ4I4=
github.com/rocket-pool/batch-query v1.0.0/go.mod h1:d1CmxShzk0fioJ4yX0eFGhz2an1odnW/LZ2cp3eDGIQ=
github.com/rocket-pool/node-manager-core v0.5.2-0.20241001041416-40f4fb819f98 h1:/vmzEAVs15gRK7q8lUYi1+MJd0XhxJwPe3zMdRB+3c8=
github.com/rocket-pool/node-manager-core v0.5.2-0.20241001041416-40f4fb819f98/go.mod h1:/H1wq3skacZi4zjgnKTtnm0wBLJH7H5r0CvLtWFs19Y=
github.com/rocket-pool/node-manager-core v0.5.2-0.20241002072934-89c9cc081cf6 h1:rn0t1IoOEy7ecETHRIGBQd40GDuqT4lK8MeWsfoGKPU=
github.com/rocket-pool/node-manager-core v0.5.2-0.20241002072934-89c9cc081cf6/go.mod h1:/H1wq3skacZi4zjgnKTtnm0wBLJH7H5r0CvLtWFs19Y=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
Expand Down
16 changes: 13 additions & 3 deletions server/server-manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package server

import (
"fmt"
"net/http"
"sync"

"github.com/nodeset-org/hyperdrive-daemon/shared/auth"
swcommon "github.com/nodeset-org/hyperdrive-stakewise/common"
swnodeset "github.com/nodeset-org/hyperdrive-stakewise/server/nodeset"
swservice "github.com/nodeset-org/hyperdrive-stakewise/server/service"
Expand All @@ -21,9 +23,9 @@ type ServerManager struct {
}

// Creates a new server manager
func NewServerManager(sp swcommon.IStakeWiseServiceProvider, ip string, port uint16, stopWg *sync.WaitGroup) (*ServerManager, error) {
func NewServerManager(sp swcommon.IStakeWiseServiceProvider, ip string, port uint16, stopWg *sync.WaitGroup, authMgr *auth.AuthorizationManager) (*ServerManager, error) {
// Start the API server
apiServer, err := createServer(sp, ip, port)
apiServer, err := createServer(sp, ip, port, authMgr)
if err != nil {
return nil, fmt.Errorf("error creating API server: %w", err)
}
Expand Down Expand Up @@ -55,20 +57,28 @@ func (m *ServerManager) Stop() {
}

// Creates a new Hyperdrive API server
func createServer(sp swcommon.IStakeWiseServiceProvider, ip string, port uint16) (*server.NetworkSocketApiServer, error) {
func createServer(sp swcommon.IStakeWiseServiceProvider, ip string, port uint16, authMgr *auth.AuthorizationManager) (*server.NetworkSocketApiServer, error) {
apiLogger := sp.GetApiLogger()
ctx := apiLogger.CreateContextWithLogger(sp.GetBaseContext())

// Create the API handlers
handlers := []server.IHandler{
swnodeset.NewNodesetHandler(apiLogger, ctx, sp),
swservice.NewServiceHandler(apiLogger, ctx, sp),
swvalidator.NewValidatorHandler(apiLogger, ctx, sp),
swwallet.NewWalletHandler(apiLogger, ctx, sp),
swstatus.NewStatusHandler(apiLogger, ctx, sp),
}

// Create the API server
server, err := server.NewNetworkSocketApiServer(apiLogger.Logger, ip, port, handlers, swconfig.DaemonBaseRoute, swconfig.ApiVersion)
if err != nil {
return nil, err
}

// Add the authorization middleware
server.GetApiRouter().Use(func(next http.Handler) http.Handler {
return authMgr.GetRequestHandler(apiLogger.Logger, next)
})
return server, nil
}
35 changes: 33 additions & 2 deletions stakewise-daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/nodeset-org/hyperdrive-daemon/module-utils/services"
"github.com/nodeset-org/hyperdrive-daemon/shared"
"github.com/nodeset-org/hyperdrive-daemon/shared/auth"
hdconfig "github.com/nodeset-org/hyperdrive-daemon/shared/config"
swcommon "github.com/nodeset-org/hyperdrive-stakewise/common"
"github.com/nodeset-org/hyperdrive-stakewise/server"
Expand Down Expand Up @@ -75,13 +76,27 @@ func main() {
Usage: "The port to bind the API server to",
Value: uint(swconfig.DefaultApiPort),
}
apiKeyFlag := &cli.StringFlag{
Name: "api-key",
Aliases: []string{"k"},
Usage: "Path of the key to use for authenticating incoming API requests",
Required: true,
}
hyperdriveApiKeyFlag := &cli.StringFlag{
Name: "hd-api-key",
Aliases: []string{"hk"},
Usage: "Path of the key to use when sending requests to the Hyperdrive API",
Required: true,
}

app.Flags = []cli.Flag{
moduleDirFlag,
hyperdriveUrlFlag,
settingsFolderFlag,
ipFlag,
portFlag,
apiKeyFlag,
hyperdriveApiKeyFlag,
}
app.Action = func(c *cli.Context) error {
// Get the env vars
Expand Down Expand Up @@ -111,14 +126,30 @@ func main() {
os.Exit(1)
}

// Make an incoming API auth manager
apiKeyPath := c.String(apiKeyFlag.Name)
moduleAuthMgr := auth.NewAuthorizationManager(apiKeyPath, "sw-daemon-svr", auth.DefaultRequestLifespan)
err = moduleAuthMgr.LoadAuthKey()
if err != nil {
return fmt.Errorf("error loading module API key: %w", err)
}

// Make an HD API auth manager
hdApiKeyPath := c.String(hyperdriveApiKeyFlag.Name)
hdAuthMgr := auth.NewAuthorizationManager(hdApiKeyPath, "sw-daemon-client", auth.DefaultRequestLifespan)
err = hdAuthMgr.LoadAuthKey()
if err != nil {
return fmt.Errorf("error loading Hyperdrive API key: %w", err)
}

// Wait group to handle the API server (separate because of error handling)
stopWg := new(sync.WaitGroup)

// Create the service provider
configFactory := func(hdCfg *hdconfig.HyperdriveConfig) (*swconfig.StakeWiseConfig, error) {
return swconfig.NewStakeWiseConfig(hdCfg, settingsList)
}
sp, err := services.NewModuleServiceProvider(hyperdriveUrl, moduleDir, swconfig.ModuleName, swconfig.ClientLogName, configFactory)
sp, err := services.NewModuleServiceProvider(hyperdriveUrl, moduleDir, swconfig.ModuleName, swconfig.ClientLogName, configFactory, hdAuthMgr)
if err != nil {
return fmt.Errorf("error creating service provider: %w", err)
}
Expand All @@ -138,7 +169,7 @@ func main() {
// Start the server after the task loop so it can log into NodeSet before this starts serving registration status checks
ip := c.String(ipFlag.Name)
port := c.Uint64(portFlag.Name)
serverMgr, err := server.NewServerManager(stakewiseSp, ip, uint16(port), stopWg)
serverMgr, err := server.NewServerManager(stakewiseSp, ip, uint16(port), stopWg, moduleAuthMgr)
if err != nil {
return fmt.Errorf("error creating StakeWise server: %w", err)
}
Expand Down
13 changes: 11 additions & 2 deletions testing/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"sync"

hdservices "github.com/nodeset-org/hyperdrive-daemon/module-utils/services"
"github.com/nodeset-org/hyperdrive-daemon/shared/auth"
hdconfig "github.com/nodeset-org/hyperdrive-daemon/shared/config"
hdtesting "github.com/nodeset-org/hyperdrive-daemon/testing"
swclient "github.com/nodeset-org/hyperdrive-stakewise/client"
Expand All @@ -17,6 +18,10 @@ import (
swconfig "github.com/nodeset-org/hyperdrive-stakewise/shared/config"
)

const (
apiAuthKey string = "sw-test-key"
)

// A complete StakeWise node instance
type StakeWiseNode struct {
// The daemon's service provider
Expand All @@ -43,7 +48,9 @@ func newStakeWiseNode(sp swcommon.IStakeWiseServiceProvider, address string, cli
// Create the server
wg := &sync.WaitGroup{}
cfg := sp.GetConfig()
serverMgr, err := swserver.NewServerManager(sp, address, cfg.ApiPort.Value, wg)
serverAuthMgr := auth.NewAuthorizationManager("", "sw-server", auth.DefaultRequestLifespan)
serverAuthMgr.SetKey([]byte(apiAuthKey))
serverMgr, err := swserver.NewServerManager(sp, address, cfg.ApiPort.Value, wg, serverAuthMgr)
if err != nil {
return nil, fmt.Errorf("error creating constellation server: %v", err)
}
Expand All @@ -54,7 +61,9 @@ func newStakeWiseNode(sp swcommon.IStakeWiseServiceProvider, address string, cli
if err != nil {
return nil, fmt.Errorf("error parsing client URL [%s]: %v", urlString, err)
}
apiClient := swclient.NewApiClient(url, clientLogger, nil)
clientAuthMgr := auth.NewAuthorizationManager("", "sw-client", auth.DefaultRequestLifespan)
clientAuthMgr.SetKey([]byte(apiAuthKey))
apiClient := swclient.NewApiClient(url, clientLogger, nil, clientAuthMgr)

return &StakeWiseNode{
sp: sp,
Expand Down

0 comments on commit 3101b38

Please sign in to comment.