feat(phase-2): workstream 5 — OPA Policy Engine
- policies/authz.rego: Rego policy with path normalisation and scope enforcement - policies/data/scopes.json: all 13 endpoint → scope mappings - src/middleware/opa.ts: OpaMiddleware with Wasm primary path + scopes.json fallback; exports createOpaMiddleware() and reloadOpaPolicy() for SIGHUP hot-reload - All four route files: opaMiddleware wired after authMiddleware - AuditController, OAuth2Service: manual scope checks removed (now centralised in OPA) - src/server.ts: SIGHUP handler calls reloadOpaPolicy() - docs/devops/environment-variables.md: POLICY_DIR documented - 38 new tests; 302/302 passing; opa.ts coverage 98.66% statements Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,6 @@ import {
|
||||
AuthenticationError,
|
||||
AuthorizationError,
|
||||
FreeTierLimitError,
|
||||
InsufficientScopeError,
|
||||
} from '../utils/errors.js';
|
||||
import { signToken, verifyToken, decodeToken, getTokenExpiresIn } from '../utils/jwt.js';
|
||||
import { verifySecret } from '../utils/crypto.js';
|
||||
@@ -214,14 +213,13 @@ export class OAuth2Service {
|
||||
/**
|
||||
* Introspects a token per RFC 7662.
|
||||
* Always returns 200; check the `active` field for validity.
|
||||
* Requires the caller to hold a token with `tokens:read` scope.
|
||||
* Scope enforcement (`tokens:read`) is handled upstream by OPA middleware.
|
||||
*
|
||||
* @param token - The JWT string to introspect.
|
||||
* @param callerPayload - The decoded payload of the calling agent's token (for scope check).
|
||||
* @param callerPayload - The decoded payload of the calling agent's token.
|
||||
* @param ipAddress - Client IP for audit logging.
|
||||
* @param userAgent - Client User-Agent for audit logging.
|
||||
* @returns The introspection response.
|
||||
* @throws InsufficientScopeError if the caller lacks `tokens:read` scope.
|
||||
*/
|
||||
async introspectToken(
|
||||
token: string,
|
||||
@@ -229,12 +227,6 @@ export class OAuth2Service {
|
||||
ipAddress: string,
|
||||
userAgent: string,
|
||||
): Promise<IIntrospectResponse> {
|
||||
// Check caller has tokens:read scope
|
||||
const callerScopes = callerPayload.scope.split(' ');
|
||||
if (!callerScopes.includes('tokens:read')) {
|
||||
throw new InsufficientScopeError('tokens:read');
|
||||
}
|
||||
|
||||
try {
|
||||
const payload = verifyToken(token, this.publicKey);
|
||||
const revoked = await this.tokenRepository.isRevoked(payload.jti);
|
||||
|
||||
Reference in New Issue
Block a user