mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-23 17:52:36 -04:00
Add hurl tests for apikeys
This commit is contained in:
parent
e8acb31834
commit
dcbbb6352a
@ -99,6 +99,6 @@ RABBITMQ_DEFAULT_PASS=aohohunuhouhuhhoahothonseuhaoensuthoaentsuhha
|
||||
|
||||
# v5 stuff, does absolutely nothing on master (aka: you can delete this)
|
||||
EXTRA_CLAIMS='{"permissions": ["core.read"], "verified": false}'
|
||||
FIRST_USER_CLAIMS='{"permissions": ["users.read", "users.write", "users.delete", "core.read"], "verified": true}'
|
||||
FIRST_USER_CLAIMS='{"permissions": ["users.read", "users.write", "apikeys.read", "apikeys.write", "users.delete", "core.read", "core.write"], "verified": true}'
|
||||
GUEST_CLAIMS='{"permissions": ["core.read"]}'
|
||||
PROTECTED_CLAIMS="permissions,verified"
|
||||
|
4
.github/workflows/auth-hurl.yml
vendored
4
.github/workflows/auth-hurl.yml
vendored
@ -53,8 +53,12 @@ jobs:
|
||||
env:
|
||||
POSTGRES_SERVER: localhost
|
||||
FIRST_USER_CLAIMS: '{"permissions": ["users.read"]}'
|
||||
KEIBI_APIKEY_HURL: 1234apikey
|
||||
KEIBI_APIKEY_HURL_CLAIMS: '{"permissions": ["apikeys.write", "apikeys.read"]}'
|
||||
|
||||
|
||||
- name: Show logs
|
||||
if: failure()
|
||||
working-directory: ./auth
|
||||
run: cat logs
|
||||
|
||||
|
@ -32,7 +32,7 @@ type ApiKeyWToken struct {
|
||||
}
|
||||
|
||||
type ApiKeyDto struct {
|
||||
Name string `json:"name" example:"my-app" validate:"alpha"`
|
||||
Name string `json:"name" example:"myapp" validate:"alpha"`
|
||||
Claims jwt.MapClaims `json:"claims" example:"isAdmin: true"`
|
||||
}
|
||||
|
||||
@ -61,8 +61,13 @@ func MapDbKey(key *dbc.Apikey) ApiKeyWToken {
|
||||
// @Failure 422 {object} KError "Invalid create body"
|
||||
// @Router /keys [post]
|
||||
func (h *Handler) CreateApiKey(c echo.Context) error {
|
||||
err := CheckPermissions(c, []string{"apikeys.write"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var req ApiKeyDto
|
||||
err := c.Bind(&req)
|
||||
err = c.Bind(&req)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusUnprocessableEntity, err.Error())
|
||||
}
|
||||
@ -104,6 +109,11 @@ func (h *Handler) CreateApiKey(c echo.Context) error {
|
||||
// @Failure 422 {object} KError "Invalid id format"
|
||||
// @Router /keys [delete]
|
||||
func (h *Handler) DeleteApiKey(c echo.Context) error {
|
||||
err := CheckPermissions(c, []string{"apikeys.write"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
id, err := uuid.Parse(c.Param("id"))
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(422, "Invalid id given: not an uuid")
|
||||
@ -127,6 +137,11 @@ func (h *Handler) DeleteApiKey(c echo.Context) error {
|
||||
// @Success 200 {object} Page[ApiKey]
|
||||
// @Router /keys [get]
|
||||
func (h *Handler) ListApiKey(c echo.Context) error {
|
||||
err := CheckPermissions(c, []string{"apikeys.read"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dbkeys, err := h.db.ListApiKeys(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/zoriya/kyoo/keibi/dbc"
|
||||
)
|
||||
|
||||
@ -103,11 +104,14 @@ func LoadConfiguration(db *dbc.Queries) (*Configuration, error) {
|
||||
}
|
||||
|
||||
for _, env := range os.Environ() {
|
||||
if !strings.HasPrefix(env, "KEIBI_APIKEY_") || strings.HasSuffix(env, "_CLAIMS") {
|
||||
if !strings.HasPrefix(env, "KEIBI_APIKEY_"){
|
||||
continue
|
||||
}
|
||||
v := strings.Split(env, "=")
|
||||
if strings.HasSuffix(v[0], "_CLAIMS") {
|
||||
continue
|
||||
}
|
||||
|
||||
v := strings.Split(env, "=")
|
||||
name := strings.TrimPrefix(v[0], "KEIBI_APIKEY_")
|
||||
cstr := os.Getenv(fmt.Sprintf("KEIBI_APIKEY_%s_CLAIMS", name))
|
||||
|
||||
@ -117,10 +121,14 @@ func LoadConfiguration(db *dbc.Queries) (*Configuration, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("missing claims env var KEIBI_APIKEY_%s_CLAIMS", name)
|
||||
}
|
||||
|
||||
name = strings.ToLower(name)
|
||||
ret.EnvApiKeys[name] = ApiKeyWToken{
|
||||
ApiKey: ApiKey{
|
||||
Id: uuid.New(),
|
||||
Name: name,
|
||||
Claims: claims,
|
||||
},
|
||||
|
@ -162,7 +162,7 @@ func (h *Handler) TokenToJwt(next echo.HandlerFunc) echo.HandlerFunc {
|
||||
}
|
||||
|
||||
if jwt != nil {
|
||||
c.Request().Header.Set("Authorization", *jwt)
|
||||
c.Request().Header.Set("Authorization", fmt.Sprintf("Bearer %s", *jwt))
|
||||
}
|
||||
return next(c)
|
||||
}
|
||||
@ -236,7 +236,7 @@ func main() {
|
||||
|
||||
r.GET("/keys", h.ListApiKey)
|
||||
r.POST("/keys", h.CreateApiKey)
|
||||
r.DELETE("/keys", h.DeleteApiKey)
|
||||
r.DELETE("/keys/:id", h.DeleteApiKey)
|
||||
|
||||
g.GET("/jwt", h.CreateJwt)
|
||||
e.GET("/.well-known/jwks.json", h.GetJwks)
|
||||
|
@ -9,7 +9,7 @@ create table apikeys(
|
||||
|
||||
created_by integer not null references users(pk) on delete cascade,
|
||||
created_at timestamptz not null default now()::timestamptz,
|
||||
last_used timestamptz not null default now()::temistamptz
|
||||
last_used timestamptz not null default now()::timestamptz
|
||||
);
|
||||
|
||||
commit;
|
||||
|
58
auth/tests/apikey.hurl
Normal file
58
auth/tests/apikey.hurl
Normal file
@ -0,0 +1,58 @@
|
||||
# perm check
|
||||
POST {{host}}/keys
|
||||
{
|
||||
"name": "dryflower",
|
||||
"claims": {
|
||||
"isAdmin": true,
|
||||
"permssions": ["core.read"]
|
||||
}
|
||||
}
|
||||
HTTP 401
|
||||
|
||||
POST {{host}}/keys
|
||||
# this is created from the gh workflow file's env var
|
||||
X-API-KEY: hurl-1234apikey
|
||||
{
|
||||
"name": "dryflower",
|
||||
"claims": {
|
||||
"isAdmin": true,
|
||||
"permssions": ["core.read"]
|
||||
}
|
||||
}
|
||||
HTTP 201
|
||||
[Captures]
|
||||
token: jsonpath "$.token"
|
||||
|
||||
GET {{host}}/jwt
|
||||
Authorization: Bearer {{token}}
|
||||
HTTP 200
|
||||
[Captures]
|
||||
id: jsonpath "$.id"
|
||||
jwt: jsonpath "$.token"
|
||||
|
||||
# Duplicates email
|
||||
POST {{host}}/keys
|
||||
X-API-KEY: hurl-1234apikey
|
||||
{
|
||||
"name": "dryflower",
|
||||
"claims": {
|
||||
"isAdmin": true,
|
||||
"permssions": ["core.read"]
|
||||
}
|
||||
}
|
||||
HTTP 409
|
||||
|
||||
# List
|
||||
GET {{host}}/keys
|
||||
Authorization: Bearer {{token}}
|
||||
HTTP 200
|
||||
[Asserts]
|
||||
jsonpath "$.items[0].id" == {{id}}
|
||||
jsonpath "$.items[0].name" == "dryflower"
|
||||
jsonpath "$.items[0].claims.permissions" contains "core.read"
|
||||
|
||||
|
||||
|
||||
DELETE {{host}}/keys/{{id}}
|
||||
Authorization: Bearer {{jwt}}
|
||||
HTTP 200
|
@ -56,7 +56,12 @@ func GetCurrentSessionId(c echo.Context) (uuid.UUID, error) {
|
||||
|
||||
func CheckPermissions(c echo.Context, perms []string) error {
|
||||
token, ok := c.Get("user").(*jwt.Token)
|
||||
if !ok {
|
||||
if !ok{
|
||||
return echo.NewHTTPError(401, "Not logged in")
|
||||
}
|
||||
sub, err := token.Claims.GetSubject()
|
||||
// ignore guests
|
||||
if err != nil || sub == "00000000-0000-0000-0000-000000000000" {
|
||||
return echo.NewHTTPError(401, "Not logged in")
|
||||
}
|
||||
claims, ok := token.Claims.(jwt.MapClaims)
|
||||
@ -68,8 +73,6 @@ func CheckPermissions(c echo.Context, perms []string) error {
|
||||
if !ok {
|
||||
return echo.NewHTTPError(403, fmt.Sprintf("Missing permissions: %s.", ", "))
|
||||
}
|
||||
fmt.Printf("%v\n", permissions_claims)
|
||||
fmt.Printf("%t\n", permissions_claims)
|
||||
permissions_int, ok := permissions_claims.([]any)
|
||||
if !ok {
|
||||
return echo.NewHTTPError(403, "Invalid permission claim.")
|
||||
|
Loading…
x
Reference in New Issue
Block a user