Базовая аутентификация HTTP для CloudFront с помощью Lambda@Edge в NodeJS

#node.js #amazon-web-services #aws-lambda #amazon-cloudfront #aws-lambda-edge

Вопрос:

Я работаю над защитой статического веб-сайта с помощью имени пользователя и пароля. Я создал базовую HTTP-аутентификацию для CloudFront с помощью Lambda@Edge в NodeJS.

Я совершенно новичок в NodeJS. Сначала у меня были жестко закодированы имя пользователя и пароль, и это сработало должным образом.

 'use strict';
exports.handler = (event, context, callback) => {

    // Get request and request headers
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    // Configure authentication
    const authUser = 'user';
    const authPass = 'pass';

    // Construct the Basic Auth string
    const authString = 'Basic '   new Buffer(authUser   ':'   authPass).toString('base64');

    // Require Basic authentication
    if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) {
        const body = 'Unauthorized';
        const response = {
            status: '401',
            statusDescription: 'Unauthorized',
            body: body,
            headers: {
                'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}]
            },
        };
        callback(null, response);
    }

    // Continue request processing if authentication passed
    callback(null, request);
};
 

Я сохранил свои секреты в SSM и хочу получить их с помощью функции. Я протестировал этот фрагмент кода отдельно в Лямбда, и он возвращает учетные данные как выделенные.

 'use strict';
exports.handler = async (event, context, callback) => {
    const ssm = new (require('aws-sdk/clients/ssm'))();
    let userData = await ssm.getParameters({Names: ['website-user']}).promise();
    let userPass = await ssm.getParameters({Names: ['website-pass']}).promise();
    let user = userData.Parameters[0].Value;
    let pass = userPass.Parameters[0].Value;
    return {user, pass};
};
 

Но когда я сшиваю два, я получаю ОШИБКУ 503, запрос не может быть удовлетворен.
Кто-нибудь знает, что я могу делать не так? Спасибо вам за вашу помощь!

Полный код:

 'use strict';

exports.handler = async (event, context, callback) => {
    const ssm = new (require('aws-sdk/clients/ssm'))();
    let userData = await ssm.getParameters({Names: ['website-user']}).promise();
    let userPass = await ssm.getParameters({Names: ['website-pass']}).promise();
    let user = userData.Parameters[0].Value;
    let pass = userPass.Parameters[0].Value;

    // Get request and request headers
    const request = event.Records[0].cf.request;
    const headers = request.headers;

    // Construct the Basic Auth string
    let authString = 'Basic '   new Buffer(user   ':'   pass).toString('base64');

    // Require Basic authentication
    if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) {
        const body = 'Unauthorized';
        const response = {
            status: '401',
            statusDescription: 'Unauthorized',
            body: body,
            headers: {
                'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}]
            },
        };
        callback(null, response);
    }

    // Continue request processing if authentication passed
    callback(null, request);
};
 

Комментарии:

1. Я думаю, что вы не можете использовать async и callback вместе. Что произойдет, если вы сделаете return response или return request ?

2. Спасибо вам за ваш отзыв! Я попытался заменить callback на return response и return request , и я все еще получаю ту же ошибку.

3. @Jens ты подтолкнул меня в правильном направлении, и я исправил свою ошибку. Я опубликую решение в качестве ответа.

Ответ №1:

Прочитав об обещаниях, я смог устранить ошибку. Вот решение, которое сработало для меня:

 'use strict';

var AWS = require('aws-sdk');
AWS.config.update({ region: 'us-east-1' });
var ssm = new AWS.SSM();

function getParameter(param) {
  return new Promise(function (success, reject) {
    ssm.getParameter(param, function (err, data) {
      if (err) {
        reject(err);
      } else {
        success(data);
      }
    });
  });
};

exports.handler =  (event, context, callback) => {
    let request = event.Records[0].cf.request;
    let headers = request.headers;
    let user = {Name: 'user-path', WithDecryption: false};
    let pass = {Name: 'password-path', WithDecryption: false};
    let authUser;
    let authPass;
    var promises = [];
    promises.push(getParameter(user), getParameter(pass));
    
    Promise.all(promises)
    .then(function (result) {
      authUser = result[0].Parameter.Value;
      authPass = result[1].Parameter.Value;
      console.log(authUser);
      console.log(authPass);
      let authString = 'Basic '   new Buffer(authUser   ':'   authPass).toString('base64');
      if (typeof headers.authorization == 'undefined' || headers.authorization[0].value != authString) {
        const body = 'Unauthorized';
        const response = {
          status: '401',
          statusDescription: 'Unauthorized',
          body: body,
          headers: {
          'www-authenticate': [{key: 'WWW-Authenticate', value:'Basic'}]
        },
    };
    callback(null, response);
}

  // Continue request processing if authentication passed
  callback(null, request);
})
    .catch(function (err) {
      console.log(err);
    });
};