github.com/Tyktechnologies/tyk@v2.9.5+incompatible/gateway/middleware.go (about)

     1  package gateway
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"strconv"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/TykTechnologies/tyk/headers"
    14  
    15  	"github.com/gocraft/health"
    16  	"github.com/justinas/alice"
    17  	newrelic "github.com/newrelic/go-agent"
    18  	"github.com/paulbellamy/ratecounter"
    19  	"github.com/pmylund/go-cache"
    20  	"github.com/sirupsen/logrus"
    21  
    22  	"github.com/TykTechnologies/tyk/apidef"
    23  	"github.com/TykTechnologies/tyk/config"
    24  	"github.com/TykTechnologies/tyk/request"
    25  	"github.com/TykTechnologies/tyk/storage"
    26  	"github.com/TykTechnologies/tyk/trace"
    27  	"github.com/TykTechnologies/tyk/user"
    28  )
    29  
    30  const mwStatusRespond = 666
    31  
    32  const authTokenType = "authToken"
    33  const jwtType = "jwt"
    34  const hmacType = "hmac"
    35  const basicType = "basic"
    36  const coprocessType = "coprocess"
    37  const oauthType = "oauth"
    38  const oidcType = "oidc"
    39  
    40  var GlobalRate = ratecounter.NewRateCounter(1 * time.Second)
    41  
    42  type TykMiddleware interface {
    43  	Init()
    44  	Base() *BaseMiddleware
    45  	SetName(string)
    46  	SetRequestLogger(*http.Request)
    47  	Logger() *logrus.Entry
    48  	Config() (interface{}, error)
    49  	ProcessRequest(w http.ResponseWriter, r *http.Request, conf interface{}) (error, int) // Handles request
    50  	EnabledForSpec() bool
    51  	Name() string
    52  }
    53  
    54  type TraceMiddleware struct {
    55  	TykMiddleware
    56  }
    57  
    58  func (tr TraceMiddleware) ProcessRequest(w http.ResponseWriter, r *http.Request, conf interface{}) (error, int) {
    59  	if trace.IsEnabled() {
    60  		span, ctx := trace.Span(r.Context(),
    61  			tr.Name(),
    62  		)
    63  		defer span.Finish()
    64  		setContext(r, ctx)
    65  		return tr.TykMiddleware.ProcessRequest(w, r, conf)
    66  	}
    67  	return tr.TykMiddleware.ProcessRequest(w, r, conf)
    68  }
    69  
    70  func createDynamicMiddleware(name string, isPre, useSession bool, baseMid BaseMiddleware) func(http.Handler) http.Handler {
    71  	dMiddleware := &DynamicMiddleware{
    72  		BaseMiddleware:      baseMid,
    73  		MiddlewareClassName: name,
    74  		Pre:                 isPre,
    75  		UseSession:          useSession,
    76  	}
    77  
    78  	return createMiddleware(dMiddleware)
    79  }
    80  
    81  // Generic middleware caller to make extension easier
    82  func createMiddleware(actualMW TykMiddleware) func(http.Handler) http.Handler {
    83  	mw := &TraceMiddleware{
    84  		TykMiddleware: actualMW,
    85  	}
    86  	// construct a new instance
    87  	mw.Init()
    88  	mw.SetName(mw.Name())
    89  	mw.Logger().Debug("Init")
    90  
    91  	// Pull the configuration
    92  	mwConf, err := mw.Config()
    93  	if err != nil {
    94  		mw.Logger().Fatal("[Middleware] Configuration load failed")
    95  	}
    96  
    97  	return func(h http.Handler) http.Handler {
    98  		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    99  			mw.SetRequestLogger(r)
   100  
   101  			if config.Global().NewRelic.AppName != "" {
   102  				if txn, ok := w.(newrelic.Transaction); ok {
   103  					defer newrelic.StartSegment(txn, mw.Name()).End()
   104  				}
   105  			}
   106  
   107  			job := instrument.NewJob("MiddlewareCall")
   108  			meta := health.Kvs{}
   109  			eventName := mw.Name() + "." + "executed"
   110  
   111  			if instrumentationEnabled {
   112  				meta = health.Kvs{
   113  					"from_ip":  request.RealIP(r),
   114  					"method":   r.Method,
   115  					"endpoint": r.URL.Path,
   116  					"raw_url":  r.URL.String(),
   117  					"size":     strconv.Itoa(int(r.ContentLength)),
   118  					"mw_name":  mw.Name(),
   119  				}
   120  				job.EventKv("executed", meta)
   121  				job.EventKv(eventName, meta)
   122  			}
   123  
   124  			startTime := time.Now()
   125  			mw.Logger().WithField("ts", startTime.UnixNano()).Debug("Started")
   126  
   127  			if mw.Base().Spec.CORS.OptionsPassthrough && r.Method == "OPTIONS" {
   128  				h.ServeHTTP(w, r)
   129  				return
   130  			}
   131  			err, errCode := mw.ProcessRequest(w, r, mwConf)
   132  			if err != nil {
   133  				// GoPluginMiddleware are expected to send response in case of error
   134  				// but we still want to record error
   135  				_, isGoPlugin := actualMW.(*GoPluginMiddleware)
   136  
   137  				handler := ErrorHandler{*mw.Base()}
   138  				handler.HandleError(w, r, err.Error(), errCode, !isGoPlugin)
   139  
   140  				meta["error"] = err.Error()
   141  
   142  				finishTime := time.Since(startTime)
   143  
   144  				if instrumentationEnabled {
   145  					job.TimingKv("exec_time", finishTime.Nanoseconds(), meta)
   146  					job.TimingKv(eventName+".exec_time", finishTime.Nanoseconds(), meta)
   147  				}
   148  
   149  				mw.Logger().WithError(err).WithField("code", errCode).WithField("ns", finishTime.Nanoseconds()).Debug("Finished")
   150  				return
   151  			}
   152  
   153  			finishTime := time.Since(startTime)
   154  
   155  			if instrumentationEnabled {
   156  				job.TimingKv("exec_time", finishTime.Nanoseconds(), meta)
   157  				job.TimingKv(eventName+".exec_time", finishTime.Nanoseconds(), meta)
   158  			}
   159  
   160  			mw.Logger().WithField("code", errCode).WithField("ns", finishTime.Nanoseconds()).Debug("Finished")
   161  
   162  			// Special code, bypasses all other execution
   163  			if errCode != mwStatusRespond {
   164  				// No error, carry on...
   165  				meta["bypass"] = "1"
   166  				h.ServeHTTP(w, r)
   167  			} else {
   168  				mw.Base().UpdateRequestSession(r)
   169  			}
   170  		})
   171  	}
   172  }
   173  
   174  func mwAppendEnabled(chain *[]alice.Constructor, mw TykMiddleware) bool {
   175  	if mw.EnabledForSpec() {
   176  		*chain = append(*chain, createMiddleware(mw))
   177  		return true
   178  	}
   179  	return false
   180  }
   181  
   182  func mwList(mws ...TykMiddleware) []alice.Constructor {
   183  	var list []alice.Constructor
   184  	for _, mw := range mws {
   185  		mwAppendEnabled(&list, mw)
   186  	}
   187  	return list
   188  }
   189  
   190  // BaseMiddleware wraps up the ApiSpec and Proxy objects to be included in a
   191  // middleware handler, this can probably be handled better.
   192  type BaseMiddleware struct {
   193  	Spec   *APISpec
   194  	Proxy  ReturningHttpHandler
   195  	logger *logrus.Entry
   196  }
   197  
   198  func (t BaseMiddleware) Base() *BaseMiddleware { return &t }
   199  
   200  func (t BaseMiddleware) Logger() (logger *logrus.Entry) {
   201  	if t.logger == nil {
   202  		t.logger = logrus.NewEntry(log)
   203  	}
   204  
   205  	return t.logger
   206  }
   207  
   208  func (t *BaseMiddleware) SetName(name string) {
   209  	t.logger = t.Logger().WithField("mw", name)
   210  }
   211  
   212  func (t *BaseMiddleware) SetRequestLogger(r *http.Request) {
   213  	t.logger = getLogEntryForRequest(t.Logger(), r, ctxGetAuthToken(r), nil)
   214  }
   215  
   216  func (t BaseMiddleware) Init() {}
   217  func (t BaseMiddleware) EnabledForSpec() bool {
   218  	return true
   219  }
   220  func (t BaseMiddleware) Config() (interface{}, error) {
   221  	return nil, nil
   222  }
   223  
   224  func (t BaseMiddleware) OrgSession(key string) (user.SessionState, bool) {
   225  	// Try and get the session from the session store
   226  	session, found := t.Spec.OrgSessionManager.SessionDetail(key, false)
   227  	if found && t.Spec.GlobalConfig.EnforceOrgDataAge {
   228  		// If exists, assume it has been authorized and pass on
   229  		// We cache org expiry data
   230  		t.Logger().Debug("Setting data expiry: ", session.OrgID)
   231  		go t.SetOrgExpiry(session.OrgID, session.DataExpires)
   232  	}
   233  
   234  	session.SetKeyHash(storage.HashKey(key))
   235  	return session, found
   236  }
   237  
   238  func (t BaseMiddleware) SetOrgExpiry(orgid string, expiry int64) {
   239  	ExpiryCache.Set(orgid, expiry, cache.DefaultExpiration)
   240  }
   241  
   242  func (t BaseMiddleware) OrgSessionExpiry(orgid string) int64 {
   243  	t.Logger().Debug("Checking: ", orgid)
   244  	cachedVal, found := ExpiryCache.Get(orgid)
   245  	if !found {
   246  		// Cache failed attempt
   247  		t.SetOrgExpiry(orgid, 604800)
   248  		go t.OrgSession(orgid)
   249  		t.Logger().Debug("no cached entry found, returning 7 days")
   250  		return 604800
   251  	}
   252  
   253  	return cachedVal.(int64)
   254  }
   255  
   256  func (t BaseMiddleware) UpdateRequestSession(r *http.Request) bool {
   257  	session := ctxGetSession(r)
   258  	token := ctxGetAuthToken(r)
   259  
   260  	if session == nil || token == "" {
   261  		return false
   262  	}
   263  
   264  	if !ctxSessionUpdateScheduled(r) {
   265  		return false
   266  	}
   267  
   268  	lifetime := session.Lifetime(t.Spec.SessionLifetime)
   269  	if err := t.Spec.SessionManager.UpdateSession(token, session, lifetime, false); err != nil {
   270  		t.Logger().WithError(err).Error("Can't update session")
   271  		return false
   272  	}
   273  
   274  	// Set context state back
   275  	// Useful for benchmarks when request object stays same
   276  	ctxDisableSessionUpdate(r)
   277  
   278  	if !t.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState {
   279  		SessionCache.Set(session.GetKeyHash(), *session, cache.DefaultExpiration)
   280  	}
   281  
   282  	return true
   283  }
   284  
   285  // ApplyPolicies will check if any policies are loaded. If any are, it
   286  // will overwrite the session state to use the policy values.
   287  func (t BaseMiddleware) ApplyPolicies(session *user.SessionState) error {
   288  	rights := make(map[string]user.AccessDefinition)
   289  	tags := make(map[string]bool)
   290  	if session.GetMetaData() == nil {
   291  		session.SetMetaData(make(map[string]interface{}))
   292  	}
   293  
   294  	didQuota, didRateLimit, didACL := make(map[string]bool), make(map[string]bool), make(map[string]bool)
   295  	policies := session.GetPolicyIDs()
   296  
   297  	for _, polID := range policies {
   298  		policiesMu.RLock()
   299  		policy, ok := policiesByID[polID]
   300  		policiesMu.RUnlock()
   301  		if !ok {
   302  			err := fmt.Errorf("policy not found: %q", polID)
   303  			t.Logger().Error(err)
   304  			return err
   305  		}
   306  		// Check ownership, policy org owner must be the same as API,
   307  		// otherwise youcould overwrite a session key with a policy from a different org!
   308  		if t.Spec != nil && policy.OrgID != t.Spec.OrgID {
   309  			err := fmt.Errorf("attempting to apply policy from different organisation to key, skipping")
   310  			t.Logger().Error(err)
   311  			return err
   312  		}
   313  
   314  		if policy.Partitions.PerAPI &&
   315  			(policy.Partitions.Quota || policy.Partitions.RateLimit || policy.Partitions.Acl) {
   316  			err := fmt.Errorf("cannot apply policy %s which has per_api and any of partitions set", policy.ID)
   317  			log.Error(err)
   318  			return err
   319  		}
   320  
   321  		if policy.Partitions.PerAPI {
   322  			for apiID, accessRights := range policy.AccessRights {
   323  				// new logic when you can specify quota or rate in more than one policy but for different APIs
   324  				if didQuota[apiID] || didRateLimit[apiID] || didACL[apiID] { // no other partitions allowed
   325  					err := fmt.Errorf("cannot apply multiple policies when some have per_api set and some are partitioned")
   326  					log.Error(err)
   327  					return err
   328  				}
   329  
   330  				// check if we already have limit on API level specified when policy was created
   331  				if accessRights.Limit == nil || *accessRights.Limit == (user.APILimit{}) {
   332  					// limit was not specified on API level so we will populate it from policy
   333  					accessRights.Limit = &user.APILimit{
   334  						QuotaMax:           policy.QuotaMax,
   335  						QuotaRenewalRate:   policy.QuotaRenewalRate,
   336  						Rate:               policy.Rate,
   337  						Per:                policy.Per,
   338  						ThrottleInterval:   policy.ThrottleInterval,
   339  						ThrottleRetryLimit: policy.ThrottleRetryLimit,
   340  					}
   341  				}
   342  
   343  				// respect current quota renews (on API limit level)
   344  				if r, ok := session.GetAccessRightByAPIID(apiID); ok && r.Limit != nil {
   345  					accessRights.Limit.QuotaRenews = r.Limit.QuotaRenews
   346  				}
   347  
   348  				accessRights.AllowanceScope = apiID
   349  				accessRights.Limit.SetBy = apiID
   350  
   351  				// overwrite session access right for this API
   352  				rights[apiID] = accessRights
   353  
   354  				// identify that limit for that API is set (to allow set it only once)
   355  				didACL[apiID] = true
   356  				didQuota[apiID] = true
   357  				didRateLimit[apiID] = true
   358  			}
   359  		} else {
   360  			usePartitions := policy.Partitions.Quota || policy.Partitions.RateLimit || policy.Partitions.Acl
   361  
   362  			for k, v := range policy.AccessRights {
   363  				ar := &v
   364  
   365  				if v.Limit == nil {
   366  					v.Limit = &user.APILimit{}
   367  				}
   368  
   369  				if !usePartitions || policy.Partitions.Acl {
   370  					didACL[k] = true
   371  
   372  					// Merge ACLs for the same API
   373  					if r, ok := rights[k]; ok {
   374  						r.Versions = appendIfMissing(rights[k].Versions, v.Versions...)
   375  
   376  						for _, u := range v.AllowedURLs {
   377  							found := false
   378  							for ai, au := range r.AllowedURLs {
   379  								if u.URL == au.URL {
   380  									found = true
   381  									r.AllowedURLs[ai].Methods = append(au.Methods, u.Methods...)
   382  								}
   383  							}
   384  
   385  							if !found {
   386  								r.AllowedURLs = append(r.AllowedURLs, v.AllowedURLs...)
   387  							}
   388  						}
   389  
   390  						ar = &r
   391  					}
   392  
   393  					ar.Limit.SetBy = policy.ID
   394  				}
   395  
   396  				if !usePartitions || policy.Partitions.Quota {
   397  					didQuota[k] = true
   398  
   399  					// -1 is special "unlimited" case
   400  					if ar.Limit.QuotaMax != -1 && policy.QuotaMax > ar.Limit.QuotaMax {
   401  						ar.Limit.QuotaMax = policy.QuotaMax
   402  					}
   403  
   404  					if policy.QuotaRenewalRate > ar.Limit.QuotaRenewalRate {
   405  						ar.Limit.QuotaRenewalRate = policy.QuotaRenewalRate
   406  						session.QuotaRenewalRate = policy.QuotaRenewalRate
   407  					}
   408  				}
   409  
   410  				if !usePartitions || policy.Partitions.RateLimit {
   411  					didRateLimit[k] = true
   412  
   413  					if ar.Limit.Rate != -1 && policy.Rate > ar.Limit.Rate {
   414  						ar.Limit.Rate = policy.Rate
   415  						session.Rate = policy.Rate
   416  					}
   417  
   418  					if policy.Per > ar.Limit.Per {
   419  						ar.Limit.Per = policy.Per
   420  						session.Per = policy.Per
   421  					}
   422  
   423  					if policy.ThrottleInterval > ar.Limit.ThrottleInterval {
   424  						ar.Limit.ThrottleInterval = policy.ThrottleInterval
   425  					}
   426  
   427  					if policy.ThrottleRetryLimit > ar.Limit.ThrottleRetryLimit {
   428  						ar.Limit.ThrottleRetryLimit = policy.ThrottleRetryLimit
   429  					}
   430  				}
   431  
   432  				// Respect existing QuotaRenews
   433  				if r, ok := session.GetAccessRightByAPIID(k); ok && r.Limit != nil {
   434  					ar.Limit.QuotaRenews = r.Limit.QuotaRenews
   435  				}
   436  
   437  				rights[k] = *ar
   438  			}
   439  
   440  			// Master policy case
   441  			if len(policy.AccessRights) == 0 {
   442  				if !usePartitions || policy.Partitions.RateLimit {
   443  					session.Rate = policy.Rate
   444  					session.Per = policy.Per
   445  					session.ThrottleInterval = policy.ThrottleInterval
   446  					session.ThrottleRetryLimit = policy.ThrottleRetryLimit
   447  				}
   448  
   449  				if !usePartitions || policy.Partitions.Quota {
   450  					session.QuotaMax = policy.QuotaMax
   451  					session.QuotaRenewalRate = policy.QuotaRenewalRate
   452  				}
   453  			}
   454  
   455  			if !session.HMACEnabled {
   456  				session.HMACEnabled = policy.HMACEnabled
   457  			}
   458  
   459  			if !session.EnableHTTPSignatureValidation {
   460  				session.EnableHTTPSignatureValidation = policy.EnableHTTPSignatureValidation
   461  			}
   462  		}
   463  
   464  		session.IsInactive = session.IsInactive || policy.IsInactive
   465  
   466  		for _, tag := range policy.Tags {
   467  			tags[tag] = true
   468  		}
   469  
   470  		for k, v := range policy.MetaData {
   471  			session.SetMetaDataKey(k, v)
   472  		}
   473  
   474  		if policy.LastUpdated > session.LastUpdated {
   475  			session.LastUpdated = policy.LastUpdated
   476  		}
   477  	}
   478  
   479  	for _, tag := range session.Tags {
   480  		tags[tag] = true
   481  	}
   482  
   483  	// set tags
   484  	session.Tags = []string{}
   485  	for tag := range tags {
   486  		session.Tags = append(session.Tags, tag)
   487  	}
   488  
   489  	distinctACL := map[string]bool{}
   490  	for _, v := range rights {
   491  		if v.Limit.SetBy != "" {
   492  			distinctACL[v.Limit.SetBy] = true
   493  		}
   494  	}
   495  
   496  	// If some APIs had only ACL partitions, inherit rest from session level
   497  	for k, v := range rights {
   498  		if !didRateLimit[k] {
   499  			v.Limit.Rate = session.Rate
   500  			v.Limit.Per = session.Per
   501  			v.Limit.ThrottleInterval = session.ThrottleInterval
   502  			v.Limit.ThrottleRetryLimit = session.ThrottleRetryLimit
   503  		}
   504  
   505  		if !didQuota[k] {
   506  			v.Limit.QuotaMax = session.QuotaMax
   507  			v.Limit.QuotaRenewalRate = session.QuotaRenewalRate
   508  			v.Limit.QuotaRenews = session.QuotaRenews
   509  		}
   510  
   511  		// If multime ACL
   512  		if len(distinctACL) > 1 {
   513  			if v.AllowanceScope == "" && v.Limit.SetBy != "" {
   514  				v.AllowanceScope = v.Limit.SetBy
   515  			}
   516  		}
   517  
   518  		v.Limit.SetBy = ""
   519  
   520  		rights[k] = v
   521  	}
   522  
   523  	// If we have policies defining rules for one single API, update session root vars (legacy)
   524  	if len(didQuota) == 1 && len(didRateLimit) == 1 {
   525  		for _, v := range rights {
   526  			if len(didRateLimit) == 1 {
   527  				session.Rate = v.Limit.Rate
   528  				session.Per = v.Limit.Per
   529  			}
   530  
   531  			if len(didQuota) == 1 {
   532  				session.QuotaMax = v.Limit.QuotaMax
   533  				session.QuotaRenews = v.Limit.QuotaRenews
   534  				session.QuotaRenewalRate = v.Limit.QuotaRenewalRate
   535  			}
   536  		}
   537  	}
   538  
   539  	// Override session ACL if at least one policy define it
   540  	if len(didACL) > 0 {
   541  		session.SetAccessRights(rights)
   542  	}
   543  
   544  	return nil
   545  }
   546  
   547  // CheckSessionAndIdentityForValidKey will check first the Session store for a valid key, if not found, it will try
   548  // the Auth Handler, if not found it will fail
   549  func (t BaseMiddleware) CheckSessionAndIdentityForValidKey(originalKey *string, r *http.Request) (user.SessionState, bool) {
   550  	key := *originalKey
   551  	minLength := t.Spec.GlobalConfig.MinTokenLength
   552  	if minLength == 0 {
   553  		// See https://github.com/TykTechnologies/tyk/issues/1681
   554  		minLength = 3
   555  	}
   556  
   557  	if len(key) <= minLength {
   558  		return user.SessionState{IsInactive: true, Mutex: &sync.RWMutex{}}, false
   559  	}
   560  
   561  	// Try and get the session from the session store
   562  	t.Logger().Debug("Querying local cache")
   563  	keyHash := key
   564  	cacheKey := key
   565  	if t.Spec.GlobalConfig.HashKeys {
   566  		keyHash = storage.HashStr(key)
   567  		cacheKey = storage.HashStr(key, storage.HashMurmur64) // always hash cache keys with murmur64 to prevent collisions
   568  	}
   569  
   570  	// Check in-memory cache
   571  	if !t.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState {
   572  		cachedVal, found := SessionCache.Get(cacheKey)
   573  		if found {
   574  			t.Logger().Debug("--> Key found in local cache")
   575  			session := cachedVal.(user.SessionState)
   576  			if err := t.ApplyPolicies(&session); err != nil {
   577  				t.Logger().Error(err)
   578  				return session, false
   579  			}
   580  			return session, true
   581  		}
   582  	}
   583  
   584  	// Check session store
   585  	t.Logger().Debug("Querying keystore")
   586  	session, found := t.Spec.SessionManager.SessionDetail(key, false)
   587  	if found {
   588  		session.SetKeyHash(keyHash)
   589  		// If exists, assume it has been authorized and pass on
   590  		// cache it
   591  		if !t.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState {
   592  			go SessionCache.Set(cacheKey, session, cache.DefaultExpiration)
   593  		}
   594  
   595  		// Check for a policy, if there is a policy, pull it and overwrite the session values
   596  		if err := t.ApplyPolicies(&session); err != nil {
   597  			t.Logger().Error(err)
   598  			return session, false
   599  		}
   600  		t.Logger().Debug("Got key")
   601  		return session, true
   602  	}
   603  
   604  	t.Logger().Debug("Querying authstore")
   605  	// 2. If not there, get it from the AuthorizationHandler
   606  	session, found = t.Spec.AuthManager.SessionDetail(key, false)
   607  	if found {
   608  		// update value of originalKey, as for custom-keys it might get updated (the key is generated again using alias)
   609  		*originalKey = key
   610  
   611  		session.SetKeyHash(keyHash)
   612  		// If not in Session, and got it from AuthHandler, create a session with a new TTL
   613  		t.Logger().Info("Recreating session for key: ", obfuscateKey(key))
   614  
   615  		// cache it
   616  		if !t.Spec.GlobalConfig.LocalSessionCache.DisableCacheSessionState {
   617  			go SessionCache.Set(cacheKey, session, cache.DefaultExpiration)
   618  		}
   619  
   620  		// Check for a policy, if there is a policy, pull it and overwrite the session values
   621  		if err := t.ApplyPolicies(&session); err != nil {
   622  			t.Logger().Error(err)
   623  			return session, false
   624  		}
   625  
   626  		t.Logger().Debug("Lifetime is: ", session.Lifetime(t.Spec.SessionLifetime))
   627  		ctxScheduleSessionUpdate(r)
   628  	}
   629  
   630  	return session, found
   631  }
   632  
   633  // FireEvent is added to the BaseMiddleware object so it is available across the entire stack
   634  func (t BaseMiddleware) FireEvent(name apidef.TykEvent, meta interface{}) {
   635  	fireEvent(name, meta, t.Spec.EventPaths)
   636  }
   637  
   638  func (b BaseMiddleware) getAuthType() string {
   639  	return ""
   640  }
   641  
   642  func (b BaseMiddleware) getAuthToken(authType string, r *http.Request) (string, apidef.AuthConfig) {
   643  	config, ok := b.Base().Spec.AuthConfigs[authType]
   644  	// Auth is deprecated. To maintain backward compatibility authToken and jwt cases are added.
   645  	if !ok && (authType == authTokenType || authType == jwtType) {
   646  		config = b.Base().Spec.Auth
   647  	}
   648  
   649  	if config.AuthHeaderName == "" {
   650  		config.AuthHeaderName = headers.Authorization
   651  	}
   652  
   653  	key := r.Header.Get(config.AuthHeaderName)
   654  
   655  	paramName := config.ParamName
   656  	if config.UseParam || paramName != "" {
   657  		if paramName == "" {
   658  			paramName = config.AuthHeaderName
   659  		}
   660  
   661  		paramValue := r.URL.Query().Get(paramName)
   662  
   663  		// Only use the paramValue if it has an actual value
   664  		if paramValue != "" {
   665  			key = paramValue
   666  		}
   667  	}
   668  
   669  	cookieName := config.CookieName
   670  	if config.UseCookie || cookieName != "" {
   671  		if cookieName == "" {
   672  			cookieName = config.AuthHeaderName
   673  		}
   674  
   675  		authCookie, err := r.Cookie(cookieName)
   676  		cookieValue := ""
   677  		if err == nil {
   678  			cookieValue = authCookie.Value
   679  		}
   680  
   681  		if cookieValue != "" {
   682  			key = cookieValue
   683  		}
   684  	}
   685  
   686  	return key, config
   687  }
   688  
   689  type TykResponseHandler interface {
   690  	Init(interface{}, *APISpec) error
   691  	Name() string
   692  	HandleResponse(http.ResponseWriter, *http.Response, *http.Request, *user.SessionState) error
   693  }
   694  
   695  func responseProcessorByName(name string) TykResponseHandler {
   696  	switch name {
   697  	case "header_injector":
   698  		return &HeaderInjector{}
   699  	case "response_body_transform":
   700  		return &ResponseTransformMiddleware{}
   701  	case "response_body_transform_jq":
   702  		return &ResponseTransformJQMiddleware{}
   703  	case "header_transform":
   704  		return &HeaderTransform{}
   705  	}
   706  	return nil
   707  }
   708  
   709  func handleResponseChain(chain []TykResponseHandler, rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState) error {
   710  	traceIsEnabled := trace.IsEnabled()
   711  	for _, rh := range chain {
   712  		if err := handleResponse(rh, rw, res, req, ses, traceIsEnabled); err != nil {
   713  			return err
   714  		}
   715  	}
   716  	return nil
   717  }
   718  
   719  func handleResponse(rh TykResponseHandler, rw http.ResponseWriter, res *http.Response, req *http.Request, ses *user.SessionState, shouldTrace bool) error {
   720  	if shouldTrace {
   721  		span, ctx := trace.Span(req.Context(), rh.Name())
   722  		defer span.Finish()
   723  		req = req.WithContext(ctx)
   724  	}
   725  	return rh.HandleResponse(rw, res, req, ses)
   726  }
   727  
   728  func parseForm(r *http.Request) {
   729  	// https://golang.org/pkg/net/http/#Request.ParseForm
   730  	// ParseForm drains the request body for a request with Content-Type of
   731  	// application/x-www-form-urlencoded
   732  	if r.Header.Get("Content-Type") == "application/x-www-form-urlencoded" && r.Form == nil {
   733  		var b bytes.Buffer
   734  		r.Body = ioutil.NopCloser(io.TeeReader(r.Body, &b))
   735  
   736  		r.ParseForm()
   737  
   738  		r.Body = ioutil.NopCloser(&b)
   739  		return
   740  	}
   741  
   742  	r.ParseForm()
   743  }