Skip to content

Instantly share code, notes, and snippets.

@jeroenvollenbrock
Last active April 8, 2024 15:51
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save jeroenvollenbrock/94edbbc62adc986d6d6a9a3076e66f5b to your computer and use it in GitHub Desktop.
Save jeroenvollenbrock/94edbbc62adc986d6d6a9a3076e66f5b to your computer and use it in GitHub Desktop.
AWS-CloudFront-basic-auth
var USERS = {
protecteddir: [{
username: 'user',
password: 'pass',
}],
};
//Response when auth is not valid.
var response401 = {
statusCode: 401,
statusDescription: 'Unauthorized',
headers: {
'www-authenticate': {value:'Basic'},
},
};
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
function btoa(input) {
input = String(input);
var bitmap, a, b, c,
result = "", i = 0,
rest = input.length % 3; // To determine the final padding
for (; i < input.length;) {
if ((a = input.charCodeAt(i++)) > 255
|| (b = input.charCodeAt(i++)) > 255
|| (c = input.charCodeAt(i++)) > 255)
throw new TypeError("Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.");
bitmap = (a << 16) | (b << 8) | c;
result += b64.charAt(bitmap >> 18 & 63) + b64.charAt(bitmap >> 12 & 63)
+ b64.charAt(bitmap >> 6 & 63) + b64.charAt(bitmap & 63);
}
// If there's need of padding, replace the last 'A's with equal signs
return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result;
}
function handler(event) {
var request = event.request;
var headers = request.headers;
var auth = request.headers.authorization && request.headers.authorization.value;
var project = request.uri.substring(1).split(/\.|\//)[0];
var users = USERS[project];
if(users) {
if(!auth || !auth.startsWith('Basic ')) {
return response401;
}
if(!users.find(function(user) {
// Construct the Basic Auth string
var authString = 'Basic ' + btoa(user.username + ':' + user.password);
return authString === auth;
})) {
return response401;
}
}
return request;
}
@henrik
Copy link

henrik commented Nov 18, 2021

Thanks for this!

I adapted it slightly because I wanted a single user for the whole site.

Coworker @aalin also simplified it a little.

We set it up per @lehuy2012's comment above: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-tutorial.html

Edited 2022-10-02 to handle ":" in passwords per comments below.

// Source: https://gist.github.com/jeroenvollenbrock/94edbbc62adc986d6d6a9a3076e66f5b

var USERNAME = 'myuser';
var PASSWORD = 'mypassword';

var response401 = {
  statusCode: 401,
  statusDescription: 'Unauthorized',
  headers: {
    'www-authenticate': {value:'Basic'},
  },
};

function validateBasicAuth(authHeader) {
  var match = authHeader.match(/^Basic (.+)$/);
  if (!match) return false;

  var credentials = String.bytesFrom(match[1], 'base64').split(':', 2);

  return credentials[0] === USERNAME && credentials[1] === PASSWORD;
}

function handler(event) {
  var request = event.request;
  var headers = request.headers;
  var auth = (headers.authorization && headers.authorization.value) || '';

  if (!validateBasicAuth(auth)) return response401;

  return request;
}

@rashidnhm
Copy link

@henrik does your example hold up if the password itself contains :?

@aalin
Copy link

aalin commented Sep 28, 2022

@rashidnhm: It seems like it doesn't.

It should only split the credentials into two parts. This should work with passwords containing :.

var credentials = String.bytesFrom(match[1], 'base64').split(':', 2);

@henrik
Copy link

henrik commented Oct 2, 2022

Thanks @rashidnhm – good catch! And thanks @aalin :)

I've edited my comment above to incorporate @aalin's fix for ease of copy-pasting.

And to make it explicit – we only need to handle ":" in passwords, not in usernames. They're not allowed in usernames.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment