diff --git a/app/node/builder.go b/app/node/builder.go index 8d01c42cb8..af35db0788 100644 --- a/app/node/builder.go +++ b/app/node/builder.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/filecoin-project/venus-auth/jwtclient" "github.com/filecoin-project/venus/app/submodule/dagservice" "github.com/filecoin-project/venus/app/submodule/network" @@ -27,7 +28,6 @@ import ( chain2 "github.com/filecoin-project/venus/pkg/chain" "github.com/filecoin-project/venus/pkg/clock" "github.com/filecoin-project/venus/pkg/journal" - "github.com/filecoin-project/venus/pkg/jwtauth" "github.com/filecoin-project/venus/pkg/paychmgr" "github.com/filecoin-project/venus/pkg/repo" "github.com/filecoin-project/venus/pkg/util/ffiwrapper" @@ -186,15 +186,20 @@ func (b *Builder) build(ctx context.Context) (*Node, error) { return nil, errors.Wrap(err, "add service failed ") } + var client *jwtclient.AuthClient cfg := nd.repo.Config() if len(cfg.API.VenusAuthURL) > 0 { - nd.remoteAuth = jwtauth.NewRemoteAuth(cfg.API.VenusAuthURL) + client, err = jwtclient.NewAuthClient(cfg.API.VenusAuthURL) + if err != nil { + return nil, fmt.Errorf("failed to create remote jwt auth client: %w", err) + } + nd.remoteAuth = jwtclient.WarpIJwtAuthClient(client) } var ratelimiter *ratelimit.RateLimiter - if nd.remoteAuth != nil && cfg.RateLimitCfg.Enable { + if client != nil && cfg.RateLimitCfg.Enable { if ratelimiter, err = ratelimit.NewRateLimitHandler(cfg.RateLimitCfg.Endpoint, - nil, &jwtauth.ValueFromCtx{}, nd.remoteAuth, logging.Logger("rate-limit")); err != nil { + nil, &ValueFromCtx{}, jwtclient.WarpLimitFinder(client), logging.Logger("rate-limit")); err != nil { return nil, fmt.Errorf("request rate-limit is enabled, but create rate-limit handler failed:%w", err) } _ = logging.SetLogLevel("rate-limit", "warn") @@ -204,3 +209,12 @@ func (b *Builder) build(ctx context.Context) (*Node, error) { nd.jsonRPCService = apiBuilder.Build("v0", ratelimiter) return nd, nil } + +type ValueFromCtx struct{} + +func (vfc *ValueFromCtx) AccFromCtx(ctx context.Context) (string, bool) { + return jwtclient.CtxGetName(ctx) +} +func (vfc *ValueFromCtx) HostFromCtx(ctx context.Context) (string, bool) { + return jwtclient.CtxGetTokenLocation(ctx) +} diff --git a/app/node/node.go b/app/node/node.go index 5d17f3f54f..10ebf09869 100644 --- a/app/node/node.go +++ b/app/node/node.go @@ -11,7 +11,7 @@ import ( "contrib.go.opencensus.io/exporter/jaeger" "github.com/awnumar/memguard" "github.com/filecoin-project/go-jsonrpc" - "github.com/filecoin-project/venus-auth/cmd/jwtclient" + "github.com/filecoin-project/venus-auth/jwtclient" "github.com/filecoin-project/venus/app/submodule/blockstore" chain2 "github.com/filecoin-project/venus/app/submodule/chain" configModule "github.com/filecoin-project/venus/app/submodule/config" @@ -31,7 +31,6 @@ import ( "github.com/filecoin-project/venus/pkg/config" _ "github.com/filecoin-project/venus/pkg/crypto/bls" // enable bls signatures _ "github.com/filecoin-project/venus/pkg/crypto/secp" // enable secp signatures - "github.com/filecoin-project/venus/pkg/jwtauth" "github.com/filecoin-project/venus/pkg/metrics" "github.com/filecoin-project/venus/pkg/repo" cmds "github.com/ipfs/go-ipfs-cmds" @@ -100,7 +99,7 @@ type Node struct { jsonRPCService, jsonRPCServiceV1 *jsonrpc.RPCServer jaegerExporter *jaeger.Exporter - remoteAuth *jwtauth.RemoteAuth + remoteAuth jwtclient.IJwtAuthClient } func (node *Node) Chain() *chain2.ChainSubmodule { @@ -261,9 +260,13 @@ func (node *Node) RunRPCAndWait(ctx context.Context, rootCmdDaemon *cmds.Command return err } - localVerifer, err := jwtauth.NewJwtAuth(node.repo) + localVerifer, token, err := jwtclient.NewLocalAuthClient() if err != nil { - return err + return fmt.Errorf("failed to generate local auth client: %s", err) + } + err = node.repo.SetAPIToken(token) + if err != nil { + return fmt.Errorf("set token fail: %w", err) } authMux := jwtclient.NewAuthMux(localVerifer, node.remoteAuth, mux) diff --git a/app/node/test/api.go b/app/node/test/api.go index 0a2258ca4b..d9cd5ebe63 100644 --- a/app/node/test/api.go +++ b/app/node/test/api.go @@ -55,6 +55,7 @@ func (a *NodeAPI) Run(ctx context.Context) (client *Client, stop func()) { token, err := a.node.Repo().APIToken() require.NoError(a.tb, err) + require.NotEmpty(a.tb, token, "empty token") return &Client{addr, token, a.tb}, func() { cancel() } diff --git a/app/node/test/builder.go b/app/node/test/builder.go index 020f318931..9e94083965 100644 --- a/app/node/test/builder.go +++ b/app/node/test/builder.go @@ -4,8 +4,6 @@ import ( "context" "testing" - "github.com/filecoin-project/venus/pkg/jwtauth" - "github.com/filecoin-project/venus/pkg/wallet" "github.com/stretchr/testify/require" @@ -98,8 +96,7 @@ func (b *NodeBuilder) Build(ctx context.Context) *node.Node { // Initialize the node. repoConfigOpts, err := node.OptionsFromRepo(repo) b.requireNoError(err) - _, err = jwtauth.NewJwtAuth(repo) - b.requireNoError(err) + nd, err := node.New(ctx, append(repoConfigOpts, b.builderOpts...)...) b.requireNoError(err) return nd diff --git a/go.mod b/go.mod index 929c78d969..c8adfd406f 100644 --- a/go.mod +++ b/go.mod @@ -42,9 +42,8 @@ require ( github.com/filecoin-project/specs-actors/v8 v8.0.1 github.com/filecoin-project/specs-storage v0.4.1 github.com/filecoin-project/test-vectors/schema v0.0.5 - github.com/filecoin-project/venus-auth v1.6.0 + github.com/filecoin-project/venus-auth v1.6.1-0.20220818060206-3313af6a9ba1 github.com/fxamacker/cbor/v2 v2.4.0 - github.com/gbrlsnchs/jwt/v3 v3.0.1 github.com/go-errors/errors v1.0.1 github.com/go-kit/kit v0.12.0 github.com/golang/mock v1.6.0 @@ -156,6 +155,7 @@ require ( github.com/flynn/noise v1.0.0 // indirect github.com/francoispqt/gojay v1.2.13 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/gbrlsnchs/jwt/v3 v3.0.1 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.7.0 // indirect github.com/go-kit/log v0.2.0 // indirect diff --git a/go.sum b/go.sum index 98d8371957..01477f4084 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= @@ -407,8 +409,8 @@ github.com/filecoin-project/storetheindex v0.3.5 h1:KoS9TvjPm6zIZfUH8atAHJbVHOO7 github.com/filecoin-project/storetheindex v0.3.5/go.mod h1:0r3d0kSpK63O6AvLr1CjAINLi+nWD49clzcnKV+GLpI= github.com/filecoin-project/test-vectors/schema v0.0.5 h1:w3zHQhzM4pYxJDl21avXjOKBLF8egrvwUwjpT8TquDg= github.com/filecoin-project/test-vectors/schema v0.0.5/go.mod h1:iQ9QXLpYWL3m7warwvK1JC/pTri8mnfEmKygNDqqY6E= -github.com/filecoin-project/venus-auth v1.6.0 h1:DLl7q5g1eh6UTpp98MLpRWAI79k6TUw1Myh/RLeaFpU= -github.com/filecoin-project/venus-auth v1.6.0/go.mod h1:x/Cv3zz9z5O+/uqIKgYtk5UsL7nYu+CtiPjyVQ8Lywg= +github.com/filecoin-project/venus-auth v1.6.1-0.20220818060206-3313af6a9ba1 h1:05GqP2sgTlGDLLSmMgkdz/1RgYBwnKDf08Qj5OrcjvU= +github.com/filecoin-project/venus-auth v1.6.1-0.20220818060206-3313af6a9ba1/go.mod h1:eqjx1U5sJ/3bqqc3PDJutap9A1GAO4fXVt25J6Sm9Fk= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/flynn/noise v0.0.0-20180327030543-2492fe189ae6/go.mod h1:1i71OnUq3iUe1ma7Lr6yG6/rjvM3emb6yoL7xLFzcVQ= github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= diff --git a/pkg/jwtauth/local_jwt.go b/pkg/jwtauth/local_jwt.go deleted file mode 100644 index 63b314806b..0000000000 --- a/pkg/jwtauth/local_jwt.go +++ /dev/null @@ -1,92 +0,0 @@ -package jwtauth - -import ( - "context" - "crypto/rand" - "fmt" - "io" - "io/ioutil" - "strings" - - vjc "github.com/filecoin-project/venus-auth/cmd/jwtclient" - "github.com/filecoin-project/venus/venus-shared/api/permission" - - "github.com/filecoin-project/go-jsonrpc/auth" - jwt3 "github.com/gbrlsnchs/jwt/v3" - logging "github.com/ipfs/go-log" - xerrors "github.com/pkg/errors" - - "github.com/filecoin-project/venus/pkg/repo" -) - -type APIAlg jwt3.HMACSHA - -var jwtLog = logging.Logger("jwt") - -type JwtPayload struct { - Allow []auth.Permission -} - -// JwtAuth auth through local token -type JwtAuth struct { - apiSecret *APIAlg - jwtSecetName string - jwtHmacSecret string - payload JwtPayload - lr repo.Repo -} - -func NewJwtAuth(lr repo.Repo) (vjc.IJwtAuthClient, error) { - jwtAuth := &JwtAuth{ - jwtSecetName: "auth-jwt-private", - jwtHmacSecret: "jwt-hmac-secret", - lr: lr, - payload: JwtPayload{Allow: permission.AllPermissions}, - } - - var err error - jwtAuth.apiSecret, err = jwtAuth.loadAPISecret() - if err != nil { - return nil, err - } - return vjc.IJwtAuthClient(jwtAuth), nil -} - -func (jwtAuth *JwtAuth) loadAPISecret() (*APIAlg, error) { - sk, err := jwtAuth.lr.Keystore().Get(jwtAuth.jwtHmacSecret) - // todo use customer keystore to replace - if err != nil && strings.Contains(err.Error(), "no key by the given name was found") { - jwtLog.Warn("Generating new API secret") - - sk, err = ioutil.ReadAll(io.LimitReader(rand.Reader, 32)) - if err != nil { - return nil, err - } - - if err := jwtAuth.lr.Keystore().Put(jwtAuth.jwtHmacSecret, sk); err != nil { - return nil, xerrors.Wrap(err, "failed to store private key") - } - - cliToken, err := jwt3.Sign(&jwtAuth.payload, jwt3.NewHS256(sk)) - if err != nil { - return nil, err - } - - if err := jwtAuth.lr.SetAPIToken(cliToken); err != nil { - return nil, err - } - } else if err != nil { - return nil, fmt.Errorf("could not get JWT Token: %v", err) - } - - return (*APIAlg)(jwt3.NewHS256(sk)), nil -} - -// Verify verify token from request -func (jwtAuth *JwtAuth) Verify(ctx context.Context, token string) ([]auth.Permission, error) { - var payload JwtPayload - if _, err := jwt3.Verify([]byte(token), (*jwt3.HMACSHA)(jwtAuth.apiSecret), &payload); err != nil { - return nil, fmt.Errorf("JWT Verification failed: %v", err) - } - return payload.Allow, nil -} diff --git a/pkg/jwtauth/remote_auth.go b/pkg/jwtauth/remote_auth.go deleted file mode 100644 index 82c208e51e..0000000000 --- a/pkg/jwtauth/remote_auth.go +++ /dev/null @@ -1,67 +0,0 @@ -package jwtauth - -import ( - "context" - - "github.com/filecoin-project/go-jsonrpc/auth" - va "github.com/filecoin-project/venus-auth/auth" - vjc "github.com/filecoin-project/venus-auth/cmd/jwtclient" - "github.com/filecoin-project/venus-auth/core" - "github.com/ipfs-force-community/metrics/ratelimit" -) - -var _ vjc.IJwtAuthClient = (*RemoteAuth)(nil) -var _ ratelimit.ILimitFinder = (*RemoteAuth)(nil) - -type ValueFromCtx struct{} - -func (vfc *ValueFromCtx) AccFromCtx(ctx context.Context) (string, bool) { - return vjc.CtxGetName(ctx) -} -func (vfc *ValueFromCtx) HostFromCtx(ctx context.Context) (string, bool) { - return vjc.CtxGetTokenLocation(ctx) -} - -// RemoteAuth in remote verification mode, venus connects venus-auth service, and verifies whether token is legal through rpc -type RemoteAuth struct { - remote *vjc.AuthClient -} - -// NewRemoteAuth new remote auth client from venus-auth url -func NewRemoteAuth(url string) *RemoteAuth { - // vjc.NewAuthClient always return nil error - cli, _ := vjc.NewAuthClient(url) - return &RemoteAuth{remote: cli} -} - -// Verify check token through venus-auth rpc api -func (r *RemoteAuth) Verify(ctx context.Context, token string) ([]auth.Permission, error) { - var perms []auth.Permission - var err error - - var res *va.VerifyResponse - if res, err = r.remote.Verify(ctx, token); err != nil { - return nil, err - } - - jwtPerms := core.AdaptOldStrategy(res.Perm) - perms = make([]auth.Permission, len(jwtPerms)) - copy(perms, jwtPerms) - - return perms, nil -} - -func (r *RemoteAuth) GetUserLimit(name, service, api string) (*ratelimit.Limit, error) { - res, err := r.remote.GetUserRateLimit(name, "") - if err != nil { - return nil, err - } - - var limit = &ratelimit.Limit{Account: name, Cap: 0, Duration: 0} - if l := res.MatchedLimit(service, api); l != nil { - limit.Cap = l.ReqLimit.Cap - limit.Duration = l.ReqLimit.ResetDur - } - - return limit, nil -}