auth: Put auth methods in API
This commit is contained in:
parent
fa4bf5178a
commit
309ecc4052
@ -33,6 +33,10 @@ type MsgWait struct {
|
|||||||
|
|
||||||
// API is a low-level interface to the Filecoin network
|
// API is a low-level interface to the Filecoin network
|
||||||
type API interface {
|
type API interface {
|
||||||
|
// Auth
|
||||||
|
AuthVerify(ctx context.Context, token string) ([]string, error)
|
||||||
|
AuthNew(ctx context.Context, perms []string) ([]byte, error)
|
||||||
|
|
||||||
// chain
|
// chain
|
||||||
|
|
||||||
ChainHead(context.Context) (*chain.TipSet, error) // TODO: check serialization
|
ChainHead(context.Context) (*chain.TipSet, error) // TODO: check serialization
|
||||||
|
@ -17,6 +17,7 @@ const (
|
|||||||
// todo: more perms once needed (network / sign / call/invoke / miner / etc)
|
// todo: more perms once needed (network / sign / call/invoke / miner / etc)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var AllPermissions = []string{PermRead, PermWrite}
|
||||||
var defaultPerms = []string{PermRead}
|
var defaultPerms = []string{PermRead}
|
||||||
|
|
||||||
func WithPerm(ctx context.Context, perms []string) context.Context {
|
func WithPerm(ctx context.Context, perms []string) context.Context {
|
||||||
|
@ -14,6 +14,9 @@ import (
|
|||||||
// Struct implements API passing calls to user-provided function values.
|
// Struct implements API passing calls to user-provided function values.
|
||||||
type Struct struct {
|
type Struct struct {
|
||||||
Internal struct {
|
Internal struct {
|
||||||
|
AuthVerify func(ctx context.Context, token string) ([]string, error)
|
||||||
|
AuthNew func(ctx context.Context, perms []string) ([]byte, error) `perm:"write"`
|
||||||
|
|
||||||
ID func(context.Context) (peer.ID, error)
|
ID func(context.Context) (peer.ID, error)
|
||||||
Version func(context.Context) (Version, error)
|
Version func(context.Context) (Version, error)
|
||||||
|
|
||||||
@ -46,6 +49,14 @@ type Struct struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Struct) AuthVerify(ctx context.Context, token string) ([]string, error) {
|
||||||
|
return c.Internal.AuthVerify(ctx, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Struct) AuthNew(ctx context.Context, perms []string) ([]byte, error) {
|
||||||
|
return c.Internal.AuthNew(ctx, perms)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Struct) ClientListImports(ctx context.Context) ([]Import, error) {
|
func (c *Struct) ClientListImports(ctx context.Context) ([]Import, error) {
|
||||||
return c.Internal.ClientListImports(ctx)
|
return c.Internal.ClientListImports(ctx)
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
// KeyInfo is used for storying keys in KeyStore
|
// KeyInfo is used for storing keys in KeyStore
|
||||||
type KeyInfo struct {
|
type KeyInfo struct {
|
||||||
Type string
|
Type string
|
||||||
PrivateKey []byte
|
PrivateKey []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeyStore is used for storying secret keys
|
// KeyStore is used for storing secret keys
|
||||||
type KeyStore interface {
|
type KeyStore interface {
|
||||||
// List lists all the keys stored in the KeyStore
|
// List lists all the keys stored in the KeyStore
|
||||||
List() ([]string, error)
|
List() ([]string, error)
|
||||||
// Get gets a key out of keystore and returns KeyInfo coresponding to named key
|
// Get gets a key out of keystore and returns KeyInfo corresponding to named key
|
||||||
Get(string) (KeyInfo, error)
|
Get(string) (KeyInfo, error)
|
||||||
// Put saves a key info under given name
|
// Put saves a key info under given name
|
||||||
Put(string, KeyInfo) error
|
Put(string, KeyInfo) error
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/multiformats/go-multiaddr"
|
"github.com/multiformats/go-multiaddr"
|
||||||
"go.uber.org/fx"
|
|
||||||
"gopkg.in/urfave/cli.v2"
|
"gopkg.in/urfave/cli.v2"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/node"
|
"github.com/filecoin-project/go-lotus/node"
|
||||||
@ -45,16 +44,12 @@ var Cmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
return lr.SetAPIEndpoint(apima)
|
return lr.SetAPIEndpoint(apima)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
node.Override(node.ServeRPCKey, func(lc fx.Lifecycle) error {
|
|
||||||
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: properly parse api endpoint (or make it a URL)
|
// TODO: properly parse api endpoint (or make it a URL)
|
||||||
return serveRPC(api, "127.0.0.1:"+cctx.String("api"))
|
return serveRPC(api, "127.0.0.1:"+cctx.String("api"), api.AuthVerify)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
package daemon
|
package daemon
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"github.com/filecoin-project/go-lotus/lib/auth"
|
"github.com/filecoin-project/go-lotus/lib/auth"
|
||||||
"github.com/gbrlsnchs/jwt/v3"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/api"
|
"github.com/filecoin-project/go-lotus/api"
|
||||||
"github.com/filecoin-project/go-lotus/lib/jsonrpc"
|
"github.com/filecoin-project/go-lotus/lib/jsonrpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
func serveRPC(a api.API, addr string, authSecret []byte) error {
|
func serveRPC(a api.API, addr string, verify func(ctx context.Context, token string) ([]string, error)) error {
|
||||||
rpcServer := jsonrpc.NewServer()
|
rpcServer := jsonrpc.NewServer()
|
||||||
rpcServer.Register("Filecoin", api.Permissioned(a))
|
rpcServer.Register("Filecoin", api.Permissioned(a))
|
||||||
|
|
||||||
authHandler := &auth.Handler{
|
authHandler := &auth.Handler{
|
||||||
Secret: jwt.NewHS256(authSecret),
|
Verify: verify,
|
||||||
Next: rpcServer.ServeHTTP,
|
Next: rpcServer.ServeHTTP,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-lotus/api"
|
"github.com/filecoin-project/go-lotus/api"
|
||||||
"github.com/gbrlsnchs/jwt/v3"
|
|
||||||
logging "github.com/ipfs/go-log"
|
logging "github.com/ipfs/go-log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = logging.Logger("auth")
|
var log = logging.Logger("auth")
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
Secret *jwt.HMACSHA
|
Verify func(ctx context.Context, token string) ([]string, error)
|
||||||
Next http.HandlerFunc
|
Next http.HandlerFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,28 +28,15 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
token = token[len("Bearer "):]
|
token = token[len("Bearer "):]
|
||||||
|
|
||||||
var payload jwtPayload
|
allow, err := h.Verify(ctx, token)
|
||||||
if _, err := jwt.Verify([]byte(token), h.Secret, &payload); err != nil {
|
if err != nil {
|
||||||
log.Warnf("JWT Verification failed: %s", err)
|
log.Warnf("JWT Verification failed: %s", err)
|
||||||
w.WriteHeader(401)
|
w.WriteHeader(401)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = api.WithPerm(ctx, payload.Allow)
|
ctx = api.WithPerm(ctx, allow)
|
||||||
}
|
}
|
||||||
|
|
||||||
h.Next(w, r.WithContext(ctx))
|
h.Next(w, r.WithContext(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
type jwtPayload struct {
|
|
||||||
Allow []string
|
|
||||||
}
|
|
||||||
|
|
||||||
/*func init() {
|
|
||||||
p := jwtPayload{
|
|
||||||
Allow: []string{"read", "write"},
|
|
||||||
}
|
|
||||||
r, _ := jwt.Sign(&p, secret)
|
|
||||||
log.Infof("WRITE TOKEN: %s", string(r))
|
|
||||||
}
|
|
||||||
*/
|
|
50
node/api.go
50
node/api.go
@ -11,13 +11,18 @@ import (
|
|||||||
"github.com/filecoin-project/go-lotus/miner"
|
"github.com/filecoin-project/go-lotus/miner"
|
||||||
"github.com/filecoin-project/go-lotus/node/client"
|
"github.com/filecoin-project/go-lotus/node/client"
|
||||||
|
|
||||||
|
"github.com/gbrlsnchs/jwt/v3"
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
logging "github.com/ipfs/go-log"
|
||||||
"github.com/libp2p/go-libp2p-core/host"
|
"github.com/libp2p/go-libp2p-core/host"
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
"github.com/libp2p/go-libp2p-core/peer"
|
||||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
ma "github.com/multiformats/go-multiaddr"
|
ma "github.com/multiformats/go-multiaddr"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var log = logging.Logger("node")
|
||||||
|
|
||||||
type API struct {
|
type API struct {
|
||||||
client.LocalStorage
|
client.LocalStorage
|
||||||
|
|
||||||
@ -26,6 +31,51 @@ type API struct {
|
|||||||
PubSub *pubsub.PubSub
|
PubSub *pubsub.PubSub
|
||||||
Mpool *chain.MessagePool
|
Mpool *chain.MessagePool
|
||||||
Wallet *chain.Wallet
|
Wallet *chain.Wallet
|
||||||
|
Keystore types.KeyStore
|
||||||
|
}
|
||||||
|
|
||||||
|
const JWTSecretName = "auth-jwt-private"
|
||||||
|
|
||||||
|
type jwtPayload struct {
|
||||||
|
Allow []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) AuthVerify(ctx context.Context, token string) ([]string, error) {
|
||||||
|
key, err := a.Keystore.Get(JWTSecretName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("couldn't get JWT secret: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var payload jwtPayload
|
||||||
|
if _, err := jwt.Verify([]byte(token), jwt.NewHS256(key.PrivateKey), &payload); err != nil {
|
||||||
|
return nil, xerrors.Errorf("JWT Verification failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload.Allow, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *API) AuthNew(ctx context.Context, perms []string) ([]byte, error) {
|
||||||
|
key, err := a.Keystore.Get(JWTSecretName)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("Generating new API secret")
|
||||||
|
|
||||||
|
key = types.KeyInfo{
|
||||||
|
Type: "jwt-hmac-secret",
|
||||||
|
PrivateKey: make([]byte, 32),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.Keystore.Put(JWTSecretName, key); err != nil {
|
||||||
|
return nil, xerrors.Errorf("writing API secret: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: put cli token in repo
|
||||||
|
}
|
||||||
|
|
||||||
|
p := jwtPayload{
|
||||||
|
Allow: perms, // TODO: consider checking validity
|
||||||
|
}
|
||||||
|
|
||||||
|
return jwt.Sign(&p, jwt.NewHS256(key.PrivateKey))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *API) ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error {
|
func (a *API) ChainSubmitBlock(ctx context.Context, blk *chain.BlockMsg) error {
|
||||||
|
@ -72,7 +72,6 @@ const (
|
|||||||
|
|
||||||
// daemon
|
// daemon
|
||||||
SetApiEndpointKey
|
SetApiEndpointKey
|
||||||
ServeRPCKey
|
|
||||||
|
|
||||||
_nInvokes // keep this last
|
_nInvokes // keep this last
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user