Skip to content

Commit

Permalink
feat: add simple-url handling and non-trailing slash redirect option
Browse files Browse the repository at this point in the history
  • Loading branch information
nickshine committed Apr 10, 2020
1 parent 1a1d534 commit 06cd901
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 29 deletions.
41 changes: 41 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Contributing

All contributions are welcome. Please [create an issue][issues] in order open up communication
with the community.

## Limitations

Be considerate of the [Lambda@Edge limitations][limitations]. The zipped function can be no more
than 1MB in size and execution cannot take longer than 5 seconds, so we must pay close attention
to the size of our dependencies and complexity of operations.

## Commit Message Guidelines

This project follows the [Conventional Commits] specification to aid in automated releases and
change log generation. [Commitlint] is enabled and ran as a `commit-msg` hook to enforce the
commit format. [Commitizen] can be used to prompt through any requirements at commit time `npm
run cm` (or `git cz` if Commitizen is installed globally).

In short, if a commit will be fixing a bug, prefix the commit message with `fix:`

```bash
fix: my bug fix
```

If a commit will be adding a feature, prefix the commit message with `feat:`

```bash
feat: my new feature
```

Commits with `fix:` prefix will show up in the generated changelog as bullets
under the `Bug Fixes:` section, and `feat:` prefixed messages will show under
the `Features:` section. For more on the available prefixes/rules, see
[here][conventional-changelog].

[commitlint]:https://github.com/conventional-changelog/commitlint
[commitizen]:http://commitizen.github.io/cz-cli/
[conventional-changelog]:https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional#rules
[Conventional Commits]:https://www.conventionalcommits.org/en/v1.0.0-beta.3/
[issues]:https://github.com/nickshine/lambda-edge-azure-auth/issues
[limitations]:https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html#limits-lambda-at-edge
43 changes: 16 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](https://github.com/semantic-release/semantic-release)
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg?style=flat-square)](http://commitizen.github.io/cz-cli/)


[Microsoft Azure AD][azure] authentication for [CloudFront] using [Lambda@Edge].

>This project is based on the upstream [cloudfront-auth], but has diverged in the following ways:
>This project is based on [Widen/cloudfront-auth][cloudfront-auth], but has diverged in the following ways:
>
> * Stripped down to focus on Microsoft Azure __Authentication__ and __Authorization__ only.
> * Serverless Webpack added to streamline the final lambda package with [Tree-Shaking].
> * Interactive prompt for generating `config.json` removed in favor of a templated config rendered
> in CI pipelines.
> * Webpack config added to bundle the handler and dependencies in to a single file.
> * A __zip__ of the bundled lambda (sans `config.json`) [is released][releases] via a GitHub Action for use in downstream [IaC] projects like [terraform-aws-lambda-edge-azure-auth].
> * Simple-Url handling for default `index.html` and trailing slash redirects.
> * Downstream terraform module for deployment.
> * Downstream terraform module for deployment ([terraform-aws-lambda-edge-azure-auth]).
## Description

Expand Down Expand Up @@ -48,7 +46,7 @@ be automatically generated).
1. Once created, go to your application `Settings -> Certificates & Secrets` and make a new **client secret** with your desired duration. Click save and copy the value. This will be your `client_secret`
1. Click on **Overview**, go to `Redirect URIs` and enter your Cloudfront hostname with your
preferred path value for the authorization callback.
>Example: https://my-cloudfront-site.example.com/_callback
>Example: `https://my-cloudfront-site.example.com/_callback`
1. Execute `./build.sh` in the downloaded directory. NPM will run to download dependencies and a RSA key will be generated.
1. Choose `Microsoft` as the authorization method and enter the values for [Tenant][azure-tenant], Client ID (**Application ID**), Client Secret (**previously created key**), Redirect URI and Session Duration
1. Select the preferred authentication method
Expand All @@ -61,38 +59,29 @@ be automatically generated).

