From de75a3eb91ee0d51fcaea4438241b2f2b5916a74 Mon Sep 17 00:00:00 2001 From: Jimil Desai Date: Wed, 28 Jul 2021 18:17:13 +0530 Subject: [PATCH] revert context passing and added support for auth_provider plugin Signed-off-by: Jimil Desai --- .../services/authprovider/authprovider.go | 41 +++++-- pkg/auth/auth.go | 2 + pkg/auth/manager/appauth/appauth.go | 12 +- pkg/auth/manager/demo/demo.go | 9 +- pkg/auth/manager/impersonator/impersonator.go | 4 + pkg/auth/manager/json/json.go | 21 ++-- pkg/auth/manager/ldap/ldap.go | 17 ++- pkg/auth/manager/oidc/oidc.go | 15 ++- pkg/auth/manager/publicshares/publicshares.go | 15 ++- pkg/auth/rpc_auth.go | 110 ++++++++++++++++++ pkg/user/rpc_user.go | 20 ++-- 11 files changed, 225 insertions(+), 41 deletions(-) create mode 100644 pkg/auth/rpc_auth.go diff --git a/internal/grpc/services/authprovider/authprovider.go b/internal/grpc/services/authprovider/authprovider.go index 535e388a938..f3a27dbd82e 100644 --- a/internal/grpc/services/authprovider/authprovider.go +++ b/internal/grpc/services/authprovider/authprovider.go @@ -21,12 +21,14 @@ package authprovider import ( "context" "fmt" + "path/filepath" provider "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1" "github.com/cs3org/reva/pkg/appctx" "github.com/cs3org/reva/pkg/auth" "github.com/cs3org/reva/pkg/auth/manager/registry" "github.com/cs3org/reva/pkg/errtypes" + "github.com/cs3org/reva/pkg/plugin" "github.com/cs3org/reva/pkg/rgrpc" "github.com/cs3org/reva/pkg/rgrpc/status" "github.com/mitchellh/mapstructure" @@ -52,6 +54,7 @@ func (c *config) init() { type service struct { authmgr auth.Manager conf *config + plugin *plugin.RevaPlugin } func parseConfig(m map[string]interface{}) (*config, error) { @@ -64,14 +67,31 @@ func parseConfig(m map[string]interface{}) (*config, error) { return c, nil } -func getAuthManager(manager string, m map[string]map[string]interface{}) (auth.Manager, error) { +func getAuthManager(manager string, m map[string]map[string]interface{}) (auth.Manager, *plugin.RevaPlugin, error) { if manager == "" { - return nil, errtypes.InternalError("authsvc: driver not configured for auth manager") + return nil, nil, errtypes.InternalError("authsvc: driver not configured for auth manager") } - if f, ok := registry.NewFuncs[manager]; ok { - return f(m[manager]) + p, err := plugin.Load("authprovider", manager) + if err == nil { + authManager, ok := p.Plugin.(auth.Manager) + if !ok { + return nil, nil, fmt.Errorf("could not assert the loaded plugin") + } + pluginConfig := filepath.Base(manager) + err = authManager.Configure(m[pluginConfig]) + if err != nil { + return nil, nil, err + } + return authManager, p, nil + } else if _, ok := err.(errtypes.NotFound); ok { + if f, ok := registry.NewFuncs[manager]; ok { + authmgr, err := f(m[manager]) + return authmgr, nil, err + } + } else { + return nil, nil, err } - return nil, errtypes.NotFound(fmt.Sprintf("authsvc: driver %s not found for auth manager", manager)) + return nil, nil, errtypes.NotFound(fmt.Sprintf("authsvc: driver %s not found for auth manager", manager)) } // New returns a new AuthProviderServiceServer. @@ -81,17 +101,24 @@ func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) { return nil, err } - authManager, err := getAuthManager(c.AuthManager, c.AuthManagers) + authManager, plug, err := getAuthManager(c.AuthManager, c.AuthManagers) if err != nil { return nil, err } - svc := &service{conf: c, authmgr: authManager} + svc := &service{ + conf: c, + authmgr: authManager, + plugin: plug, + } return svc, nil } func (s *service) Close() error { + if s.plugin != nil { + s.plugin.Kill() + } return nil } diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go index 87140996833..a3cd390338e 100644 --- a/pkg/auth/auth.go +++ b/pkg/auth/auth.go @@ -25,10 +25,12 @@ import ( authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1" registry "github.com/cs3org/go-cs3apis/cs3/auth/registry/v1beta1" user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + "github.com/cs3org/reva/pkg/plugin" ) // Manager is the interface to implement to authenticate users type Manager interface { + plugin.Plugin Authenticate(ctx context.Context, clientID, clientSecret string) (*user.User, map[string]*authpb.Scope, error) } diff --git a/pkg/auth/manager/appauth/appauth.go b/pkg/auth/manager/appauth/appauth.go index cb4b29a0201..738f51b4cd5 100644 --- a/pkg/auth/manager/appauth/appauth.go +++ b/pkg/auth/manager/appauth/appauth.go @@ -44,13 +44,21 @@ type manager struct { // New returns a new auth Manager. func New(m map[string]interface{}) (auth.Manager, error) { mgr := &manager{} - err := mapstructure.Decode(m, mgr) + err := mgr.Configure(m) if err != nil { - return nil, errors.Wrap(err, "error decoding conf") + return nil, err } return mgr, nil } +func (m *manager) Configure(ml map[string]interface{}) error { + err := mapstructure.Decode(ml, m) + if err != nil { + return errors.Wrap(err, "error decoding conf") + } + return nil +} + func (m *manager) Authenticate(ctx context.Context, username, password string) (*user.User, map[string]*authpb.Scope, error) { gtw, err := pool.GetGatewayServiceClient(m.GatewayAddr) if err != nil { diff --git a/pkg/auth/manager/demo/demo.go b/pkg/auth/manager/demo/demo.go index b0636f62eeb..7f2e1ddd6d6 100644 --- a/pkg/auth/manager/demo/demo.go +++ b/pkg/auth/manager/demo/demo.go @@ -46,8 +46,15 @@ type Credentials struct { // New returns a new auth Manager. func New(m map[string]interface{}) (auth.Manager, error) { // m not used + mgr := &manager{} + err := mgr.Configure(m) + return mgr, err +} + +func (m *manager) Configure(ml map[string]interface{}) error { creds := getCredentials() - return &manager{credentials: creds}, nil + m.credentials = creds + return nil } func (m *manager) Authenticate(ctx context.Context, clientID, clientSecret string) (*user.User, map[string]*authpb.Scope, error) { diff --git a/pkg/auth/manager/impersonator/impersonator.go b/pkg/auth/manager/impersonator/impersonator.go index 0f9fd612baa..19d7f88000f 100644 --- a/pkg/auth/manager/impersonator/impersonator.go +++ b/pkg/auth/manager/impersonator/impersonator.go @@ -40,6 +40,10 @@ func New(c map[string]interface{}) (auth.Manager, error) { return &mgr{}, nil } +func (m *mgr) Configure(ml map[string]interface{}) error { + return nil +} + func (m *mgr) Authenticate(ctx context.Context, clientID, clientSecret string) (*user.User, map[string]*authpb.Scope, error) { // allow passing in uid as @ at := strings.LastIndex(clientID, "@") diff --git a/pkg/auth/manager/json/json.go b/pkg/auth/manager/json/json.go index e12c907126d..daf81e25b3e 100644 --- a/pkg/auth/manager/json/json.go +++ b/pkg/auth/manager/json/json.go @@ -79,30 +79,37 @@ func parseConfig(m map[string]interface{}) (*config, error) { // New returns a new auth Manager. func New(m map[string]interface{}) (auth.Manager, error) { - c, err := parseConfig(m) + mgr := &manager{} + err := mgr.Configure(m) if err != nil { return nil, err } + return mgr, nil +} - manager := &manager{credentials: map[string]*Credentials{}} +func (m *manager) Configure(ml map[string]interface{}) error { + c, err := parseConfig(ml) + if err != nil { + return err + } + m.credentials = map[string]*Credentials{} f, err := ioutil.ReadFile(c.Users) if err != nil { - return nil, err + return err } credentials := []*Credentials{} err = json.Unmarshal(f, &credentials) if err != nil { - return nil, err + return err } for _, c := range credentials { - manager.credentials[c.Username] = c + m.credentials[c.Username] = c } - - return manager, nil + return nil } func (m *manager) Authenticate(ctx context.Context, username string, secret string) (*user.User, map[string]*authpb.Scope, error) { diff --git a/pkg/auth/manager/ldap/ldap.go b/pkg/auth/manager/ldap/ldap.go index 1727076d0f1..cefd1adef0c 100644 --- a/pkg/auth/manager/ldap/ldap.go +++ b/pkg/auth/manager/ldap/ldap.go @@ -104,10 +104,19 @@ func parseConfig(m map[string]interface{}) (*config, error) { // New returns an auth manager implementation that connects to a LDAP server to validate the user. func New(m map[string]interface{}) (auth.Manager, error) { - c, err := parseConfig(m) + manager := &mgr{} + err := manager.Configure(m) if err != nil { return nil, err } + return manager, nil +} + +func (am *mgr) Configure(m map[string]interface{}) error { + c, err := parseConfig(m) + if err != nil { + return err + } // backwards compatibility if c.UserFilter != "" { @@ -122,10 +131,8 @@ func New(m map[string]interface{}) (auth.Manager, error) { } c.GatewaySvc = sharedconf.GetGatewaySVC(c.GatewaySvc) - - return &mgr{ - c: c, - }, nil + am.c = c + return nil } func (am *mgr) Authenticate(ctx context.Context, clientID, clientSecret string) (*user.User, map[string]*authpb.Scope, error) { diff --git a/pkg/auth/manager/oidc/oidc.go b/pkg/auth/manager/oidc/oidc.go index dd717bec85e..c6dd62b371a 100644 --- a/pkg/auth/manager/oidc/oidc.go +++ b/pkg/auth/manager/oidc/oidc.go @@ -79,13 +79,22 @@ func parseConfig(m map[string]interface{}) (*config, error) { // New returns an auth manager implementation that verifies the oidc token and obtains the user claims. func New(m map[string]interface{}) (auth.Manager, error) { - c, err := parseConfig(m) + manager := &mgr{} + err := manager.Configure(m) if err != nil { return nil, err } - c.init() + return manager, nil +} - return &mgr{c: c}, nil +func (am *mgr) Configure(m map[string]interface{}) error { + c, err := parseConfig(m) + if err != nil { + return err + } + c.init() + am.c = c + return nil } // the clientID it would be empty as we only need to validate the clientSecret variable diff --git a/pkg/auth/manager/publicshares/publicshares.go b/pkg/auth/manager/publicshares/publicshares.go index ceed1421116..c00f37f9965 100644 --- a/pkg/auth/manager/publicshares/publicshares.go +++ b/pkg/auth/manager/publicshares/publicshares.go @@ -61,14 +61,21 @@ func parseConfig(m map[string]interface{}) (*config, error) { // New returns a new auth Manager. func New(m map[string]interface{}) (auth.Manager, error) { - conf, err := parseConfig(m) + mgr := &manager{} + err := mgr.Configure(m) if err != nil { return nil, err } + return mgr, nil +} - return &manager{ - c: conf, - }, nil +func (m *manager) Configure(ml map[string]interface{}) error { + conf, err := parseConfig(ml) + if err != nil { + return err + } + m.c = conf + return nil } func (m *manager) Authenticate(ctx context.Context, token, secret string) (*user.User, map[string]*authpb.Scope, error) { diff --git a/pkg/auth/rpc_auth.go b/pkg/auth/rpc_auth.go new file mode 100644 index 00000000000..33a6145c47c --- /dev/null +++ b/pkg/auth/rpc_auth.go @@ -0,0 +1,110 @@ +// Copyright 2018-2021 CERN +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package auth + +import ( + "context" + "net/rpc" + + authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1" + user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" + "github.com/cs3org/reva/pkg/plugin" + hcplugin "github.com/hashicorp/go-plugin" +) + +func init() { + plugin.Register("authprovider", &AuthProviderPlugin{}) +} + +// ProviderPlugin is the implementation of plugin.Plugin so we can serve/consume this. +type AuthProviderPlugin struct { + Impl Manager +} + +// Server returns the RPC Server which serves the methods that the Client calls over net/rpc +func (p *AuthProviderPlugin) Server(*hcplugin.MuxBroker) (interface{}, error) { + return &RPCServer{Impl: p.Impl}, nil +} + +// Client returns interface implementation for the plugin that communicates to the server end of the plugin +func (p *AuthProviderPlugin) Client(b *hcplugin.MuxBroker, c *rpc.Client) (interface{}, error) { + return &RPCClient{Client: c}, nil +} + +// RPCClient is an implementation of Manager that talks over RPC. +type RPCClient struct{ Client *rpc.Client } + +// ConfigureArg for RPC +type ConfigureArg struct { + Ml map[string]interface{} +} + +// ConfigureReply for RPC +type ConfigureReply struct { + Err error +} + +// Configure RPCClient configure method +func (m *RPCClient) Configure(ml map[string]interface{}) error { + args := ConfigureArg{Ml: ml} + resp := ConfigureReply{} + err := m.Client.Call("Plugin.Configure", args, &resp) + if err != nil { + return err + } + return resp.Err +} + +type AuthenticateArgs struct { + ClientID string + ClientSecret string +} + +type AuthenticateReply struct { + User *user.User + Auth map[string]*authpb.Scope + Error error +} + +func (m *RPCClient) Authenticate(ctx context.Context, clientID, clientSecret string) (*user.User, map[string]*authpb.Scope, error) { + args := AuthenticateArgs{ClientID: clientID, ClientSecret: clientSecret} + reply := AuthenticateReply{} + err := m.Client.Call("Plugin.Authenticate", args, &reply) + if err != nil { + return nil, nil, err + } + return reply.User, reply.Auth, reply.Error +} + +// RPCServer is the server that RPCClient talks to, conforming to the requirements of net/rpc +type RPCServer struct { + // This is the real implementation + Impl Manager +} + +// Configure RPCServer Configure method +func (m *RPCServer) Configure(args ConfigureArg, resp *ConfigureReply) error { + resp.Err = m.Impl.Configure(args.Ml) + return nil +} + +func (m *RPCServer) Authenticate(args AuthenticateArgs, resp *AuthenticateReply) error { + resp.User, resp.Auth, resp.Error = m.Impl.Authenticate(context.Background(), args.ClientID, args.ClientSecret) + return nil +} diff --git a/pkg/user/rpc_user.go b/pkg/user/rpc_user.go index 918e7611cd9..4a98017b7bf 100644 --- a/pkg/user/rpc_user.go +++ b/pkg/user/rpc_user.go @@ -72,7 +72,6 @@ func (m *RPCClient) Configure(ml map[string]interface{}) error { // GetUserArg for RPC type GetUserArg struct { - Ctx context.Context UID *userpb.UserId } @@ -84,7 +83,7 @@ type GetUserReply struct { // GetUser RPCClient GetUser method func (m *RPCClient) GetUser(ctx context.Context, uid *userpb.UserId) (*userpb.User, error) { - args := GetUserArg{UID: uid, Ctx: ctx} + args := GetUserArg{UID: uid} resp := GetUserReply{} err := m.Client.Call("Plugin.GetUser", args, &resp) if err != nil { @@ -95,7 +94,6 @@ func (m *RPCClient) GetUser(ctx context.Context, uid *userpb.UserId) (*userpb.Us // GetUserByClaimArg for RPC type GetUserByClaimArg struct { - Ctx context.Context Claim string Value string } @@ -108,7 +106,7 @@ type GetUserByClaimReply struct { // GetUserByClaim RPCClient GetUserByClaim method func (m *RPCClient) GetUserByClaim(ctx context.Context, claim, value string) (*userpb.User, error) { - args := GetUserByClaimArg{Ctx: ctx, Claim: claim, Value: value} + args := GetUserByClaimArg{Claim: claim, Value: value} resp := GetUserByClaimReply{} err := m.Client.Call("Plugin.GetUserByClaim", args, &resp) if err != nil { @@ -119,7 +117,6 @@ func (m *RPCClient) GetUserByClaim(ctx context.Context, claim, value string) (*u // GetUserGroupsArg for RPC type GetUserGroupsArg struct { - Ctx context.Context User *userpb.UserId } @@ -131,7 +128,7 @@ type GetUserGroupsReply struct { // GetUserGroups RPCClient GetUserGroups method func (m *RPCClient) GetUserGroups(ctx context.Context, user *userpb.UserId) ([]string, error) { - args := GetUserGroupsArg{Ctx: ctx, User: user} + args := GetUserGroupsArg{User: user} resp := GetUserGroupsReply{} err := m.Client.Call("Plugin.GetUserGroups", args, &resp) if err != nil { @@ -142,7 +139,6 @@ func (m *RPCClient) GetUserGroups(ctx context.Context, user *userpb.UserId) ([]s // FindUsersArg for RPC type FindUsersArg struct { - Ctx context.Context Query string } @@ -154,7 +150,7 @@ type FindUsersReply struct { // FindUsers RPCClient FindUsers method func (m *RPCClient) FindUsers(ctx context.Context, query string) ([]*userpb.User, error) { - args := FindUsersArg{Ctx: ctx, Query: query} + args := FindUsersArg{Query: query} resp := FindUsersReply{} err := m.Client.Call("Plugin.FindUsers", args, &resp) if err != nil { @@ -177,24 +173,24 @@ func (m *RPCServer) Configure(args ConfigureArg, resp *ConfigureReply) error { // GetUser RPCServer GetUser method func (m *RPCServer) GetUser(args GetUserArg, resp *GetUserReply) error { - resp.User, resp.Err = m.Impl.GetUser(args.Ctx, args.UID) + resp.User, resp.Err = m.Impl.GetUser(context.Background(), args.UID) return nil } // GetUserByClaim RPCServer GetUserByClaim method func (m *RPCServer) GetUserByClaim(args GetUserByClaimArg, resp *GetUserByClaimReply) error { - resp.User, resp.Err = m.Impl.GetUserByClaim(args.Ctx, args.Claim, args.Value) + resp.User, resp.Err = m.Impl.GetUserByClaim(context.Background(), args.Claim, args.Value) return nil } // GetUserGroups RPCServer GetUserGroups method func (m *RPCServer) GetUserGroups(args GetUserGroupsArg, resp *GetUserGroupsReply) error { - resp.Group, resp.Err = m.Impl.GetUserGroups(args.Ctx, args.User) + resp.Group, resp.Err = m.Impl.GetUserGroups(context.Background(), args.User) return nil } // FindUsers RPCServer FindUsers method func (m *RPCServer) FindUsers(args FindUsersArg, resp *FindUsersReply) error { - resp.User, resp.Err = m.Impl.FindUsers(args.Ctx, args.Query) + resp.User, resp.Err = m.Impl.FindUsers(context.Background(), args.Query) return nil }