mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02: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)
|
# v5 stuff, does absolutely nothing on master (aka: you can delete this)
|
||||||
EXTRA_CLAIMS='{"permissions": ["core.read"], "verified": false}'
|
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"]}'
|
GUEST_CLAIMS='{"permissions": ["core.read"]}'
|
||||||
PROTECTED_CLAIMS="permissions,verified"
|
PROTECTED_CLAIMS="permissions,verified"
|
||||||
|
4
.github/workflows/auth-hurl.yml
vendored
4
.github/workflows/auth-hurl.yml
vendored
@ -53,8 +53,12 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
POSTGRES_SERVER: localhost
|
POSTGRES_SERVER: localhost
|
||||||
FIRST_USER_CLAIMS: '{"permissions": ["users.read"]}'
|
FIRST_USER_CLAIMS: '{"permissions": ["users.read"]}'
|
||||||
|
KEIBI_APIKEY_HURL: 1234apikey
|
||||||
|
KEIBI_APIKEY_HURL_CLAIMS: '{"permissions": ["apikeys.write", "apikeys.read"]}'
|
||||||
|
|
||||||
|
|
||||||
- name: Show logs
|
- name: Show logs
|
||||||
|
if: failure()
|
||||||
working-directory: ./auth
|
working-directory: ./auth
|
||||||
run: cat logs
|
run: cat logs
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ type ApiKeyWToken struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ApiKeyDto 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"`
|
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"
|
// @Failure 422 {object} KError "Invalid create body"
|
||||||
// @Router /keys [post]
|
// @Router /keys [post]
|
||||||
func (h *Handler) CreateApiKey(c echo.Context) error {
|
func (h *Handler) CreateApiKey(c echo.Context) error {
|
||||||
|
err := CheckPermissions(c, []string{"apikeys.write"})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
var req ApiKeyDto
|
var req ApiKeyDto
|
||||||
err := c.Bind(&req)
|
err = c.Bind(&req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return echo.NewHTTPError(http.StatusUnprocessableEntity, err.Error())
|
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"
|
// @Failure 422 {object} KError "Invalid id format"
|
||||||
// @Router /keys [delete]
|
// @Router /keys [delete]
|
||||||
func (h *Handler) DeleteApiKey(c echo.Context) error {
|
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"))
|
id, err := uuid.Parse(c.Param("id"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return echo.NewHTTPError(422, "Invalid id given: not an uuid")
|
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]
|
// @Success 200 {object} Page[ApiKey]
|
||||||
// @Router /keys [get]
|
// @Router /keys [get]
|
||||||
func (h *Handler) ListApiKey(c echo.Context) error {
|
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())
|
dbkeys, err := h.db.ListApiKeys(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/zoriya/kyoo/keibi/dbc"
|
"github.com/zoriya/kyoo/keibi/dbc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -103,11 +104,14 @@ func LoadConfiguration(db *dbc.Queries) (*Configuration, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, env := range os.Environ() {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
v := strings.Split(env, "=")
|
|
||||||
name := strings.TrimPrefix(v[0], "KEIBI_APIKEY_")
|
name := strings.TrimPrefix(v[0], "KEIBI_APIKEY_")
|
||||||
cstr := os.Getenv(fmt.Sprintf("KEIBI_APIKEY_%s_CLAIMS", name))
|
cstr := os.Getenv(fmt.Sprintf("KEIBI_APIKEY_%s_CLAIMS", name))
|
||||||
|
|
||||||
@ -117,10 +121,14 @@ func LoadConfiguration(db *dbc.Queries) (*Configuration, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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{
|
ret.EnvApiKeys[name] = ApiKeyWToken{
|
||||||
ApiKey: ApiKey{
|
ApiKey: ApiKey{
|
||||||
|
Id: uuid.New(),
|
||||||
Name: name,
|
Name: name,
|
||||||
Claims: claims,
|
Claims: claims,
|
||||||
},
|
},
|
||||||
|
@ -162,7 +162,7 @@ func (h *Handler) TokenToJwt(next echo.HandlerFunc) echo.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if jwt != nil {
|
if jwt != nil {
|
||||||
c.Request().Header.Set("Authorization", *jwt)
|
c.Request().Header.Set("Authorization", fmt.Sprintf("Bearer %s", *jwt))
|
||||||
}
|
}
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
@ -236,7 +236,7 @@ func main() {
|
|||||||
|
|
||||||
r.GET("/keys", h.ListApiKey)
|
r.GET("/keys", h.ListApiKey)
|
||||||
r.POST("/keys", h.CreateApiKey)
|
r.POST("/keys", h.CreateApiKey)
|
||||||
r.DELETE("/keys", h.DeleteApiKey)
|
r.DELETE("/keys/:id", h.DeleteApiKey)
|
||||||
|
|
||||||
g.GET("/jwt", h.CreateJwt)
|
g.GET("/jwt", h.CreateJwt)
|
||||||
e.GET("/.well-known/jwks.json", h.GetJwks)
|
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_by integer not null references users(pk) on delete cascade,
|
||||||
created_at timestamptz not null default now()::timestamptz,
|
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;
|
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
|
@ -59,6 +59,11 @@ func CheckPermissions(c echo.Context, perms []string) error {
|
|||||||
if !ok{
|
if !ok{
|
||||||
return echo.NewHTTPError(401, "Not logged in")
|
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)
|
claims, ok := token.Claims.(jwt.MapClaims)
|
||||||
if !ok {
|
if !ok {
|
||||||
return echo.NewHTTPError(403, "Could not retrieve claims")
|
return echo.NewHTTPError(403, "Could not retrieve claims")
|
||||||
@ -68,8 +73,6 @@ func CheckPermissions(c echo.Context, perms []string) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return echo.NewHTTPError(403, fmt.Sprintf("Missing permissions: %s.", ", "))
|
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)
|
permissions_int, ok := permissions_claims.([]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
return echo.NewHTTPError(403, "Invalid permission claim.")
|
return echo.NewHTTPError(403, "Invalid permission claim.")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user