github.com/craicoverflow/tyk@v2.9.6-rc3+incompatible/gateway/mw_auth_key.go (about)

     1  package gateway
     2  
     3  import (
     4  	"errors"
     5  	"net/http"
     6  	"strings"
     7  
     8  	"github.com/TykTechnologies/tyk/certs"
     9  
    10  	"github.com/TykTechnologies/tyk/user"
    11  
    12  	"github.com/TykTechnologies/tyk/apidef"
    13  	"github.com/TykTechnologies/tyk/config"
    14  	"github.com/TykTechnologies/tyk/request"
    15  	"github.com/TykTechnologies/tyk/signature_validator"
    16  )
    17  
    18  const (
    19  	defaultSignatureErrorCode    = http.StatusUnauthorized
    20  	defaultSignatureErrorMessage = "Request signature verification failed"
    21  )
    22  
    23  const (
    24  	ErrAuthAuthorizationFieldMissing = "auth.auth_field_missing"
    25  	ErrAuthKeyNotFound               = "auth.key_not_found"
    26  )
    27  
    28  func init() {
    29  	TykErrors[ErrAuthAuthorizationFieldMissing] = config.TykError{
    30  		Message: "Authorization field missing",
    31  		Code:    http.StatusUnauthorized,
    32  	}
    33  
    34  	TykErrors[ErrAuthKeyNotFound] = config.TykError{
    35  		Message: "Access to this API has been disallowed",
    36  		Code:    http.StatusForbidden,
    37  	}
    38  }
    39  
    40  // KeyExists will check if the key being used to access the API is in the request data,
    41  // and then if the key is in the storage engine
    42  type AuthKey struct {
    43  	BaseMiddleware
    44  }
    45  
    46  func (k *AuthKey) Name() string {
    47  	return "AuthKey"
    48  }
    49  
    50  func (k *AuthKey) setContextVars(r *http.Request, token string) {
    51  	// Flatten claims and add to context
    52  	if !k.Spec.EnableContextVars {
    53  		return
    54  	}
    55  	if cnt := ctxGetData(r); cnt != nil {
    56  		// Key data
    57  		cnt["token"] = token
    58  		ctxSetData(r, cnt)
    59  	}
    60  }
    61  
    62  // getAuthType overrides BaseMiddleware.getAuthType.
    63  func (k *AuthKey) getAuthType() string {
    64  	return authTokenType
    65  }
    66  
    67  func (k *AuthKey) ProcessRequest(w http.ResponseWriter, r *http.Request, _ interface{}) (error, int) {
    68  	if ctxGetRequestStatus(r) == StatusOkAndIgnore {
    69  		return nil, http.StatusOK
    70  	}
    71  
    72  	key, authConfig := k.getAuthToken(k.getAuthType(), r)
    73  
    74  	keyExists := false
    75  	var session user.SessionState
    76  	if key != "" {
    77  		key = stripBearer(key)
    78  	} else if authConfig.UseCertificate && key == "" && r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
    79  		log.Debug("Trying to find key by client certificate")
    80  
    81  		key = certs.HexSHA256(r.TLS.PeerCertificates[0].Raw)
    82  	} else {
    83  		k.Logger().Info("Attempted access with malformed header, no auth header found.")
    84  
    85  		return errorAndStatusCode(ErrAuthAuthorizationFieldMissing)
    86  	}
    87  
    88  	session, keyExists = k.CheckSessionAndIdentityForValidKey(&key, r)
    89  	if !keyExists {
    90  		k.Logger().WithField("key", obfuscateKey(key)).Info("Attempted access with non-existent key.")
    91  
    92  		// Fire Authfailed Event
    93  		AuthFailed(k, r, key)
    94  
    95  		// Report in health check
    96  		reportHealthValue(k.Spec, KeyFailure, "1")
    97  
    98  		return errorAndStatusCode(ErrAuthKeyNotFound)
    99  	}
   100  
   101  	// Set session state on context, we will need it later
   102  	switch k.Spec.BaseIdentityProvidedBy {
   103  	case apidef.AuthToken, apidef.UnsetAuth:
   104  		ctxSetSession(r, &session, key, false)
   105  		k.setContextVars(r, key)
   106  	}
   107  
   108  	return k.validateSignature(r, key)
   109  }
   110  
   111  func (k *AuthKey) validateSignature(r *http.Request, key string) (error, int) {
   112  	config := k.Spec.Auth
   113  	logger := k.Logger().WithField("key", obfuscateKey(key))
   114  
   115  	if !config.ValidateSignature {
   116  		return nil, http.StatusOK
   117  	}
   118  
   119  	errorCode := defaultSignatureErrorCode
   120  	if config.Signature.ErrorCode != 0 {
   121  		errorCode = config.Signature.ErrorCode
   122  	}
   123  
   124  	errorMessage := defaultSignatureErrorMessage
   125  	if config.Signature.ErrorMessage != "" {
   126  		errorMessage = config.Signature.ErrorMessage
   127  	}
   128  
   129  	validator := signature_validator.SignatureValidator{}
   130  	if err := validator.Init(config.Signature.Algorithm); err != nil {
   131  		logger.WithError(err).Info("Invalid signature verification algorithm")
   132  		return errors.New("internal server error"), http.StatusInternalServerError
   133  	}
   134  
   135  	signature := r.Header.Get(config.Signature.Header)
   136  	if signature == "" {
   137  		logger.Info("Request signature header not found or empty")
   138  		return errors.New(errorMessage), errorCode
   139  	}
   140  
   141  	secret := replaceTykVariables(r, config.Signature.Secret, false)
   142  
   143  	if secret == "" {
   144  		logger.Info("Request signature secret not found or empty")
   145  		return errors.New(errorMessage), errorCode
   146  	}
   147  
   148  	if err := validator.Validate(signature, key, secret, config.Signature.AllowedClockSkew); err != nil {
   149  		logger.WithError(err).Info("Request signature validation failed")
   150  		return errors.New(errorMessage), errorCode
   151  	}
   152  
   153  	return nil, http.StatusOK
   154  }
   155  
   156  func stripBearer(token string) string {
   157  	if len(token) > 6 && strings.ToUpper(token[0:7]) == "BEARER " {
   158  		return token[7:]
   159  	}
   160  	return token
   161  }
   162  
   163  func AuthFailed(m TykMiddleware, r *http.Request, token string) {
   164  	m.Base().FireEvent(EventAuthFailure, EventKeyFailureMeta{
   165  		EventMetaDefault: EventMetaDefault{Message: "Auth Failure", OriginatingRequest: EncodeRequestToEvent(r)},
   166  		Path:             r.URL.Path,
   167  		Origin:           request.RealIP(r),
   168  		Key:              token,
   169  	})
   170  }