From fac3431375d0fe221f8725b46f1e95084f9e2f81 Mon Sep 17 00:00:00 2001 From: garrettmills Date: Sun, 18 Oct 2020 21:07:42 -0500 Subject: [PATCH] Add api authorization logging --- .../middleware/api/Permission.middleware.js | 16 ++++++++++++++-- .../middleware/auth/APIRoute.middleware.js | 10 ++++++++++ app/services/activity.service.js | 1 + 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/app/routing/middleware/api/Permission.middleware.js b/app/routing/middleware/api/Permission.middleware.js index 5e74b39..72bf56a 100644 --- a/app/routing/middleware/api/Permission.middleware.js +++ b/app/routing/middleware/api/Permission.middleware.js @@ -8,23 +8,30 @@ class PermissionMiddleware extends Middleware { async test(req, res, next, { check }) { const Policy = this.models.get('iam:Policy') + req.additional_api_log_data.permission_check = check + // If the request was authorized using an OAuth2 bearer token, // make sure the associated client has permission to access this endpoint. if ( req?.oauth?.client ) { if ( !req.oauth.client.can(check) ) { const reason = 'oauth-permission-fail' - await this.activity.api_access_denial({ + const fail_activity = await this.activity.api_access_denial({ req, reason, check, oauth_client_id: req.oauth.client.uuid, }) + req.additional_api_log_data.permission_check_succeeded = false + req.additional_api_log_data.permission_check_activity_id = fail_activity.id + return res.status(401) .message('Insufficient permissions (OAuth2 Client).') .api() } + req.additional_api_log_data.permission_check_succeeded = true + // If the oauth2 client has this permission, then allow the request to continue, // even if the user does not. // OAuth2Clients need to be able to query users via the API. @@ -38,13 +45,18 @@ class PermissionMiddleware extends Middleware { if ( policy_denied || (!req.user.can(check) && !policy_access) ) { // Record the failed API access const reason = policy_denied ? 'iam-denial' : (!req.user.can(check) ? 'user-permission-fail' : 'iam-not-granted') - await this.activity.api_access_denial({ req, reason, check }) + const fail_activity = await this.activity.api_access_denial({ req, reason, check }) + + req.additional_api_log_data.permission_check_succeeded = false + req.additional_api_log_data.permission_check_reason = reason + req.additional_api_log_data.permission_check_activity_id = fail_activity.id return res.status(401) .message('Insufficient permissions.') .api() } + req.additional_api_log_data.permission_check_succeeded = true return next() } } diff --git a/app/routing/middleware/auth/APIRoute.middleware.js b/app/routing/middleware/auth/APIRoute.middleware.js index 8da4f35..a92ea99 100644 --- a/app/routing/middleware/auth/APIRoute.middleware.js +++ b/app/routing/middleware/auth/APIRoute.middleware.js @@ -6,14 +6,21 @@ class APIRouteMiddleware extends Middleware { } async test(req, res, next, { allow_token = true, allow_user = true }) { + if ( !req.additional_api_log_data ) req.additional_api_log_data = {} + // First, check if there is a user in the session. if ( allow_user && req.user ) { + req.additional_api_log_data.authorized_by = 'user' return next() } else if ( allow_token ) { if ( !req.oauth ) req.oauth = {} + req.additional_api_log_data.attempted_token_auth = true return req.app.oauth2.authorise()(req, res, async e => { if ( e ) return next(e) + + req.additional_api_log_data.authorized_by = 'token' + // Look up the OAuth2 client an inject it into the route if ( req.user && req.user.id ) { const User = this.models.get('auth:User') @@ -44,6 +51,9 @@ class APIRouteMiddleware extends Middleware { .message('This OAuth2 client is no longer authorized.') .api() + req.additional_api_log_data.token_client_id = client.uuid + req.additional_api_log_data.token = bearer + req.oauth.token = token req.oauth.client = client } else diff --git a/app/services/activity.service.js b/app/services/activity.service.js index 4f59b19..db5efb4 100644 --- a/app/services/activity.service.js +++ b/app/services/activity.service.js @@ -36,6 +36,7 @@ class ActivityService extends Service { } await activity.save() + return activity } async mfa_enable({ req }) {