Skip to content

Commit

Permalink
user: new package with SessionState
Browse files Browse the repository at this point in the history
Since this is useful in other places, such as the dashboard repo.
  • Loading branch information
mvdan committed Oct 6, 2017
1 parent d67d254 commit 2a9d7d5
Show file tree
Hide file tree
Showing 37 changed files with 245 additions and 213 deletions.
35 changes: 18 additions & 17 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/TykTechnologies/tyk/apidef"
"github.com/TykTechnologies/tyk/config"
"github.com/TykTechnologies/tyk/storage"
"github.com/TykTechnologies/tyk/user"
)

// APIModifyKeySuccess represents when a Key modification was successful
Expand Down Expand Up @@ -84,7 +85,7 @@ func GetSpecForOrg(apiID string) *APISpec {
return apisByID[aKey]
}

func checkAndApplyTrialPeriod(keyName, apiId string, newSession *SessionState) {
func checkAndApplyTrialPeriod(keyName, apiId string, newSession *user.SessionState) {
// Check the policies to see if we are forcing an expiry on the key
for _, polID := range newSession.PolicyIDs() {
policiesMu.RLock()
Expand All @@ -105,7 +106,7 @@ func checkAndApplyTrialPeriod(keyName, apiId string, newSession *SessionState) {
}
}

func doAddOrUpdate(keyName string, newSession *SessionState, dontReset bool) error {
func doAddOrUpdate(keyName string, newSession *user.SessionState, dontReset bool) error {
newSession.LastUpdated = strconv.Itoa(int(time.Now().Unix()))

if len(newSession.AccessRights) > 0 {
Expand Down Expand Up @@ -192,19 +193,19 @@ func ObfuscateKeyString(keyName string) string {
// remove from all stores, update to all stores, stores handle quotas separately though because they are localised! Keys will
// need to be managed by API, but only for GetDetail, GetList, UpdateKey and DeleteKey

func SetSessionPassword(session *SessionState) {
session.BasicAuthData.Hash = HashBCrypt
func SetSessionPassword(session *user.SessionState) {
session.BasicAuthData.Hash = user.HashBCrypt
newPass, err := bcrypt.GenerateFromPassword([]byte(session.BasicAuthData.Password), 10)
if err != nil {
log.Error("Could not hash password, setting to plaintext, error was: ", err)
session.BasicAuthData.Hash = HashPlainText
session.BasicAuthData.Hash = user.HashPlainText
return
}

session.BasicAuthData.Password = string(newPass)
}

func GetKeyDetail(key, apiID string) (SessionState, bool) {
func GetKeyDetail(key, apiID string) (user.SessionState, bool) {
sessionManager := FallbackKeySesionManager
if spec := getApiSpec(apiID); spec != nil {
sessionManager = spec.SessionManager
Expand All @@ -214,7 +215,7 @@ func GetKeyDetail(key, apiID string) (SessionState, bool) {
}

func handleAddOrUpdate(keyName string, r *http.Request) (interface{}, int) {
var newSession SessionState
var newSession user.SessionState
if err := json.NewDecoder(r.Body).Decode(&newSession); err != nil {
log.Error("Couldn't decode new session object: ", err)
return apiError("Request malformed"), 400
Expand All @@ -231,7 +232,7 @@ func handleAddOrUpdate(keyName string, r *http.Request) (interface{}, int) {
SetSessionPassword(&newSession)
case "PUT":
// Ge the session
var originalKey SessionState
var originalKey user.SessionState
var found bool
for apiID := range newSession.AccessRights {
originalKey, found = GetKeyDetail(keyName, apiID)
Expand Down Expand Up @@ -339,7 +340,7 @@ func handleDeleteKey(keyName, apiID string) (interface{}, int) {
apisMu.RLock()
for _, spec := range apisByID {
spec.SessionManager.RemoveSession(keyName)
spec.SessionManager.ResetQuota(keyName, &SessionState{})
spec.SessionManager.ResetQuota(keyName, &user.SessionState{})
}
apisMu.RUnlock()

Expand All @@ -360,7 +361,7 @@ func handleDeleteKey(keyName, apiID string) (interface{}, int) {
}

sessionManager.RemoveSession(keyName)
sessionManager.ResetQuota(keyName, &SessionState{})
sessionManager.ResetQuota(keyName, &user.SessionState{})

statusObj := APIModifyKeySuccess{keyName, "ok", "deleted"}

Expand Down Expand Up @@ -629,7 +630,7 @@ func handleUpdateHashedKey(keyName, apiID, policyId string) (interface{}, int) {
return apiError("Key not found"), 404
}

sess := SessionState{}
sess := user.SessionState{}
if err := json.Unmarshal([]byte(rawSessionData), &sess); err != nil {
log.WithFields(logrus.Fields{
"prefix": "api",
Expand Down Expand Up @@ -707,7 +708,7 @@ func orgHandler(w http.ResponseWriter, r *http.Request) {
}

func handleOrgAddOrUpdate(keyName string, r *http.Request) (interface{}, int) {
newSession := new(SessionState)
newSession := new(user.SessionState)

if err := json.NewDecoder(r.Body).Decode(newSession); err != nil {
log.Error("Couldn't decode new session object: ", err)
Expand Down Expand Up @@ -866,7 +867,7 @@ func resetHandler(fn func()) http.HandlerFunc {
}

func createKeyHandler(w http.ResponseWriter, r *http.Request) {
newSession := new(SessionState)
newSession := new(user.SessionState)
if err := json.NewDecoder(r.Body).Decode(newSession); err != nil {
log.WithFields(logrus.Fields{
"prefix": "api",
Expand Down Expand Up @@ -1324,7 +1325,7 @@ func UserRatesCheck() http.HandlerFunc {
return
}

returnSession := PublicSessionState{}
returnSession := PublicSession{}
returnSession.Quota.QuotaRenews = session.QuotaRenews
returnSession.Quota.QuotaRemaining = session.QuotaRemaining
returnSession.Quota.QuotaMax = session.QuotaMax
Expand Down Expand Up @@ -1395,14 +1396,14 @@ func ctxSetData(r *http.Request, m map[string]interface{}) {
setCtxValue(r, ContextData, m)
}

func ctxGetSession(r *http.Request) *SessionState {
func ctxGetSession(r *http.Request) *user.SessionState {
if v := r.Context().Value(SessionData); v != nil {
return v.(*SessionState)
return v.(*user.SessionState)
}
return nil
}

func ctxSetSession(r *http.Request, s *SessionState) {
func ctxSetSession(r *http.Request, s *user.SessionState) {
if s == nil {
panic("setting a nil context SessionData")
}
Expand Down
9 changes: 5 additions & 4 deletions api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/TykTechnologies/tyk/apidef"
"github.com/TykTechnologies/tyk/config"
"github.com/TykTechnologies/tyk/storage"
"github.com/TykTechnologies/tyk/user"
)

const apiTestDef = `{
Expand Down Expand Up @@ -64,8 +65,8 @@ func TestHealthCheckEndpoint(t *testing.T) {
}
}

func createSampleSession() *SessionState {
return &SessionState{
func createSampleSession() *user.SessionState {
return &user.SessionState{
Rate: 5.0,
Allowance: 5.0,
LastCheck: time.Now().Unix(),
Expand All @@ -74,7 +75,7 @@ func createSampleSession() *SessionState {
QuotaRenews: time.Now().Unix(),
QuotaRemaining: 10,
QuotaMax: 10,
AccessRights: map[string]AccessDefinition{
AccessRights: map[string]user.AccessDefinition{
"1": {
APIName: "Test",
APIID: "1",
Expand Down Expand Up @@ -695,7 +696,7 @@ func TestContextSession(t *testing.T) {
if ctxGetSession(r) != nil {
t.Fatal("expected ctxGetSession to return nil")
}
ctxSetSession(r, &SessionState{})
ctxSetSession(r, &user.SessionState{})
if ctxGetSession(r) == nil {
t.Fatal("expected ctxGetSession to return non-nil")
}
Expand Down
33 changes: 17 additions & 16 deletions auth_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,31 @@ import (

"github.com/TykTechnologies/tyk/config"
"github.com/TykTechnologies/tyk/storage"
"github.com/TykTechnologies/tyk/user"

"github.com/Sirupsen/logrus"
)

// AuthorisationHandler is used to validate a session key,
// implementing KeyAuthorised() to validate if a key exists or
// is valid in any way (e.g. cryptographic signing etc.). Returns
// a SessionState object (deserialised JSON)
// a user.SessionState object (deserialised JSON)
type AuthorisationHandler interface {
Init(storage.Handler)
KeyAuthorised(string) (SessionState, bool)
KeyExpired(*SessionState) bool
KeyAuthorised(string) (user.SessionState, bool)
KeyExpired(*user.SessionState) bool
}

// SessionHandler handles all update/create/access session functions and deals exclusively with
// SessionState objects, not identity
// user.SessionState objects, not identity
type SessionHandler interface {
Init(store storage.Handler)
UpdateSession(keyName string, session *SessionState, resetTTLTo int64) error
UpdateSession(keyName string, session *user.SessionState, resetTTLTo int64) error
RemoveSession(keyName string)
SessionDetail(keyName string) (SessionState, bool)
SessionDetail(keyName string) (user.SessionState, bool)
Sessions(filter string) []string
Store() storage.Handler
ResetQuota(string, *SessionState)
ResetQuota(string, *user.SessionState)
}

// DefaultAuthorisationManager implements AuthorisationHandler,
Expand All @@ -51,10 +52,10 @@ func (b *DefaultAuthorisationManager) Init(store storage.Handler) {
b.store.Connect()
}

// KeyAuthorised checks if key exists and can be read into a SessionState object
func (b *DefaultAuthorisationManager) KeyAuthorised(keyName string) (SessionState, bool) {
// KeyAuthorised checks if key exists and can be read into a user.SessionState object
func (b *DefaultAuthorisationManager) KeyAuthorised(keyName string) (user.SessionState, bool) {
jsonKeyVal, err := b.store.GetKey(keyName)
var newSession SessionState
var newSession user.SessionState
if err != nil {
log.WithFields(logrus.Fields{
"prefix": "auth-mgr",
Expand All @@ -73,8 +74,8 @@ func (b *DefaultAuthorisationManager) KeyAuthorised(keyName string) (SessionStat
return newSession, true
}

// KeyExpired checks if a key has expired, if the value of SessionState.Expires is 0, it will be ignored
func (b *DefaultAuthorisationManager) KeyExpired(newSession *SessionState) bool {
// KeyExpired checks if a key has expired, if the value of user.SessionState.Expires is 0, it will be ignored
func (b *DefaultAuthorisationManager) KeyExpired(newSession *user.SessionState) bool {
if newSession.Expires >= 1 {
return time.Now().After(time.Unix(newSession.Expires, 0))
}
Expand All @@ -90,7 +91,7 @@ func (b *DefaultSessionManager) Store() storage.Handler {
return b.store
}

func (b *DefaultSessionManager) ResetQuota(keyName string, session *SessionState) {
func (b *DefaultSessionManager) ResetQuota(keyName string, session *user.SessionState) {

rawKey := QuotaKeyPrefix + storage.HashKey(keyName)
log.WithFields(logrus.Fields{
Expand All @@ -108,7 +109,7 @@ func (b *DefaultSessionManager) ResetQuota(keyName string, session *SessionState
}

// UpdateSession updates the session state in the storage engine
func (b *DefaultSessionManager) UpdateSession(keyName string, session *SessionState, resetTTLTo int64) error {
func (b *DefaultSessionManager) UpdateSession(keyName string, session *user.SessionState, resetTTLTo int64) error {
if !session.HasChanged() {
log.Debug("Session has not changed, not updating")
return nil
Expand All @@ -129,9 +130,9 @@ func (b *DefaultSessionManager) RemoveSession(keyName string) {
}

// SessionDetail returns the session detail using the storage engine (either in memory or Redis)
func (b *DefaultSessionManager) SessionDetail(keyName string) (SessionState, bool) {
func (b *DefaultSessionManager) SessionDetail(keyName string) (user.SessionState, bool) {
jsonKeyVal, err := b.store.GetKey(keyName)
var session SessionState
var session user.SessionState
if err != nil {
log.WithFields(logrus.Fields{
"prefix": "auth-mgr",
Expand Down
21 changes: 11 additions & 10 deletions coprocess_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,30 @@ package main

import (
"github.com/TykTechnologies/tyk/coprocess"
"github.com/TykTechnologies/tyk/user"
)

// TykSessionState takes a coprocess.SessionState (as returned by the Protocol Buffer binding), and outputs a standard Tyk SessionState.
func TykSessionState(session *coprocess.SessionState) *SessionState {
accessDefinitions := make(map[string]AccessDefinition, len(session.AccessRights))
func TykSessionState(session *coprocess.SessionState) *user.SessionState {
accessDefinitions := make(map[string]user.AccessDefinition, len(session.AccessRights))

for key, protoAccessDefinition := range session.AccessRights {
allowedUrls := make([]AccessSpec, len(protoAccessDefinition.AllowedUrls))
allowedUrls := make([]user.AccessSpec, len(protoAccessDefinition.AllowedUrls))
for _, protoAllowedURL := range protoAccessDefinition.AllowedUrls {
allowedURL := AccessSpec{protoAllowedURL.Url, protoAllowedURL.Methods}
allowedURL := user.AccessSpec{protoAllowedURL.Url, protoAllowedURL.Methods}
allowedUrls = append(allowedUrls, allowedURL)
}
accessDefinition := AccessDefinition{protoAccessDefinition.ApiName, protoAccessDefinition.ApiId, protoAccessDefinition.Versions, allowedUrls}
accessDefinition := user.AccessDefinition{protoAccessDefinition.ApiName, protoAccessDefinition.ApiId, protoAccessDefinition.Versions, allowedUrls}
accessDefinitions[key] = accessDefinition
}

var basicAuthData struct {
Password string `json:"password" msg:"password"`
Hash HashType `json:"hash_type" msg:"hash_type"`
Password string `json:"password" msg:"password"`
Hash user.HashType `json:"hash_type" msg:"hash_type"`
}
if session.BasicAuthData != nil {
basicAuthData.Password = session.BasicAuthData.Password
basicAuthData.Hash = HashType(session.BasicAuthData.Hash)
basicAuthData.Hash = user.HashType(session.BasicAuthData.Hash)
}

var jwtData struct {
Expand All @@ -44,7 +45,7 @@ func TykSessionState(session *coprocess.SessionState) *SessionState {
monitor.TriggerLimits = session.Monitor.TriggerLimits
}

return &SessionState{
return &user.SessionState{
session.LastCheck,
session.Allowance,
session.Rate,
Expand Down Expand Up @@ -79,7 +80,7 @@ func TykSessionState(session *coprocess.SessionState) *SessionState {
}

// ProtoSessionState takes a standard SessionState and outputs a SessionState object compatible with Protocol Buffers.
func ProtoSessionState(session *SessionState) *coprocess.SessionState {
func ProtoSessionState(session *user.SessionState) *coprocess.SessionState {

accessDefinitions := make(map[string]*coprocess.AccessDefinition, len(session.AccessRights))

Expand Down
5 changes: 3 additions & 2 deletions coprocess_id_extractor.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ import (
"gopkg.in/xmlpath.v2"

"github.com/TykTechnologies/tyk/apidef"
"github.com/TykTechnologies/tyk/user"
)

// IdExtractor is the base interface for an ID extractor.
type IdExtractor interface {
ExtractAndCheck(*http.Request) (string, ReturnOverrides)
PostProcess(*http.Request, *SessionState, string)
PostProcess(*http.Request, *user.SessionState, string)
GenerateSessionID(string, BaseMiddleware) string
}

Expand All @@ -42,7 +43,7 @@ func (e *BaseExtractor) ExtractAndCheck(r *http.Request) (sessionID string, retu
}

// PostProcess sets context variables and updates the storage.
func (e *BaseExtractor) PostProcess(r *http.Request, session *SessionState, sessionID string) {
func (e *BaseExtractor) PostProcess(r *http.Request, session *user.SessionState, sessionID string) {
sessionLifetime := session.Lifetime(e.Spec.SessionLifetime)
e.Spec.SessionManager.UpdateSession(sessionID, session, sessionLifetime)

Expand Down
Loading

0 comments on commit 2a9d7d5

Please sign in to comment.