[Manual Deployment](https://github.com/Widen/cloudfront-auth/wiki/Manual-Deployment) __*or*__ [AWS SAM Deployment](https://github.com/Widen/cloudfront-auth/wiki/AWS-SAM-Deployment)

## Authorization Method Examples

- [Use Google Groups to authorize users](https://github.com/Widen/cloudfront-auth/wiki/Google-Groups-Setup)

- JSON array of email addresses

```
[ "[email protected]", "[email protected]" ]
```
## Testing

Detailed instructions on testing your function can be found [in the Wiki](https://github.com/Widen/cloudfront-auth/wiki/Debug-&-Test).

## Build Requirements

- [npm](https://www.npmjs.com/) ^5.6.0
- [node](https://nodejs.org/en/) ^10.0
- [openssl](https://www.openssl.org)
* [npm] ^5.6.0
* [node] ^10.0
* [openssl]

## Contributing

All contributions are welcome. Please create an issue in order open up communication with the community.
When implementing a new flow or using an already implemented flow, be sure to follow the same style used in `build.js`. The config.json file should have an object for each request made. For example, `openid.index.js` converts config.AUTH_REQUEST and config.TOKEN_REQUEST to querystrings for simplified requests (after adding dynamic variables such as state or nonce). For implementations that are not generic (most), endpoints are hardcoded in to the config (or discovery documents).
Be considerate of our [limitations](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html#limits-lambda-at-edge). The zipped function can be no more than 1MB in size and execution cannot take longer than 5 seconds, so we must pay close attention to the size of our dependencies and complexity of operations.
See [CONTRIBUTING.md](Contributing.md).

[azure]:https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-code
[azure-tenant]:https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-howto-tenant
[cloudfront]:https://aws.amazon.com/cloudfront/
[cloudfront-auth]:https://github.com/Widen/cloudfront-auth
[lambda@edge]:https://webpack.js.org/guides/tree-shaking/
[IaC]:https://en.wikipedia.org/wiki/Infrastructure_as_code
[lambda@edge]:https://aws.amazon.com/lambda/edge/
[node]:https://nodejs.org/en/
[npm]:https://www.npmjs.com/
[oai]:http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html#private-content-creating-oai-console
[tree-shaking]:https://webpack.js.org/guides/tree-shaking/
[openssl]:https://www.openssl.org
[terraform-aws-lambda-edge-azure-auth]:https://registry.terraform.io/modules/nickshine/lambda-edge-azure-auth/aws/
[releases]:https://github.com/nickshine/lambda-edge-azure-auth/releases
7 changes: 7 additions & 0 deletions authn/openid.index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const cookie = require('cookie');
const jwkToPem = require('jwk-to-pem');
const auth = require('./auth.js');
const nonce = require('./nonce.js');
const simpleUrl = require('./simpleurl.js');
const axios = require('axios');
var discoveryDocument;
var jwks;
Expand Down Expand Up @@ -229,6 +230,12 @@ function mainProcess(event, context, callback) {
unauthorized('Unauthorized.', 'User ' + decoded.sub + ' is not permitted.', '', callback);
}
} else {
if (config.TRAILING_SLASH_REDIRECTS_ENABLED) {
simpleUrl.handleRedirect(request, callback)
}
if (config.SIMPLE_URLS_ENABLED) {
request.uri = simpleUrl.handleIndexes(request.uri)
}
console.log("Authorizing user.");
auth.isAuthorized(decoded, request, callback, unauthorized, internalServerError, config);
}
Expand Down
16 changes: 15 additions & 1 deletion build/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,24 @@ prompt.get({
distribution: {
message: colors.red("Enter distribution name"),
required: true
}
},
trailing_slash_redirects_enabled: {
description: colors.red("Enable trailing slash redirects? (e.g. www.example.com/about redirects to www.example.com/about/"),
type: 'boolean',
required: true,
default: true
},
simple_urls_enabled: {
description: colors.red("Enable simple urls (e.g. www.example.com/about/ returns www.example.com/about/index.html object)"),
type: 'boolean',
required: true,
default: true
},
}
}, function (err, result) {
config.DISTRIBUTION = result.distribution;
config.TRAILING_SLASH_REDIRECTS_ENABLED = result.trailing_slash_redirects_enabled;
config.SIMPLE_URLS_ENABLED = result.simple_urls_enabled;
shell.mkdir('-p', 'distributions/' + config.DISTRIBUTION);
if (fs.existsSync('distributions/' + config.DISTRIBUTION + '/config.json')) {
oldConfig = JSON.parse(fs.readFileSync('./distributions/' + config.DISTRIBUTION + '/config.json', 'utf8'));
Expand Down
2 changes: 1 addition & 1 deletion nonce.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ module.exports.validateNonce = function (nonce, hash) {
const other = crypto.createHmac('sha256', nonce)
.digest('hex');
return (other == hash);
}
}
31 changes: 31 additions & 0 deletions simpleurl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const redirect = (request, callback) => {
const location = request.querystring ? `${request.uri}/?${request.querystring}` : `${request.uri}/`

const response = {
status: '301',
statusDescription: 'Moved Permanently',
headers: {
location: [{
key: 'Location',
value: location
}]
}
};
callback(null, response);
}

module.exports.handleIndexes = (uri) => {
if (uri.endsWith('/')) {
console.log(`'index.html' appended to request.uri: ${request.uri}`);
return `${uri}index.html`;
}

return uri;
}

module.exports.handleRedirect = (request, callback) => {
if (!request.uri.endsWith('/') && !request.uri.includes('.')) {
console.log(`301 redirect ${request.uri} to ${request.uri}/`);
redirect(request, callback);
}
}

0 comments on commit 06cd901

Please sign in to comment.