feat: add shared backend authorization seams
This commit is contained in:
1 parent
d0207fcebe
commit
48dd5d07c8
9 files changed
+1086
No files matched your search
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"version": 1,
|
||||
"cookieName": "zhinian_session",
|
||||
"cases": [
|
||||
{
|
||||
"name": "optional unconfigured application access uses the local administrator",
|
||||
"state": { "required": false, "configured": false },
|
||||
"requirement": "app",
|
||||
"resolverOutcome": "not_called",
|
||||
"expected": { "outcome": "authenticated", "status": 200, "role": "super_admin", "authMode": "admin" }
|
||||
},
|
||||
{
|
||||
"name": "required unconfigured authentication fails with service unavailable",
|
||||
"state": { "required": true, "configured": false },
|
||||
"requirement": "app",
|
||||
"resolverOutcome": "not_called",
|
||||
"expected": { "outcome": "configuration_error", "status": 503 }
|
||||
},
|
||||
{
|
||||
"name": "required configured request without a cookie is unauthenticated",
|
||||
"state": { "required": true, "configured": true },
|
||||
"requirement": "app",
|
||||
"resolverOutcome": "not_called",
|
||||
"expected": { "outcome": "unauthenticated", "status": 401 }
|
||||
},
|
||||
{
|
||||
"name": "an invalid session falls back locally only when authentication is optional",
|
||||
"state": { "required": false, "configured": true },
|
||||
"requirement": "super_admin",
|
||||
"resolverOutcome": "unauthenticated",
|
||||
"expected": { "outcome": "authenticated", "status": 200, "role": "super_admin", "authMode": "admin" }
|
||||
},
|
||||
{
|
||||
"name": "database refreshed user is allowed application access",
|
||||
"state": { "required": true, "configured": true },
|
||||
"requirement": "app",
|
||||
"resolverOutcome": "authenticated",
|
||||
"session": { "authMode": "user", "role": "user" },
|
||||
"expected": { "outcome": "authenticated", "status": 200, "role": "user", "authMode": "user" }
|
||||
},
|
||||
{
|
||||
"name": "ordinary user cannot access administration",
|
||||
"state": { "required": true, "configured": true },
|
||||
"requirement": "admin",
|
||||
"resolverOutcome": "authenticated",
|
||||
"session": { "authMode": "user", "role": "user" },
|
||||
"expected": { "outcome": "forbidden", "status": 403 }
|
||||
},
|
||||
{
|
||||
"name": "organization administrator in admin mode can access administration",
|
||||
"state": { "required": true, "configured": true },
|
||||
"requirement": "admin",
|
||||
"resolverOutcome": "authenticated",
|
||||
"session": { "authMode": "admin", "role": "organization_admin" },
|
||||
"expected": { "outcome": "authenticated", "status": 200, "role": "organization_admin", "authMode": "admin" }
|
||||
},
|
||||
{
|
||||
"name": "admin role without admin login mode cannot access administration",
|
||||
"state": { "required": true, "configured": true },
|
||||
"requirement": "admin",
|
||||
"resolverOutcome": "authenticated",
|
||||
"session": { "authMode": "user", "role": "organization_admin" },
|
||||
"expected": { "outcome": "forbidden", "status": 403 }
|
||||
},
|
||||
{
|
||||
"name": "organization administrator cannot access super administration",
|
||||
"state": { "required": true, "configured": true },
|
||||
"requirement": "super_admin",
|
||||
"resolverOutcome": "authenticated",
|
||||
"session": { "authMode": "admin", "role": "organization_admin" },
|
||||
"expected": { "outcome": "forbidden", "status": 403 }
|
||||
},
|
||||
{
|
||||
"name": "super administrator can access super administration",
|
||||
"state": { "required": true, "configured": true },
|
||||
"requirement": "super_admin",
|
||||
"resolverOutcome": "authenticated",
|
||||
"session": { "authMode": "admin", "role": "super_admin" },
|
||||
"expected": { "outcome": "authenticated", "status": 200, "role": "super_admin", "authMode": "admin" }
|
||||
},
|
||||
{
|
||||
"name": "resolver infrastructure failure is not disguised as authentication denial",
|
||||
"state": { "required": true, "configured": true },
|
||||
"requirement": "app",
|
||||
"resolverOutcome": "infrastructure_error",
|
||||
"expected": { "outcome": "infrastructure_error", "status": 500 }
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"version": 1,
|
||||
"apiKeys": " alpha : alpha-secret ,\n bare-secret\n, invalid-only-id: , :invalid-only-key, beta: beta-secret ",
|
||||
"clients": [
|
||||
{ "id": "alpha", "key": "alpha-secret" },
|
||||
{ "id": "default", "key": "bare-secret" },
|
||||
{ "id": "beta", "key": "beta-secret" }
|
||||
],
|
||||
"authenticationCases": [
|
||||
{
|
||||
"name": "case insensitive bearer authenticates",
|
||||
"headers": { "authorization": "bEaReR alpha-secret " },
|
||||
"expected": { "client": { "id": "alpha", "key": "alpha-secret" }, "owner": "api:alpha" }
|
||||
},
|
||||
{
|
||||
"name": "legacy api key header authenticates",
|
||||
"headers": { "x-zhinian-api-key": "bare-secret" },
|
||||
"expected": { "client": { "id": "default", "key": "bare-secret" }, "owner": "api:default" }
|
||||
},
|
||||
{
|
||||
"name": "bearer takes precedence over legacy header",
|
||||
"headers": { "authorization": "Bearer beta-secret", "x-zhinian-api-key": "alpha-secret" },
|
||||
"expected": { "client": { "id": "beta", "key": "beta-secret" }, "owner": "api:beta" }
|
||||
},
|
||||
{
|
||||
"name": "invalid bearer does not fall back to legacy header",
|
||||
"headers": { "authorization": "Bearer wrong", "x-zhinian-api-key": "alpha-secret" },
|
||||
"error": { "status": 401, "message": "Invalid API key." }
|
||||
},
|
||||
{
|
||||
"name": "missing credentials are typed",
|
||||
"headers": {},
|
||||
"error": { "status": 401, "message": "Missing API key." }
|
||||
},
|
||||
{
|
||||
"name": "different length credential is invalid",
|
||||
"headers": { "authorization": "Bearer x" },
|
||||
"error": { "status": 401, "message": "Invalid API key." }
|
||||
}
|
||||
],
|
||||
"ownerCases": [
|
||||
{ "id": "tenant / 中文!?", "owner": "api:tenant_" },
|
||||
{ "id": "", "owner": "api:unknown" },
|
||||
{ "id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "owner": "api:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "maxPartLength": 96 },
|
||||
{ "id": "safe.ID:@-42", "owner": "api:safe.ID:@-42" }
|
||||
],
|
||||
"workerCases": [
|
||||
{
|
||||
"name": "development permits an unconfigured token",
|
||||
"production": false,
|
||||
"configuredToken": " ",
|
||||
"headers": {},
|
||||
"allowed": true
|
||||
},
|
||||
{
|
||||
"name": "production rejects an unconfigured token",
|
||||
"production": true,
|
||||
"configuredToken": " ",
|
||||
"headers": {},
|
||||
"error": { "status": 500, "message": "Worker token is not configured." }
|
||||
},
|
||||
{
|
||||
"name": "worker header authenticates",
|
||||
"production": true,
|
||||
"configuredToken": " worker-secret ",
|
||||
"headers": { "x-zhinian-worker-token": "worker-secret" },
|
||||
"allowed": true
|
||||
},
|
||||
{
|
||||
"name": "worker header takes precedence over bearer",
|
||||
"production": true,
|
||||
"configuredToken": "worker-secret",
|
||||
"headers": { "x-zhinian-worker-token": "wrong", "authorization": "Bearer worker-secret" },
|
||||
"error": { "status": 401, "message": "Invalid worker token." }
|
||||
},
|
||||
{
|
||||
"name": "worker bearer is case insensitive",
|
||||
"production": true,
|
||||
"configuredToken": "worker-secret",
|
||||
"headers": { "authorization": "BEARER worker-secret" },
|
||||
"allowed": true
|
||||
},
|
||||
{
|
||||
"name": "invalid worker token is typed",
|
||||
"production": false,
|
||||
"configuredToken": "worker-secret",
|
||||
"headers": { "x-zhinian-worker-token": "x" },
|
||||
"error": { "status": 401, "message": "Invalid worker token." }
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user