github.com/cs3org/reva/v2@v2.27.7/pkg/auth/manager/machine/machine.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 machine
    20  
    21  import (
    22  	"context"
    23  	"strings"
    24  
    25  	authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
    26  	userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
    27  	rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
    28  	"github.com/cs3org/reva/v2/pkg/auth"
    29  	"github.com/cs3org/reva/v2/pkg/auth/manager/registry"
    30  	"github.com/cs3org/reva/v2/pkg/auth/scope"
    31  	"github.com/cs3org/reva/v2/pkg/errtypes"
    32  	"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
    33  	"github.com/mitchellh/mapstructure"
    34  	"github.com/pkg/errors"
    35  )
    36  
    37  // 'machine' is an authentication method used to impersonate users.
    38  // To impersonate the given user it's only needed an api-key, saved
    39  // in a config file.
    40  
    41  // supported claims
    42  var claims = []string{"mail", "uid", "username", "gid", "userid"}
    43  
    44  type manager struct {
    45  	APIKey      string `mapstructure:"api_key"`
    46  	GatewayAddr string `mapstructure:"gateway_addr"`
    47  }
    48  
    49  func init() {
    50  	registry.Register("machine", New)
    51  }
    52  
    53  // Configure parses the map conf
    54  func (m *manager) Configure(conf map[string]interface{}) error {
    55  	err := mapstructure.Decode(conf, m)
    56  	if err != nil {
    57  		return errors.Wrap(err, "error decoding conf")
    58  	}
    59  	return nil
    60  }
    61  
    62  // New creates a new manager for the 'machine' authentication
    63  func New(conf map[string]interface{}) (auth.Manager, error) {
    64  	m := &manager{}
    65  	err := m.Configure(conf)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	return m, nil
    70  }
    71  
    72  // Authenticate impersonate an user if the provided secret is equal to the api-key
    73  func (m *manager) Authenticate(ctx context.Context, user, secret string) (*userpb.User, map[string]*authpb.Scope, error) {
    74  	if m.APIKey != secret {
    75  		return nil, nil, errtypes.InvalidCredentials("")
    76  	}
    77  
    78  	gtw, err := pool.GetGatewayServiceClient(m.GatewayAddr)
    79  	if err != nil {
    80  		return nil, nil, err
    81  	}
    82  
    83  	// username could be either a normal username or a string <claim>:<value>
    84  	// in the first case the claim is "username"
    85  	claim, value := parseUser(user)
    86  
    87  	userResponse, err := gtw.GetUserByClaim(ctx, &userpb.GetUserByClaimRequest{
    88  		Claim: claim,
    89  		Value: value,
    90  	})
    91  
    92  	switch {
    93  	case err != nil:
    94  		return nil, nil, err
    95  	case userResponse.Status.Code == rpc.Code_CODE_NOT_FOUND:
    96  		return nil, nil, errtypes.NotFound(userResponse.Status.Message)
    97  	case userResponse.Status.Code != rpc.Code_CODE_OK:
    98  		return nil, nil, errtypes.InternalError(userResponse.Status.Message)
    99  	}
   100  
   101  	scope, err := scope.AddOwnerScope(nil)
   102  	if err != nil {
   103  		return nil, nil, err
   104  	}
   105  
   106  	return userResponse.GetUser(), scope, nil
   107  
   108  }
   109  
   110  func contains(lst []string, s string) bool {
   111  	for _, e := range lst {
   112  		if e == s {
   113  			return true
   114  		}
   115  	}
   116  	return false
   117  }
   118  
   119  func parseUser(user string) (string, string) {
   120  	s := strings.SplitN(user, ":", 2)
   121  	if len(s) == 2 && contains(claims, s[0]) {
   122  		return s[0], s[1]
   123  	}
   124  	return "username", user
   125  }