LoginSignup
17
7

More than 5 years have passed since last update.

CloudFront Lamba@EdgeでBasic認証する

Last updated at Posted at 2017-04-12

2017/8: GA版にあわせて書き直しました

CloudFront + S3オリジン構成の場合、Basic認証を使ったコンテンツ保護が出来ませんでしたが、Lambda@Edgeによって可能になりました。

下記の機能を提供しています。

  • 一部のパスだけを認証の対象にできる。この例では、パスにsecretが含まれるものだけが認証の対象です
  • Authorizationヘッダがなかった場合に401ではなく403を返すことで、ブラウザの認証ダイアログが表示される
  • 認証エラー時にBodyを返却する
  • 複数のクレデンシャルに対応している

今のバージョンは、クレデンシャルがそのままハードコードされてるので、ソースの取り扱いにご注意を。
パスワードはハッシュをかけた方が安全ですが、これはTODOとします。

'use strict';

exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;

  const errorContent = '\
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">\
<html><head>\
<title>401 Authorization Required</title>\
</head><body>\
<h1>Authorization Required</h1>\
<p>This server could not verify that you are authorized to access the document\
requested.  Either you supplied the wrong credentials (e.g., bad password), or your\
browser doesn\'t understand how to supply the credentials required.</p>\
</body></html>\
';

  const credentials = {
    'user1': 'pass1234',
    'user2': 'pass5678'
  }

  if (request.uri.match(/secret/i)) {
    var authorities = request.headers.Authorization || request.headers.authorization
    if (authorities) {
      let authorized = false;
      for (let user in credentials) {
        var secret = new Buffer(user + ':' + credentials[user]).toString('base64');
        for (var i = 0; i < authorities.length; i++) {
          if (authorities[i].value.split(" ")[1] === secret) {
            authorized = true;
          }
        }
      }
      if (authorized) {
        console.log("match: " + authorities);
        callback(null, request);
      } else {
        console.log("not match: " + authorities);
        callback(null, {status: '403', statusDescription: '403 Forbidden',
                        headers: {
                          'content-type': [ { key: 'Content-Type', value: 'text/html; charset=UTF-8' } ]
                        },
                        body: errorContent.toString('utf8')
                       });
      }
    } else {
      // Client did not send authorization
      callback(null, {status: '401', statusDescription: '401 Unauthorized',
                      headers: {
                        'www-authenticate': [{ key: 'WWW-Authenticate', value: 'Basic' }]
                      }
                     });
    }
  } else {
    console.log("do nothing");
    callback(null, request);
  }
}
17
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
7