Skip to content

Commit

Permalink
Allow updating key by its hash by passing hashed=true
Browse files Browse the repository at this point in the history
Works similar to how we allowed deleting key by hash
  • Loading branch information
buger committed Jan 11, 2019
1 parent ac2d339 commit 352f98c
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 44 deletions.
58 changes: 31 additions & 27 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func getSpecForOrg(orgID string) *APISpec {
return nil
}

func checkAndApplyTrialPeriod(keyName, apiId string, newSession *user.SessionState) {
func checkAndApplyTrialPeriod(keyName, apiId string, newSession *user.SessionState, isHashed bool) {
// Check the policies to see if we are forcing an expiry on the key
for _, polID := range newSession.PolicyIDs() {
policiesMu.RLock()
Expand All @@ -106,7 +106,7 @@ func checkAndApplyTrialPeriod(keyName, apiId string, newSession *user.SessionSta
// Are we foring an expiry?
if policy.KeyExpiresIn > 0 {
// We are, does the key exist?
_, found := getKeyDetail(keyName, apiId, false)
_, found := getKeyDetail(keyName, apiId, isHashed)
if !found {
// this is a new key, lets expire it
newSession.Expires = time.Now().Unix() + policy.KeyExpiresIn
Expand All @@ -115,17 +115,17 @@ func checkAndApplyTrialPeriod(keyName, apiId string, newSession *user.SessionSta
}
}

func applyPoliciesAndSave(keyName string, session *user.SessionState, spec *APISpec) error {
func applyPoliciesAndSave(keyName string, session *user.SessionState, spec *APISpec, isHashed bool) error {
// use basic middleware to apply policies to key/session (it also saves it)
mw := BaseMiddleware{
Spec: spec,
}
if err := mw.ApplyPolicies(keyName, session); err != nil {
if err := mw.ApplyPolicies(session); err != nil {
return err
}

lifetime := session.Lifetime(spec.SessionLifetime)
if err := spec.SessionManager.UpdateSession(keyName, session, lifetime, false); err != nil {
if err := spec.SessionManager.UpdateSession(keyName, session, lifetime, isHashed); err != nil {
return err
}

Expand All @@ -142,7 +142,7 @@ func resetAPILimits(accessRights map[string]user.AccessDefinition) {
}
}

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

if len(newSession.AccessRights) > 0 {
Expand All @@ -164,18 +164,18 @@ func doAddOrUpdate(keyName string, newSession *user.SessionState, dontReset bool
}).Error("Could not add key for this API ID, API doesn't exist.")
return errors.New("API must be active to add keys")
}
checkAndApplyTrialPeriod(keyName, apiId, newSession)
checkAndApplyTrialPeriod(keyName, apiId, newSession, isHashed)

// Lets reset keys if they are edited by admin
if !apiSpec.DontSetQuotasOnCreate {
// Reset quote by default
if !dontReset {
apiSpec.SessionManager.ResetQuota(keyName, newSession)
apiSpec.SessionManager.ResetQuota(keyName, newSession, isHashed)
newSession.QuotaRenews = time.Now().Unix() + newSession.QuotaRenewalRate
}

// apply polices (if any) and save key
if err := applyPoliciesAndSave(keyName, newSession, apiSpec); err != nil {
if err := applyPoliciesAndSave(keyName, newSession, apiSpec, isHashed); err != nil {
return err
}
}
Expand All @@ -191,13 +191,13 @@ func doAddOrUpdate(keyName string, newSession *user.SessionState, dontReset bool
defer apisMu.RUnlock()
for _, spec := range apisByID {
if !dontReset {
spec.SessionManager.ResetQuota(keyName, newSession)
spec.SessionManager.ResetQuota(keyName, newSession, isHashed)
newSession.QuotaRenews = time.Now().Unix() + newSession.QuotaRenewalRate
}
checkAndApplyTrialPeriod(keyName, spec.APIID, newSession)
checkAndApplyTrialPeriod(keyName, spec.APIID, newSession, isHashed)

// apply polices (if any) and save key
if err := applyPoliciesAndSave(keyName, newSession, spec); err != nil {
if err := applyPoliciesAndSave(keyName, newSession, spec, isHashed); err != nil {
return err
}
}
Expand Down Expand Up @@ -243,7 +243,7 @@ func getKeyDetail(key, apiID string, hashed bool) (user.SessionState, bool) {
return sessionManager.SessionDetail(key, hashed)
}

func handleAddOrUpdate(keyName string, r *http.Request) (interface{}, int) {
func handleAddOrUpdate(keyName string, r *http.Request, isHashed bool) (interface{}, int) {
var newSession 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 @@ -285,7 +285,7 @@ func handleAddOrUpdate(keyName string, r *http.Request) (interface{}, int) {

suppressReset := r.URL.Query().Get("suppress_reset") == "1"

if err := doAddOrUpdate(keyName, &newSession, suppressReset); err != nil {
if err := doAddOrUpdate(keyName, &newSession, suppressReset, isHashed); err != nil {
return apiError("Failed to create key, ensure security settings are correct."), http.StatusInternalServerError
}

Expand All @@ -309,7 +309,11 @@ func handleAddOrUpdate(keyName string, r *http.Request) (interface{}, int) {

// add key hash for newly created key
if config.Global().HashKeys && r.Method == http.MethodPost {
response.KeyHash = storage.HashKey(keyName)
if isHashed {
response.KeyHash = keyName
} else {
response.KeyHash = storage.HashKey(keyName)
}
}

return response, http.StatusOK
Expand Down Expand Up @@ -358,7 +362,7 @@ func handleGetDetail(sessionKey, apiID string, byHash bool) (interface{}, int) {
}

mw := BaseMiddleware{Spec: spec}
mw.ApplyPolicies(sessionKey, &session)
mw.ApplyPolicies(&session)

log.WithFields(logrus.Fields{
"prefix": "api",
Expand Down Expand Up @@ -435,7 +439,7 @@ func handleDeleteKey(keyName, apiID string) (interface{}, int) {
apisMu.RLock()
for _, spec := range apisByID {
spec.SessionManager.RemoveSession(keyName, false)
spec.SessionManager.ResetQuota(keyName, &user.SessionState{})
spec.SessionManager.ResetQuota(keyName, &user.SessionState{}, false)
}
apisMu.RUnlock()

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

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

statusObj := apiModifyKeySuccess{
Key: keyName,
Expand Down Expand Up @@ -669,7 +673,7 @@ func keyHandler(w http.ResponseWriter, r *http.Request) {

switch r.Method {
case "POST", "PUT":
obj, code = handleAddOrUpdate(keyName, r)
obj, code = handleAddOrUpdate(keyName, r, isHashed)

case "GET":
if keyName != "" {
Expand Down Expand Up @@ -826,7 +830,7 @@ func handleOrgAddOrUpdate(keyName string, r *http.Request) (interface{}, int) {
}

if r.URL.Query().Get("reset_quota") == "1" {
sessionManager.ResetQuota(keyName, newSession)
sessionManager.ResetQuota(keyName, newSession, false)
newSession.QuotaRenews = time.Now().Unix() + newSession.QuotaRenewalRate
rawKey := QuotaKeyPrefix + storage.HashKey(keyName)

Expand Down Expand Up @@ -1011,23 +1015,23 @@ func createKeyHandler(w http.ResponseWriter, r *http.Request) {
for apiID := range newSession.AccessRights {
apiSpec := getApiSpec(apiID)
if apiSpec != nil {
checkAndApplyTrialPeriod(newKey, apiID, newSession)
checkAndApplyTrialPeriod(newKey, apiID, newSession, false)
// If we have enabled HMAC checking for keys, we need to generate a secret for the client to use
if !apiSpec.DontSetQuotasOnCreate {
// Reset quota by default
apiSpec.SessionManager.ResetQuota(newKey, newSession)
apiSpec.SessionManager.ResetQuota(newKey, newSession, false)
newSession.QuotaRenews = time.Now().Unix() + newSession.QuotaRenewalRate
}
// apply polices (if any) and save key
if err := applyPoliciesAndSave(newKey, newSession, apiSpec); err != nil {
if err := applyPoliciesAndSave(newKey, newSession, apiSpec, false); err != nil {
doJSONWrite(w, http.StatusInternalServerError, apiError("Failed to create key - "+err.Error()))
return
}
} else {
// Use fallback
sessionManager := FallbackKeySesionManager
newSession.QuotaRenews = time.Now().Unix() + newSession.QuotaRenewalRate
sessionManager.ResetQuota(newKey, newSession)
sessionManager.ResetQuota(newKey, newSession, false)
err := sessionManager.UpdateSession(newKey, newSession, -1, false)
if err != nil {
doJSONWrite(w, http.StatusInternalServerError, apiError("Failed to create key - "+err.Error()))
Expand All @@ -1052,14 +1056,14 @@ func createKeyHandler(w http.ResponseWriter, r *http.Request) {
apisMu.RLock()
defer apisMu.RUnlock()
for _, spec := range apisByID {
checkAndApplyTrialPeriod(newKey, spec.APIID, newSession)
checkAndApplyTrialPeriod(newKey, spec.APIID, newSession, false)
if !spec.DontSetQuotasOnCreate {
// Reset quote by default
spec.SessionManager.ResetQuota(newKey, newSession)
spec.SessionManager.ResetQuota(newKey, newSession, false)
newSession.QuotaRenews = time.Now().Unix() + newSession.QuotaRenewalRate
}
// apply polices (if any) and save key
if err := applyPoliciesAndSave(newKey, newSession, spec); err != nil {
if err := applyPoliciesAndSave(newKey, newSession, spec, false); err != nil {
doJSONWrite(w, http.StatusInternalServerError, apiError("Failed to create key - "+err.Error()))
return
}
Expand Down
9 changes: 9 additions & 0 deletions api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,15 @@ func testHashKeyHandlerHelper(t *testing.T, expectedHashSize int) {
Code: 200,
BodyMatch: fmt.Sprintf(`"key_hash":"%s"`, myKeyHash),
},
// Update key by hash value with specifying hashed=true
{
Method: "PUT",
Path: "/tyk/keys/" + myKeyHash + "?hashed=true",
Data: string(withAccessJSON),
AdminAuth: true,
Code: 200,
BodyMatch: fmt.Sprintf(`"key":"%s"`, myKeyHash),
},
// get one key by key name
{
Method: "GET",
Expand Down
15 changes: 10 additions & 5 deletions auth_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type SessionHandler interface {
SessionDetail(keyName string, hashed bool) (user.SessionState, bool)
Sessions(filter string) []string
Store() storage.Handler
ResetQuota(string, *user.SessionState)
ResetQuota(string, *user.SessionState, bool)
Stop()
}

Expand Down Expand Up @@ -183,15 +183,20 @@ func (b *DefaultSessionManager) Store() storage.Handler {
return b.store
}

func (b *DefaultSessionManager) ResetQuota(keyName string, session *user.SessionState) {
rawKey := QuotaKeyPrefix + storage.HashKey(keyName)
func (b *DefaultSessionManager) ResetQuota(keyName string, session *user.SessionState, isHashed bool) {
origKeyName := keyName
if !isHashed {
keyName = storage.HashKey(keyName)
}

rawKey := QuotaKeyPrefix + keyName
log.WithFields(logrus.Fields{
"prefix": "auth-mgr",
"inbound-key": obfuscateKey(keyName),
"inbound-key": obfuscateKey(origKeyName),
"key": rawKey,
}).Info("Reset quota for key.")

rateLimiterSentinelKey := RateLimitKeyPrefix + storage.HashKey(keyName) + ".BLOCKED"
rateLimiterSentinelKey := RateLimitKeyPrefix + keyName + ".BLOCKED"
// Clear the rate limiter
go b.store.DeleteRawKey(rateLimiterSentinelKey)
// Fix the raw key
Expand Down
8 changes: 4 additions & 4 deletions middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ func (t BaseMiddleware) UpdateRequestSession(r *http.Request) bool {

// ApplyPolicies will check if any policies are loaded. If any are, it
// will overwrite the session state to use the policy values.
func (t BaseMiddleware) ApplyPolicies(key string, session *user.SessionState) error {
func (t BaseMiddleware) ApplyPolicies(session *user.SessionState) error {
rights := session.AccessRights
if rights == nil {
rights = make(map[string]user.AccessDefinition)
Expand Down Expand Up @@ -420,7 +420,7 @@ func (t BaseMiddleware) CheckSessionAndIdentityForValidKey(key string, r *http.R
if found {
t.Logger().Debug("--> Key found in local cache")
session := cachedVal.(user.SessionState)
if err := t.ApplyPolicies(key, &session); err != nil {
if err := t.ApplyPolicies(&session); err != nil {
t.Logger().Error(err)
return session, false
}
Expand All @@ -440,7 +440,7 @@ func (t BaseMiddleware) CheckSessionAndIdentityForValidKey(key string, r *http.R
}

// Check for a policy, if there is a policy, pull it and overwrite the session values
if err := t.ApplyPolicies(key, &session); err != nil {
if err := t.ApplyPolicies(&session); err != nil {
t.Logger().Error(err)
return session, false
}
Expand All @@ -462,7 +462,7 @@ func (t BaseMiddleware) CheckSessionAndIdentityForValidKey(key string, r *http.R
}

// Check for a policy, if there is a policy, pull it and overwrite the session values
if err := t.ApplyPolicies(key, &session); err != nil {
if err := t.ApplyPolicies(&session); err != nil {
t.Logger().Error(err)
return session, false
}
Expand Down
2 changes: 1 addition & 1 deletion mw_js_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ func (j *JSVM) LoadTykJSApi() {
return otto.Value{}
}

doAddOrUpdate(apiKey, &newSession, suppressReset == "1")
doAddOrUpdate(apiKey, &newSession, suppressReset == "1", false)

return otto.Value{}
})
Expand Down
4 changes: 2 additions & 2 deletions mw_jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ func (k *JWTMiddleware) processCentralisedJWT(r *http.Request, token *jwt.Token)
newSession.SetPolicies(polIDs...)

// multiple policies assigned to a key, check if it is applicable
if err := k.ApplyPolicies(sessionID, &newSession); err != nil {
if err := k.ApplyPolicies(&newSession); err != nil {
k.reportLoginFailure(baseFieldData, r)
k.Logger().WithError(err).Error("Could not several policies from scope-claim mapping to JWT to session")
return errors.New("Key not authorized: could not apply several policies"), http.StatusForbidden
Expand Down Expand Up @@ -390,7 +390,7 @@ func (k *JWTMiddleware) processCentralisedJWT(r *http.Request, token *jwt.Token)
}
// apply new policy to session and update session
session.SetPolicies(policyID)
if err := k.ApplyPolicies(sessionID, &session); err != nil {
if err := k.ApplyPolicies(&session); err != nil {
k.reportLoginFailure(baseFieldData, r)
k.Logger().WithError(err).Error("Could not apply new policy from JWT to session")
return errors.New("Key not authorized: could not apply new policy"), http.StatusForbidden
Expand Down
2 changes: 1 addition & 1 deletion mw_jwt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ func prepareJWTSessionRSAWithRawSourceOnWithClientID(isBench bool) string {
}
session := createJWTSessionWithRSAWithPolicy(policyID)

spec.SessionManager.ResetQuota(tokenID, session)
spec.SessionManager.ResetQuota(tokenID, session, false)
spec.SessionManager.UpdateSession(tokenID, session, 60, false)

jwtToken := createJWKToken(func(t *jwt.Token) {
Expand Down
2 changes: 1 addition & 1 deletion mw_openid.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ func (k *OpenIDMW) ProcessRequest(w http.ResponseWriter, r *http.Request, _ inte
}
// apply new policy to session if any and update session
session.SetPolicies(policiesToApply...)
if err := k.ApplyPolicies(sessionID, &session); err != nil {
if err := k.ApplyPolicies(&session); err != nil {
k.Logger().WithError(err).Error("Could not apply new policy from OIDC client to session")
return errors.New("Key not authorized: could not apply new policy"), http.StatusForbidden
}
Expand Down
6 changes: 3 additions & 3 deletions policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ func testPrepareApplyPolicies() (*BaseMiddleware, []testApplyPoliciesData) {
policiesMu.Lock()
policiesByID["acl3"] = newPolicy
policiesMu.Unlock()
err := bmid.ApplyPolicies("", s)
err := bmid.ApplyPolicies(s)
if err != nil {
t.Fatalf("couldn't apply policy: %s", err.Error())
}
Expand Down Expand Up @@ -408,7 +408,7 @@ func TestApplyPolicies(t *testing.T) {
sess := &user.SessionState{}
sess.SetPolicies(tc.policies...)
errStr := ""
if err := bmid.ApplyPolicies("", sess); err != nil {
if err := bmid.ApplyPolicies(sess); err != nil {
errStr = err.Error()
}
if tc.errMatch == "" && errStr != "" {
Expand All @@ -433,7 +433,7 @@ func BenchmarkApplyPolicies(b *testing.B) {
for _, tc := range tests {
sess := &user.SessionState{}
sess.SetPolicies(tc.policies...)
bmid.ApplyPolicies("", sess)
bmid.ApplyPolicies(sess)
}
}
}

0 comments on commit 352f98c

Please sign in to comment.