github.com/cs3org/reva/v2@v2.27.7/internal/grpc/services/gateway/authprovider.go (about)

     1  // Copyright 2018-2021 CERN
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // In applying this license, CERN does not waive the privileges and immunities
    16  // granted to it by virtue of its status as an Intergovernmental Organization
    17  // or submit itself to any jurisdiction.
    18  
    19  package gateway
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  
    25  	authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
    26  	registry "github.com/cs3org/go-cs3apis/cs3/auth/registry/v1beta1"
    27  	gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
    28  	userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    29  	rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
    30  	storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
    31  	"github.com/cs3org/reva/v2/pkg/appctx"
    32  	ctxpkg "github.com/cs3org/reva/v2/pkg/ctx"
    33  	"github.com/cs3org/reva/v2/pkg/errtypes"
    34  	"github.com/cs3org/reva/v2/pkg/rgrpc/status"
    35  	"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
    36  	"github.com/cs3org/reva/v2/pkg/sharedconf"
    37  	"github.com/pkg/errors"
    38  	"google.golang.org/grpc/metadata"
    39  	"google.golang.org/protobuf/proto"
    40  )
    41  
    42  func (s *svc) Authenticate(ctx context.Context, req *gateway.AuthenticateRequest) (*gateway.AuthenticateResponse, error) {
    43  	log := appctx.GetLogger(ctx)
    44  
    45  	// find auth provider
    46  	c, err := s.findAuthProvider(ctx, req.Type)
    47  	if err != nil {
    48  		log.Err(err).Str("type", req.Type).Msg("error getting auth provider client")
    49  		return &gateway.AuthenticateResponse{
    50  			Status: status.NewInternal(ctx, "error getting auth provider client"),
    51  		}, nil
    52  	}
    53  
    54  	authProviderReq := &authpb.AuthenticateRequest{
    55  		ClientId:     req.ClientId,
    56  		ClientSecret: req.ClientSecret,
    57  	}
    58  	res, err := c.Authenticate(ctx, authProviderReq)
    59  	switch {
    60  	case err != nil:
    61  		return &gateway.AuthenticateResponse{
    62  			Status: status.NewInternal(ctx, fmt.Sprintf("gateway: error calling Authenticate for type: %s", req.Type)),
    63  		}, nil
    64  	case res.Status.Code == rpc.Code_CODE_PERMISSION_DENIED:
    65  		fallthrough
    66  	case res.Status.Code == rpc.Code_CODE_UNAUTHENTICATED:
    67  		fallthrough
    68  	case res.Status.Code == rpc.Code_CODE_NOT_FOUND:
    69  		// normal failures, no need to log
    70  		return &gateway.AuthenticateResponse{
    71  			Status: res.Status,
    72  		}, nil
    73  	case res.Status.Code != rpc.Code_CODE_OK:
    74  		return &gateway.AuthenticateResponse{
    75  			Status: status.NewInternal(ctx, fmt.Sprintf("error authenticating credentials to auth provider for type: %s", req.Type)),
    76  		}, nil
    77  	}
    78  
    79  	// validate valid userId
    80  	if res.User == nil {
    81  		err := errtypes.NotFound("gateway: user after Authenticate is nil")
    82  		log.Err(err).Msg("user is nil")
    83  		return &gateway.AuthenticateResponse{
    84  			Status: status.NewInternal(ctx, "user is nil"),
    85  		}, nil
    86  	}
    87  
    88  	if res.User.Id == nil {
    89  		err := errtypes.NotFound("gateway: uid after Authenticate is nil")
    90  		log.Err(err).Msg("user id is nil")
    91  		return &gateway.AuthenticateResponse{
    92  			Status: status.NewInternal(ctx, "user id is nil"),
    93  		}, nil
    94  	}
    95  
    96  	u := proto.Clone(res.User).(*userpb.User)
    97  	if sharedconf.SkipUserGroupsInToken() {
    98  		u.Groups = []string{}
    99  	}
   100  
   101  	token, err := s.tokenmgr.MintToken(ctx, u, res.TokenScope)
   102  	if err != nil {
   103  		err = errors.Wrap(err, "authsvc: error in MintToken")
   104  		res := &gateway.AuthenticateResponse{
   105  			Status: status.NewUnauthenticated(ctx, err, "error creating access token"),
   106  		}
   107  		return res, nil
   108  	}
   109  
   110  	if scope, ok := res.TokenScope["user"]; s.c.DisableHomeCreationOnLogin || !ok || scope.Role != authpb.Role_ROLE_OWNER || res.User.Id.Type == userpb.UserType_USER_TYPE_FEDERATED {
   111  		gwRes := &gateway.AuthenticateResponse{
   112  			Status: status.NewOK(ctx),
   113  			User:   res.User,
   114  			Token:  token,
   115  		}
   116  		return gwRes, nil
   117  	}
   118  
   119  	// we need to pass the token to authenticate the CreateHome request.
   120  	// TODO(labkode): appending to existing context will not pass the token.
   121  	ctx = ctxpkg.ContextSetToken(ctx, token)
   122  	ctx = ctxpkg.ContextSetUser(ctx, res.User)
   123  	ctx = metadata.AppendToOutgoingContext(ctx, ctxpkg.TokenHeader, token) // TODO(jfd): hardcoded metadata key. use  PerRPCCredentials?
   124  
   125  	// create home directory
   126  	createHomeRes, err := s.CreateHome(ctx, &storageprovider.CreateHomeRequest{})
   127  	if err != nil {
   128  		log.Err(err).Msg("error calling CreateHome")
   129  		return &gateway.AuthenticateResponse{
   130  			Status: status.NewInternal(ctx, "error creating user home"),
   131  		}, nil
   132  	}
   133  
   134  	if createHomeRes.Status.Code != rpc.Code_CODE_OK && createHomeRes.Status.Code != rpc.Code_CODE_ALREADY_EXISTS {
   135  		err := status.NewErrorFromCode(createHomeRes.Status.Code, "gateway")
   136  		log.Err(err).Msg("error calling Createhome")
   137  		return &gateway.AuthenticateResponse{
   138  			Status: status.NewInternal(ctx, "error creating user home"),
   139  		}, nil
   140  	}
   141  
   142  	gwRes := &gateway.AuthenticateResponse{
   143  		Status: status.NewOK(ctx),
   144  		User:   res.User,
   145  		Token:  token,
   146  	}
   147  	return gwRes, nil
   148  }
   149  
   150  func (s *svc) WhoAmI(ctx context.Context, req *gateway.WhoAmIRequest) (*gateway.WhoAmIResponse, error) {
   151  	u, _, err := s.tokenmgr.DismantleToken(ctx, req.Token)
   152  	if err != nil {
   153  		err = errors.Wrap(err, "gateway: error getting user from token")
   154  		return &gateway.WhoAmIResponse{
   155  			Status: status.NewUnauthenticated(ctx, err, "error dismantling token"),
   156  		}, nil
   157  	}
   158  
   159  	if sharedconf.SkipUserGroupsInToken() {
   160  		groupsRes, err := s.GetUserGroups(ctx, &userpb.GetUserGroupsRequest{UserId: u.Id})
   161  		if err != nil {
   162  			return nil, err
   163  		}
   164  		u.Groups = groupsRes.Groups
   165  	}
   166  
   167  	res := &gateway.WhoAmIResponse{
   168  		Status: status.NewOK(ctx),
   169  		User:   u,
   170  	}
   171  	return res, nil
   172  }
   173  
   174  func (s *svc) findAuthProvider(ctx context.Context, authType string) (authpb.ProviderAPIClient, error) {
   175  	c, err := pool.GetAuthRegistryServiceClient(s.c.AuthRegistryEndpoint)
   176  	if err != nil {
   177  		err = errors.Wrap(err, "gateway: error getting auth registry client")
   178  		return nil, err
   179  	}
   180  
   181  	res, err := c.GetAuthProviders(ctx, &registry.GetAuthProvidersRequest{
   182  		Type: authType,
   183  	})
   184  
   185  	if err != nil {
   186  		err = errors.Wrap(err, "gateway: error calling GetAuthProvider")
   187  		return nil, err
   188  	}
   189  
   190  	if res.Status.Code == rpc.Code_CODE_OK && res.Providers != nil && len(res.Providers) > 0 {
   191  		// TODO(labkode): check for capabilities here
   192  		c, err := pool.GetAuthProviderServiceClient(res.Providers[0].Address)
   193  		if err != nil {
   194  			err = errors.Wrap(err, "gateway: error getting an auth provider client")
   195  			return nil, err
   196  		}
   197  
   198  		return c, nil
   199  	}
   200  
   201  	if res.Status.Code == rpc.Code_CODE_NOT_FOUND {
   202  		return nil, errtypes.NotFound("gateway: auth provider not found for type:" + authType)
   203  	}
   204  
   205  	return nil, errtypes.InternalError("gateway: error finding an auth provider for type: " + authType)
   206  }