github.com/thanos-io/thanos@v0.32.5/internal/cortex/tenant/resolver.go (about)

     1  // Copyright (c) The Cortex Authors.
     2  // Licensed under the Apache License 2.0.
     3  
     4  package tenant
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"strings"
    10  
    11  	"github.com/weaveworks/common/user"
    12  )
    13  
    14  var defaultResolver Resolver = NewSingleResolver()
    15  
    16  // TenantID returns exactly a single tenant ID from the context. It should be
    17  // used when a certain endpoint should only support exactly a single
    18  // tenant ID. It returns an error user.ErrNoOrgID if there is no tenant ID
    19  // supplied or user.ErrTooManyOrgIDs if there are multiple tenant IDs present.
    20  //
    21  // ignore stutter warning
    22  //
    23  //nolint:golint
    24  func TenantID(ctx context.Context) (string, error) {
    25  	return defaultResolver.TenantID(ctx)
    26  }
    27  
    28  // TenantIDs returns all tenant IDs from the context. It should return
    29  // normalized list of ordered and distinct tenant IDs (as produced by
    30  // NormalizeTenantIDs).
    31  //
    32  // ignore stutter warning
    33  //
    34  //nolint:golint
    35  func TenantIDs(ctx context.Context) ([]string, error) {
    36  	return defaultResolver.TenantIDs(ctx)
    37  }
    38  
    39  type Resolver interface {
    40  	// TenantID returns exactly a single tenant ID from the context. It should be
    41  	// used when a certain endpoint should only support exactly a single
    42  	// tenant ID. It returns an error user.ErrNoOrgID if there is no tenant ID
    43  	// supplied or user.ErrTooManyOrgIDs if there are multiple tenant IDs present.
    44  	TenantID(context.Context) (string, error)
    45  
    46  	// TenantIDs returns all tenant IDs from the context. It should return
    47  	// normalized list of ordered and distinct tenant IDs (as produced by
    48  	// NormalizeTenantIDs).
    49  	TenantIDs(context.Context) ([]string, error)
    50  }
    51  
    52  // NewSingleResolver creates a tenant resolver, which restricts all requests to
    53  // be using a single tenant only. This allows a wider set of characters to be
    54  // used within the tenant ID and should not impose a breaking change.
    55  func NewSingleResolver() *SingleResolver {
    56  	return &SingleResolver{}
    57  }
    58  
    59  type SingleResolver struct {
    60  }
    61  
    62  // containsUnsafePathSegments will return true if the string is a directory
    63  // reference like `.` and `..` or if any path separator character like `/` and
    64  // `\` can be found.
    65  func containsUnsafePathSegments(id string) bool {
    66  	// handle the relative reference to current and parent path.
    67  	if id == "." || id == ".." {
    68  		return true
    69  	}
    70  
    71  	return strings.ContainsAny(id, "\\/")
    72  }
    73  
    74  var errInvalidTenantID = errors.New("invalid tenant ID")
    75  
    76  func (t *SingleResolver) TenantID(ctx context.Context) (string, error) {
    77  	//lint:ignore faillint wrapper around upstream method
    78  	id, err := user.ExtractOrgID(ctx)
    79  	if err != nil {
    80  		return "", err
    81  	}
    82  
    83  	if containsUnsafePathSegments(id) {
    84  		return "", errInvalidTenantID
    85  	}
    86  
    87  	return id, nil
    88  }
    89  
    90  func (t *SingleResolver) TenantIDs(ctx context.Context) ([]string, error) {
    91  	orgID, err := t.TenantID(ctx)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  	return []string{orgID}, err
    96  }