From c8fd291e7109cb9e90c01fbf620b2056eeba2a31 Mon Sep 17 00:00:00 2001 From: dencoded <33698537+dencoded@users.noreply.github.com> Date: Thu, 6 Dec 2018 23:25:30 -0500 Subject: [PATCH 1/3] special case for basic auth added --- api.go | 4 ++++ api_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/api.go b/api.go index f3ab817e2d2..f4f5bcfa0a5 100644 --- a/api.go +++ b/api.go @@ -324,6 +324,10 @@ func handleGetDetail(sessionKey, apiID string, byHash bool) (interface{}, int) { spec := getApiSpec(apiID) if spec != nil { sessionManager = spec.SessionManager + // special case for basic auth with custom hashing algo + if spec.UseBasicAuth && strings.HasPrefix(sessionKey, spec.OrgID) { + sessionKey = generateToken(spec.OrgID, sessionKey) + } } var session user.SessionState diff --git a/api_test.go b/api_test.go index b3d90613247..ead17e56544 100644 --- a/api_test.go +++ b/api_test.go @@ -299,6 +299,9 @@ func TestHashKeyHandler(t *testing.T) { t.Run(fmt.Sprintf("%sHash fn: %s", tc.desc, tc.hashFunction), func(t *testing.T) { testHashKeyHandlerHelper(t, tc.expectedHashSize) }) + t.Run(fmt.Sprintf("%sHash fn: %s and Basic Auth", tc.desc, tc.hashFunction), func(t *testing.T) { + testHashFuncAndBAHelper(t) + }) } } @@ -419,6 +422,29 @@ func testHashKeyHandlerHelper(t *testing.T, expectedHashSize int) { }) } +func testHashFuncAndBAHelper(t *testing.T) { + ts := newTykTestServer() + defer ts.Close() + + session := testPrepareBasicAuth(false) + + ts.Run(t, []test.TestCase{ + { + Method: "POST", + Path: "/tyk/keys/defaultuser", + Data: session, + AdminAuth: true, + Code: 200, + }, + { + Method: "GET", + Path: "/tyk/keys/defaultuser?api_id=test", + AdminAuth: true, + Code: 200, + }, + }...) +} + func TestHashKeyListingDisabled(t *testing.T) { globalConf := config.Global() // make it to use hashes for Redis keys From a9226a1064bd694a4200aaa2960f416fac90e8ea Mon Sep 17 00:00:00 2001 From: dencoded <33698537+dencoded@users.noreply.github.com> Date: Thu, 20 Dec 2018 00:53:14 -0500 Subject: [PATCH 2/3] username URL query param added to GET/PUT/DELETE key by username --- api.go | 30 +++++++++++++++++++++++------- api_test.go | 24 ++++++++++++++++++------ mw_basic_auth_test.go | 17 +++++++++++++++++ 3 files changed, 58 insertions(+), 13 deletions(-) diff --git a/api.go b/api.go index f4f5bcfa0a5..317895d0d7d 100644 --- a/api.go +++ b/api.go @@ -78,16 +78,16 @@ func allowMethods(next http.HandlerFunc, methods ...string) http.HandlerFunc { } } -func getSpecForOrg(apiID string) *APISpec { +func getSpecForOrg(orgID string) *APISpec { apisMu.RLock() defer apisMu.RUnlock() for _, v := range apisByID { - if v.OrgID == apiID { + if v.OrgID == orgID { return v } } - // If we can't find a spec, it doesn;t matter, because we default to Redis anyway, grab whatever you can find + // If we can't find a spec, it doesn't matter, because we default to Redis anyway, grab whatever you can find for _, v := range apisByID { return v } @@ -324,10 +324,6 @@ func handleGetDetail(sessionKey, apiID string, byHash bool) (interface{}, int) { spec := getApiSpec(apiID) if spec != nil { sessionManager = spec.SessionManager - // special case for basic auth with custom hashing algo - if spec.UseBasicAuth && strings.HasPrefix(sessionKey, spec.OrgID) { - sessionKey = generateToken(spec.OrgID, sessionKey) - } } var session user.SessionState @@ -660,6 +656,26 @@ func keyHandler(w http.ResponseWriter, r *http.Request) { keyName := mux.Vars(r)["keyName"] apiID := r.URL.Query().Get("api_id") isHashed := r.URL.Query().Get("hashed") != "" + isUserName := r.URL.Query().Get("username") == "true" + + // check if passed key is user name and convert it to real key with respect to current hashing algorithm + if r.Method != http.MethodPost && isUserName { + orgID := "default" + // check if we have real orgID + if !strings.HasPrefix(keyName, "default") && len(keyName) > 24 { + orgID = keyName[:24] + } + // check if organization ID is real + if spec := getSpecForOrg(orgID); spec == nil { + doJSONWrite( + w, + http.StatusNotFound, + apiError("Key not found"), + ) + return + } + keyName = generateToken(orgID, keyName) + } var obj interface{} var code int diff --git a/api_test.go b/api_test.go index ead17e56544..baa91d83d4c 100644 --- a/api_test.go +++ b/api_test.go @@ -299,8 +299,11 @@ func TestHashKeyHandler(t *testing.T) { t.Run(fmt.Sprintf("%sHash fn: %s", tc.desc, tc.hashFunction), func(t *testing.T) { testHashKeyHandlerHelper(t, tc.expectedHashSize) }) - t.Run(fmt.Sprintf("%sHash fn: %s and Basic Auth", tc.desc, tc.hashFunction), func(t *testing.T) { - testHashFuncAndBAHelper(t) + t.Run(fmt.Sprintf("%sHash fn: %s and Basic Auth with default OrgID", tc.desc, tc.hashFunction), func(t *testing.T) { + testHashFuncAndBAHelper(t, "default") + }) + t.Run(fmt.Sprintf("%sHash fn: %s and Basic Auth with real OrgID", tc.desc, tc.hashFunction), func(t *testing.T) { + testHashFuncAndBAHelper(t, "5b5fd341e6355b5eb194765e") }) } } @@ -422,25 +425,34 @@ func testHashKeyHandlerHelper(t *testing.T, expectedHashSize int) { }) } -func testHashFuncAndBAHelper(t *testing.T) { +func testHashFuncAndBAHelper(t *testing.T, orgID string) { ts := newTykTestServer() defer ts.Close() - session := testPrepareBasicAuth(false) + session := testPrepareBasicAuthWithOrgID(false, orgID) + + userName := orgID + "user" ts.Run(t, []test.TestCase{ { Method: "POST", - Path: "/tyk/keys/defaultuser", + Path: "/tyk/keys/" + userName, Data: session, AdminAuth: true, Code: 200, }, { Method: "GET", - Path: "/tyk/keys/defaultuser?api_id=test", + Path: "/tyk/keys/" + userName + "?username=true", + AdminAuth: true, + Code: 200, + }, + { + Method: "DELETE", + Path: "/tyk/keys/" + userName + "?username=true", AdminAuth: true, Code: 200, + BodyMatch: `"action":"deleted"`, }, }...) } diff --git a/mw_basic_auth_test.go b/mw_basic_auth_test.go index cef5f25d595..f2722584d46 100644 --- a/mw_basic_auth_test.go +++ b/mw_basic_auth_test.go @@ -35,6 +35,23 @@ func testPrepareBasicAuth(cacheDisabled bool) *user.SessionState { return session } +func testPrepareBasicAuthWithOrgID(cacheDisabled bool, orgID string) *user.SessionState { + session := createStandardSession() + session.BasicAuthData.Password = "password" + session.AccessRights = map[string]user.AccessDefinition{"test": {APIID: "test", Versions: []string{"v1"}}} + session.OrgID = orgID + + buildAndLoadAPI(func(spec *APISpec) { + spec.UseBasicAuth = true + spec.BasicAuth.DisableCaching = cacheDisabled + spec.UseKeylessAccess = false + spec.Proxy.ListenPath = "/" + spec.OrgID = orgID + }) + + return session +} + func TestBasicAuth(t *testing.T) { ts := newTykTestServer() defer ts.Close() From 90e9e0d6939f87edcc11e647e0ef6a935ed380ca Mon Sep 17 00:00:00 2001 From: dencoded <33698537+dencoded@users.noreply.github.com> Date: Fri, 21 Dec 2018 15:26:33 -0500 Subject: [PATCH 3/3] added one more query param org_id --- api.go | 15 +-------------- api_test.go | 19 +++++++------------ mw_basic_auth_test.go | 17 ----------------- 3 files changed, 8 insertions(+), 43 deletions(-) diff --git a/api.go b/api.go index 317895d0d7d..bae09231893 100644 --- a/api.go +++ b/api.go @@ -657,23 +657,10 @@ func keyHandler(w http.ResponseWriter, r *http.Request) { apiID := r.URL.Query().Get("api_id") isHashed := r.URL.Query().Get("hashed") != "" isUserName := r.URL.Query().Get("username") == "true" + orgID := r.URL.Query().Get("org_id") // check if passed key is user name and convert it to real key with respect to current hashing algorithm if r.Method != http.MethodPost && isUserName { - orgID := "default" - // check if we have real orgID - if !strings.HasPrefix(keyName, "default") && len(keyName) > 24 { - orgID = keyName[:24] - } - // check if organization ID is real - if spec := getSpecForOrg(orgID); spec == nil { - doJSONWrite( - w, - http.StatusNotFound, - apiError("Key not found"), - ) - return - } keyName = generateToken(orgID, keyName) } diff --git a/api_test.go b/api_test.go index baa91d83d4c..0dd4b555120 100644 --- a/api_test.go +++ b/api_test.go @@ -299,11 +299,8 @@ func TestHashKeyHandler(t *testing.T) { t.Run(fmt.Sprintf("%sHash fn: %s", tc.desc, tc.hashFunction), func(t *testing.T) { testHashKeyHandlerHelper(t, tc.expectedHashSize) }) - t.Run(fmt.Sprintf("%sHash fn: %s and Basic Auth with default OrgID", tc.desc, tc.hashFunction), func(t *testing.T) { - testHashFuncAndBAHelper(t, "default") - }) - t.Run(fmt.Sprintf("%sHash fn: %s and Basic Auth with real OrgID", tc.desc, tc.hashFunction), func(t *testing.T) { - testHashFuncAndBAHelper(t, "5b5fd341e6355b5eb194765e") + t.Run(fmt.Sprintf("%sHash fn: %s and Basic Auth", tc.desc, tc.hashFunction), func(t *testing.T) { + testHashFuncAndBAHelper(t) }) } } @@ -425,31 +422,29 @@ func testHashKeyHandlerHelper(t *testing.T, expectedHashSize int) { }) } -func testHashFuncAndBAHelper(t *testing.T, orgID string) { +func testHashFuncAndBAHelper(t *testing.T) { ts := newTykTestServer() defer ts.Close() - session := testPrepareBasicAuthWithOrgID(false, orgID) - - userName := orgID + "user" + session := testPrepareBasicAuth(false) ts.Run(t, []test.TestCase{ { Method: "POST", - Path: "/tyk/keys/" + userName, + Path: "/tyk/keys/defaultuser", Data: session, AdminAuth: true, Code: 200, }, { Method: "GET", - Path: "/tyk/keys/" + userName + "?username=true", + Path: "/tyk/keys/defaultuser?username=true&org_id=default", AdminAuth: true, Code: 200, }, { Method: "DELETE", - Path: "/tyk/keys/" + userName + "?username=true", + Path: "/tyk/keys/defaultuser?username=true&org_id=default", AdminAuth: true, Code: 200, BodyMatch: `"action":"deleted"`, diff --git a/mw_basic_auth_test.go b/mw_basic_auth_test.go index f2722584d46..cef5f25d595 100644 --- a/mw_basic_auth_test.go +++ b/mw_basic_auth_test.go @@ -35,23 +35,6 @@ func testPrepareBasicAuth(cacheDisabled bool) *user.SessionState { return session } -func testPrepareBasicAuthWithOrgID(cacheDisabled bool, orgID string) *user.SessionState { - session := createStandardSession() - session.BasicAuthData.Password = "password" - session.AccessRights = map[string]user.AccessDefinition{"test": {APIID: "test", Versions: []string{"v1"}}} - session.OrgID = orgID - - buildAndLoadAPI(func(spec *APISpec) { - spec.UseBasicAuth = true - spec.BasicAuth.DisableCaching = cacheDisabled - spec.UseKeylessAccess = false - spec.Proxy.ListenPath = "/" - spec.OrgID = orgID - }) - - return session -} - func TestBasicAuth(t *testing.T) { ts := newTykTestServer() defer ts.Close()