-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: Move ownership verify into separate file
* Add test that uses same data as lb * Add and update test fixture outputs Signed-off-by: Mahendra Paipuri <[email protected]>
- Loading branch information
1 parent
96b6386
commit 034ca18
Showing
14 changed files
with
261 additions
and
131 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package http | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
"reflect" | ||
"strings" | ||
|
||
"github.com/go-kit/log" | ||
"github.com/go-kit/log/level" | ||
"github.com/mahendrapaipuri/ceems/pkg/api/base" | ||
) | ||
|
||
// VerifyOwnership returns true if user is the owner of queried units | ||
func VerifyOwnership(user string, uuids []string, db *sql.DB, logger log.Logger) bool { | ||
// If there is no active DB conn or if uuids is empty, return | ||
if db == nil || len(uuids) == 0 { | ||
return true | ||
} | ||
|
||
level.Debug(logger). | ||
Log("msg", "UUIDs in query", "user", user, "queried_uuids", strings.Join(uuids, ",")) | ||
|
||
// First get a list of projects that user is part of | ||
rows, err := db.Query( | ||
fmt.Sprintf("SELECT DISTINCT project FROM %s WHERE usr = ?", base.UsageDBTableName), | ||
user, | ||
) | ||
if err != nil { | ||
level.Warn(logger). | ||
Log("msg", "Failed to get user projects. Allowing query", "user", user, | ||
"queried_uuids", strings.Join(uuids, ","), "err", err, | ||
) | ||
return false | ||
} | ||
|
||
// Scan project rows | ||
var projects []string | ||
var project string | ||
for rows.Next() { | ||
if err := rows.Scan(&project); err != nil { | ||
continue | ||
} | ||
projects = append(projects, project) | ||
} | ||
|
||
// If no projects found, return. This should not be the case and if it happens | ||
// something is wrong. Spit a warning log | ||
if len(projects) == 0 { | ||
level.Warn(logger). | ||
Log("msg", "No user projects found. Query unauthorized", "user", user, | ||
"queried_uuids", strings.Join(uuids, ","), "err", err, | ||
) | ||
return false | ||
} | ||
|
||
// Make a query and query args. Query args must be converted to slice of interfaces | ||
// and it is sql driver's responsibility to cast them to proper types | ||
query := fmt.Sprintf( | ||
"SELECT uuid FROM %s WHERE project IN (%s) AND uuid IN (%s)", | ||
base.UnitsDBTableName, | ||
strings.Join(strings.Split(strings.Repeat("?", len(projects)), ""), ","), | ||
strings.Join(strings.Split(strings.Repeat("?", len(uuids)), ""), ","), | ||
) | ||
queryData := islice(append(projects, uuids...)) | ||
|
||
// Make query. If query fails for any reason, we allow request to avoid false negatives | ||
rows, err = db.Query(query, queryData...) | ||
if err != nil { | ||
level.Warn(logger). | ||
Log("msg", "Failed to check uuid ownership. Query unauthorized", "user", user, "query", query, | ||
"user_projects", strings.Join(projects, ","), "queried_uuids", strings.Join(uuids, ","), | ||
"err", err, | ||
) | ||
return false | ||
} | ||
defer rows.Close() | ||
|
||
// Get number of rows returned by query | ||
uuidCount := 0 | ||
for rows.Next() { | ||
uuidCount++ | ||
} | ||
|
||
// If returned number of UUIDs is not same as queried UUIDs, user is attempting | ||
// to query for jobs of other user | ||
if uuidCount != len(uuids) { | ||
level.Debug(logger). | ||
Log("msg", "Unauthorized query", "user", user, "user_projects", strings.Join(projects, ","), | ||
"queried_uuids", len(uuids), "found_uuids", uuidCount, | ||
) | ||
return false | ||
} | ||
return true | ||
} | ||
|
||
// Convert a slice of types into slice of interfaces | ||
func islice(x interface{}) []interface{} { | ||
xv := reflect.ValueOf(x) | ||
out := make([]interface{}, xv.Len()) | ||
for i := range out { | ||
out[i] = xv.Index(i).Interface() | ||
} | ||
return out | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package http | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/go-kit/log" | ||
) | ||
|
||
// Same as the one in lb/frontend/middleware_test.go | ||
func setupMockDB(d string) (*sql.DB, string) { | ||
dbPath := filepath.Join(d, "test.db") | ||
db, err := sql.Open("sqlite3", dbPath) | ||
if err != nil { | ||
fmt.Printf("failed to create DB") | ||
} | ||
|
||
stmts := ` | ||
PRAGMA foreign_keys=OFF; | ||
BEGIN TRANSACTION; | ||
CREATE TABLE units ( | ||
"id" integer not null primary key, | ||
"uuid" text, | ||
"project" text, | ||
"usr" text | ||
); | ||
INSERT INTO units VALUES(1,'1479763', 'prj1', 'usr1'); | ||
INSERT INTO units VALUES(2,'1481508', 'prj1', 'usr2'); | ||
INSERT INTO units VALUES(3,'1479765', 'prj2', 'usr2'); | ||
INSERT INTO units VALUES(4,'1481510', 'prj3', 'usr3'); | ||
CREATE TABLE usage ( | ||
"id" integer not null primary key, | ||
"project" text, | ||
"usr" text | ||
); | ||
INSERT INTO usage VALUES(1, 'prj1', 'usr1'); | ||
INSERT INTO usage VALUES(2, 'prj1', 'usr2'); | ||
INSERT INTO usage VALUES(3, 'prj2', 'usr2'); | ||
INSERT INTO usage VALUES(4, 'prj3', 'usr3'); | ||
COMMIT; | ||
` | ||
_, err = db.Exec(stmts) | ||
if err != nil { | ||
fmt.Printf("failed to insert mock data into DB: %s", err) | ||
} | ||
return db, dbPath | ||
} | ||
|
||
func TestVerifyOwnership(t *testing.T) { | ||
db, _ := setupMockDB(t.TempDir()) | ||
|
||
tests := []struct { | ||
name string | ||
uuids []string | ||
user string | ||
verify bool | ||
}{ | ||
{ | ||
name: "forbid due to mismatch uuid", | ||
uuids: []string{"1479765", "1481510"}, | ||
user: "usr1", | ||
verify: false, | ||
}, | ||
{ | ||
name: "forbid due to missing project", | ||
uuids: []string{"123", "345"}, | ||
user: "usr1", | ||
verify: false, | ||
}, | ||
{ | ||
name: "forbid due to missing header", | ||
uuids: []string{"123", "345"}, | ||
user: "", | ||
verify: false, | ||
}, | ||
{ | ||
name: "pass due to correct uuid", | ||
uuids: []string{"1479763"}, | ||
user: "usr1", | ||
verify: true, | ||
}, | ||
{ | ||
name: "pass due to uuid from same project", | ||
uuids: []string{"1481508"}, | ||
user: "usr1", | ||
verify: true, | ||
}, | ||
{ | ||
name: "pass due to no uuid", | ||
uuids: []string{}, | ||
user: "usr3", | ||
verify: true, | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
result := VerifyOwnership(test.user, test.uuids, db, log.NewNopLogger()) | ||
|
||
if result != test.verify { | ||
t.Errorf("%s: expected %t, got %t", test.name, test.verify, result) | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"status":"error","errorType":"unauthorized","error":"user do not have permissions on uuids"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"status":"success","data":{"user":"usr1","uuids":["1479763","1479765"],"verfiy":true}} |
Oops, something went wrong.