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

     1  package gateway
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"strings"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/TykTechnologies/tyk/config"
    11  	"github.com/TykTechnologies/tyk/storage"
    12  	"github.com/TykTechnologies/tyk/user"
    13  	uuid "github.com/satori/go.uuid"
    14  	"github.com/sirupsen/logrus"
    15  )
    16  
    17  // SessionHandler handles all update/create/access session functions and deals exclusively with
    18  // user.SessionState objects, not identity
    19  type SessionHandler interface {
    20  	Init(store storage.Handler)
    21  	Store() storage.Handler
    22  	UpdateSession(keyName string, session *user.SessionState, resetTTLTo int64, hashed bool) error
    23  	RemoveSession(keyName string, hashed bool) bool
    24  	SessionDetail(keyName string, hashed bool) (user.SessionState, bool)
    25  	KeyExpired(newSession *user.SessionState) bool
    26  	Sessions(filter string) []string
    27  	ResetQuota(string, *user.SessionState, bool)
    28  	Stop()
    29  }
    30  
    31  type DefaultSessionManager struct {
    32  	store storage.Handler
    33  	orgID string
    34  }
    35  
    36  func (b *DefaultSessionManager) Init(store storage.Handler) {
    37  	b.store = store
    38  	b.store.Connect()
    39  }
    40  
    41  // KeyExpired checks if a key has expired, if the value of user.SessionState.Expires is 0, it will be ignored
    42  func (b *DefaultSessionManager) KeyExpired(newSession *user.SessionState) bool {
    43  	if newSession.Expires >= 1 {
    44  		return time.Now().After(time.Unix(newSession.Expires, 0))
    45  	}
    46  	return false
    47  }
    48  
    49  func (b *DefaultSessionManager) Store() storage.Handler {
    50  	return b.store
    51  }
    52  
    53  func (b *DefaultSessionManager) ResetQuota(keyName string, session *user.SessionState, isHashed bool) {
    54  	origKeyName := keyName
    55  	if !isHashed {
    56  		keyName = storage.HashKey(keyName)
    57  	}
    58  
    59  	rawKey := QuotaKeyPrefix + keyName
    60  	log.WithFields(logrus.Fields{
    61  		"prefix":      "auth-mgr",
    62  		"inbound-key": obfuscateKey(origKeyName),
    63  		"key":         rawKey,
    64  	}).Info("Reset quota for key.")
    65  
    66  	rateLimiterSentinelKey := RateLimitKeyPrefix + keyName + ".BLOCKED"
    67  	// Clear the rate limiter
    68  	go b.store.DeleteRawKey(rateLimiterSentinelKey)
    69  	// Fix the raw key
    70  	go b.store.DeleteRawKey(rawKey)
    71  	//go b.store.SetKey(rawKey, "0", session.QuotaRenewalRate)
    72  
    73  	for _, acl := range session.GetAccessRights() {
    74  		rawKey = QuotaKeyPrefix + acl.AllowanceScope + "-" + keyName
    75  		go b.store.DeleteRawKey(rawKey)
    76  	}
    77  }
    78  
    79  func (b *DefaultSessionManager) clearCacheForKey(keyName string, hashed bool) {
    80  	cacheKey := keyName
    81  	if !hashed {
    82  		cacheKey = storage.HashKey(keyName)
    83  	}
    84  
    85  	// Delete current gateway's cache immediately
    86  	SessionCache.Delete(cacheKey)
    87  
    88  	// Notify gateways in cluster to flush cache
    89  	n := Notification{
    90  		Command: KeySpaceUpdateNotification,
    91  		Payload: cacheKey,
    92  	}
    93  	MainNotifier.Notify(n)
    94  }
    95  
    96  // UpdateSession updates the session state in the storage engine
    97  func (b *DefaultSessionManager) UpdateSession(keyName string, session *user.SessionState,
    98  	resetTTLTo int64, hashed bool) error {
    99  	defer b.clearCacheForKey(keyName, hashed)
   100  
   101  	v, err := json.Marshal(session)
   102  	if err != nil {
   103  		log.Error("Error marshalling session for sync update")
   104  		return err
   105  	}
   106  
   107  	// sync update
   108  	if hashed {
   109  		keyName = b.store.GetKeyPrefix() + keyName
   110  		err = b.store.SetRawKey(keyName, string(v), resetTTLTo)
   111  	} else {
   112  		err = b.store.SetKey(keyName, string(v), resetTTLTo)
   113  	}
   114  
   115  	return err
   116  }
   117  
   118  // RemoveSession removes session from storage
   119  func (b *DefaultSessionManager) RemoveSession(keyName string, hashed bool) bool {
   120  	defer b.clearCacheForKey(keyName, hashed)
   121  
   122  	if hashed {
   123  		return b.store.DeleteRawKey(b.store.GetKeyPrefix() + keyName)
   124  	} else {
   125  		// support both old and new key hashing
   126  		res1 := b.store.DeleteKey(keyName)
   127  		res2 := b.store.DeleteKey(generateToken(b.orgID, keyName))
   128  		return res1 || res2
   129  	}
   130  }
   131  
   132  // SessionDetail returns the session detail using the storage engine (either in memory or Redis)
   133  func (b *DefaultSessionManager) SessionDetail(keyName string, hashed bool) (user.SessionState, bool) {
   134  	var jsonKeyVal string
   135  	var err error
   136  	session := user.SessionState{Mutex: &sync.RWMutex{}}
   137  	// get session by key
   138  	if hashed {
   139  		jsonKeyVal, err = b.store.GetRawKey(b.store.GetKeyPrefix() + keyName)
   140  	} else {
   141  		if storage.TokenOrg(keyName) != b.orgID {
   142  			// try to get legacy and new format key at once
   143  			toSearchList := []string{generateToken(b.orgID, keyName), keyName}
   144  			for _, fallback := range config.Global().HashKeyFunctionFallback {
   145  				toSearchList = append(toSearchList, generateToken(b.orgID, keyName, fallback))
   146  			}
   147  
   148  			var jsonKeyValList []string
   149  			jsonKeyValList, err = b.store.GetMultiKey(toSearchList)
   150  
   151  			// pick the 1st non empty from the returned list
   152  			for _, val := range jsonKeyValList {
   153  				if val != "" {
   154  					jsonKeyVal = val
   155  					break
   156  				}
   157  			}
   158  		} else {
   159  			// key is not an imported one
   160  			jsonKeyVal, err = b.store.GetKey(keyName)
   161  		}
   162  	}
   163  
   164  	if err != nil {
   165  		log.WithFields(logrus.Fields{
   166  			"prefix":      "auth-mgr",
   167  			"inbound-key": obfuscateKey(keyName),
   168  			"err":         err,
   169  		}).Debug("Could not get session detail, key not found")
   170  		return session, false
   171  	}
   172  
   173  	if err := json.Unmarshal([]byte(jsonKeyVal), &session); err != nil {
   174  		log.Error("Couldn't unmarshal session object (may be cache miss): ", err)
   175  		return session, false
   176  	}
   177  
   178  	return session, true
   179  }
   180  
   181  func (b *DefaultSessionManager) Stop() {}
   182  
   183  // Sessions returns all sessions in the key store that match a filter key (a prefix)
   184  func (b *DefaultSessionManager) Sessions(filter string) []string {
   185  	return b.store.GetKeys(filter)
   186  }
   187  
   188  type DefaultKeyGenerator struct{}
   189  
   190  func generateToken(orgID, keyID string, customHashKeyFunction ...string) string {
   191  	keyID = strings.TrimPrefix(keyID, orgID)
   192  	hashKeyFunction := config.Global().HashKeyFunction
   193  
   194  	if len(customHashKeyFunction) > 0 {
   195  		hashKeyFunction = customHashKeyFunction[0]
   196  	}
   197  
   198  	token, err := storage.GenerateToken(orgID, keyID, hashKeyFunction)
   199  	if err != nil {
   200  		log.WithFields(logrus.Fields{
   201  			"prefix": "auth-mgr",
   202  			"orgID":  orgID,
   203  		}).WithError(err).Warning("Issue during token generation")
   204  	}
   205  
   206  	return token
   207  }
   208  
   209  // GenerateAuthKey is a utility function for generating new auth keys. Returns the storage key name and the actual key
   210  func (DefaultKeyGenerator) GenerateAuthKey(orgID string) string {
   211  	return generateToken(orgID, "")
   212  }
   213  
   214  // GenerateHMACSecret is a utility function for generating new auth keys. Returns the storage key name and the actual key
   215  func (DefaultKeyGenerator) GenerateHMACSecret() string {
   216  	u5 := uuid.NewV4()
   217  	cleanSting := strings.Replace(u5.String(), "-", "", -1)
   218  	return base64.StdEncoding.EncodeToString([]byte(cleanSting))
   219  }