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 }