From 306199c5f118441140e158ff5d369187b4eefe22 Mon Sep 17 00:00:00 2001 From: Waldemar Hummer Date: Wed, 24 Jul 2019 14:51:00 +0200 Subject: [PATCH] add per-event basicAuth config --- index.js | 33 ++++++++++++++++++++++++--------- readme.md | 20 ++++++++++++++++++++ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index d4a8986..7a26af0 100644 --- a/index.js +++ b/index.js @@ -73,31 +73,46 @@ module.exports = class SetupBasicAuthentication { } addAuthorizerFunctionToPrivateFunctions() { - // for each function which is marked as 'private', set the basic authenticator - // if it doesn't have a custom authenticator yet - Object.keys(this.serverless.service.functions).forEach((functionName) => { + // For each function which is marked as 'private', set the basic authenticator + // if it doesn't have a custom authenticator yet. + + // If any of the functions' events is marked with the flag "basicAuth", then + // only the events with basicAuth=true are configured with basic auth. + + const functions = this.serverless.service.functions || []; + + const hasAnyBasicAuthConfig = Object.keys(functions).reduce( + (result, func) => result || Object.keys(func.events || []).reduce( + (hasBasicAuthConfig, event) => hasBasicAuthConfig || (event.http && 'basicAuth' in event.http), + false), + false); + + Object.keys(functions).forEach((functionName) => { // ignore our own function if (functionName === 'basicAuthenticator') { return; } // get all function configs - const fnctn = this.serverless.service.functions[functionName]; + const fnctn = functions[functionName]; // check if any of the http events is marked as private, and if that event // also doesn't have a custom authorizer already, apply our authenticator Object.keys(fnctn.events).forEach((fnctnEvent) => { // if http doesn't exist, skip - if (!('http' in this.serverless.service.functions[functionName].events[fnctnEvent])) { + if (!fnctn.events[fnctnEvent].http) { return; } if ( - this.serverless.service.functions[functionName].events[fnctnEvent].http != null - && this.serverless.service.functions[functionName].events[fnctnEvent].http.private === true - && this.serverless.service.functions[functionName].events[fnctnEvent].http.authorizer == null + !fnctn.events[fnctnEvent].http.authorizer && + ( + fnctn.events[fnctnEvent].http.private === true || + !hasAnyBasicAuthConfig || + fnctn.events[fnctnEvent].http.basicAuth === true + ) ) { - this.serverless.service.functions[functionName].events[fnctnEvent].http.authorizer = { + fnctn.events[fnctnEvent].http.authorizer = { name: 'basicAuthenticator', identitySource: '', // this is only valid if we set cache ttl to 0 resultTtlInSeconds: 0, diff --git a/readme.md b/readme.md index 56ca974..b1d8230 100644 --- a/readme.md +++ b/readme.md @@ -58,6 +58,26 @@ functions: private: true ``` +For more fine-grained control over which functions are enabled for basic auth, use the `basicAuth` attribute on events. If any of the functions' events is marked with the flag `basicAuth`, then only the events with `basicAuth=true` are configured with basic auth. + +``` +functions: + foo: + handler: handler.foo + events: + - http: + path: foo + method: get + basicAuth: true # Basic auth enabled + bar: + handler: handler.bar + events: + - http: + path: bar + method: get + private: true # Basic auth not enabled (may use some other default authorizer) +``` + To send the correct header so that browsers will prompt for username and password, add a `GatewayResponse` to the `resources`: ```