Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:

- run: npm run-script build-ci okta_native
- run: test -f distributions/okta_native/okta_native.zip
- run: npm run-script build-ci auth0
- run: test -f distributions/auth0/auth0.zip
- run: npm run-script build-ci rotate_key_pair
- run: test -f distributions/rotate_key_pair/rotate_key_pair.zip

Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ jobs:
- name: Build okta_native
run: npm run-script build-ci okta_native

- name: Build auth0
run: npm run-script build-ci auth0

- name: Build rotate_key_pair
run: npm run-script build-ci rotate_key_pair

Expand All @@ -36,4 +39,5 @@ jobs:
with:
files: |
./distributions/okta_native/okta_native.zip
./distributions/auth0/auth0.zip
./distributions/rotate_key_pair/rotate_key_pair.zip
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ If you need to build a generic package yourself, execute:
The supported values of `package` are:

* `okta_native` - builds a generic Lambda package for OKTA Native authentication
* `auth0` - builds a generic Lambda package for Auth0 authentication
* `rotate_key_pair` - builds a Lambda package for rotating the RSA keys in AWS Secrets Manager

GitHub Actions automatically creates a new GitHub release when the repository owner pushes a tag that begins with `v`.
Expand Down
64 changes: 36 additions & 28 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 cfg = require('./config.js');
const axios = require('axios');
const url = require('url');
const entities = require('html-entities');
Expand All @@ -15,40 +16,47 @@ var config;

exports.handler = (event, context, callback) => {
if (typeof jwks == 'undefined' || typeof discoveryDocument == 'undefined' || typeof config == 'undefined') {
config = JSON.parse(fs.readFileSync('config.json', 'utf8'));
cfg.getConfig('config.json', context.functionName, function(error, result) {
if (error) {
console.log("Internal server error: " + error.message);
internalServerError(callback);
} else {
config = result;

// Get Discovery Document data
console.log("Get discovery document data");
axios.get(config.DISCOVERY_DOCUMENT)
.then(function(response) {
console.log(response);
// Get Discovery Document data
console.log("Get discovery document data");
axios.get(config.DISCOVERY_DOCUMENT)
.then(function(response) {
console.log(response);

// Get jwks from discovery document url
console.log("Get jwks from discovery document");
discoveryDocument = response.data;
if (discoveryDocument.hasOwnProperty('jwks_uri')) {
// Get jwks from discovery document url
console.log("Get jwks from discovery document");
discoveryDocument = response.data;
if (discoveryDocument.hasOwnProperty('jwks_uri')) {

// Get public key and verify JWT
axios.get(discoveryDocument.jwks_uri)
.then(function(response) {
console.log(response);
jwks = response.data;
// Get public key and verify JWT
axios.get(discoveryDocument.jwks_uri)
.then(function(response) {
console.log(response);
jwks = response.data;

// Callback to main function
mainProcess(event, context, callback);
})
.catch(function(error) {
console.log("Internal server error: " + error.message);
// Callback to main function
mainProcess(event, context, callback);
})
.catch(function(error) {
console.log("Internal server error: " + error.message);
internalServerError(callback);
});
} else {
console.log("Internal server error: Unable to find JWK in discovery document");
internalServerError(callback);
});
} else {
console.log("Internal server error: Unable to find JWK in discovery document");
internalServerError(callback);
}
})
.catch(function(error) {
console.log("Internal server error: " + error.message);
internalServerError(callback);
});
}
})
.catch(function(error) {
console.log("Internal server error: " + error.message);
internalServerError(callback);
});
} else {
mainProcess(event, context, callback);
Expand Down
45 changes: 38 additions & 7 deletions build/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ if (config.DISTRIBUTION) {
case 'okta_native':
genericOktaConfiguration();
break;
case 'auth0':
genericAuth0Configuration();
break;
case 'rotate_key_pair':
buildRotateKeyPair();
break;
Expand Down Expand Up @@ -565,16 +568,44 @@ function auth0Configuration() {
config.TOKEN_REQUEST.redirect_uri = result.REDIRECT_URI;
config.TOKEN_REQUEST.grant_type = 'authorization_code';

config.AUTHZ = "AUTH0";
buildAuth0();
});
}

shell.cp('./authn/openid.index.js', './distributions/' + config.DISTRIBUTION + '/index.js');
shell.cp('./nonce.js', './distributions/' + config.DISTRIBUTION + '/nonce.js');
function genericAuth0Configuration() {
config.PRIVATE_KEY = '${private-key}';
config.PUBLIC_KEY = '${public-key}';

fs.writeFileSync('distributions/' + config.DISTRIBUTION + '/config.json', JSON.stringify(result, null, 4));
config.DISCOVERY_DOCUMENT = '${base-url}/.well-known/openid-configuration';
config.SESSION_DURATION = '${session-duration}';

shell.cp('./authz/auth0.js', './distributions/' + config.DISTRIBUTION + '/auth.js');
writeConfig(config, zip, ['config.json', 'index.js', 'auth.js', 'nonce.js']);
});
config.BASE_URL = '${base-url}';
config.CALLBACK_PATH = '${callback-path}';
config.LOGOUT_PATH = '${logout-path}';

config.AUTH_REQUEST.client_id = '${client-id}';
config.AUTH_REQUEST.response_type = 'code';
config.AUTH_REQUEST.scope = '${scope}';
config.AUTH_REQUEST.redirect_uri = 'https://${domain-name}${callback-path}';

config.TOKEN_REQUEST.client_id = '${client-id}';
config.TOKEN_REQUEST.redirect_uri = 'https://${domain-name}${callback-path}';
config.TOKEN_REQUEST.grant_type = 'authorization_code';
config.TOKEN_REQUEST.client_secret = '${client-secret}';

buildAuth0(true);
}

function buildAuth0(isGeneric) {
config.AUTHZ = "AUTH0";

shell.cp('./authn/openid.index.js', './distributions/' + config.DISTRIBUTION + '/index.js');
shell.cp('./nonce.js', './distributions/' + config.DISTRIBUTION + '/nonce.js');

shell.cp(isGeneric ? './config/generic.config.js' : './config/custom.config.js', './distributions/' + config.DISTRIBUTION + '/config.js');

shell.cp('./authz/auth0.js', './distributions/' + config.DISTRIBUTION + '/auth.js');
writeConfig(config, zip, ['config.json', 'config.js', 'index.js', 'auth.js', 'nonce.js']);
}

// Centrify configuration
Expand Down
2 changes: 1 addition & 1 deletion infra/terraform/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Terraform Modules for CloudFront Authentication

This directory contains the _Terraform_ configuration for adding authentication to a CloudFront distribution. Currently only OKTA Native authentication is supported.
This directory contains the _Terraform_ configuration for adding authentication to a CloudFront distribution. Currently only OKTA Native and Auth0 authentication is supported.

## Usage

Expand Down
10 changes: 10 additions & 0 deletions infra/terraform/modules/auth0/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module "auth" {
source = "../_auth"

release_version = var.release_version
name = var.name
tags = var.tags
package_url = "https://github.com/iress/cloudfront-auth/releases/download/${var.release_version}/auth0.zip"
key_pair_rotation_period_days = var.key_pair_rotation_period_days
kms_key_arn = var.kms_key_arn
}
4 changes: 4 additions & 0 deletions infra/terraform/modules/auth0/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "auth_lambda_arn" {
value = module.auth.auth_lambda_arn
description = "The Amazon Resource Name (ARN) identifying the authentication Lambda Function Version"
}
56 changes: 56 additions & 0 deletions infra/terraform/modules/auth0/parameters.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
resource "aws_ssm_parameter" "base_url" {
name = "/${var.name}/base-url"
type = "String"
value = var.org_url
tags = var.tags
}

resource "aws_ssm_parameter" "client_id" {
name = "/${var.name}/client-id"
type = "String"
value = var.client_id
tags = var.tags
}

resource "aws_ssm_parameter" "domain_name" {
name = "/${var.name}/domain-name"
type = "String"
value = var.domain_name
tags = var.tags
}

resource "aws_ssm_parameter" "callback_path" {
name = "/${var.name}/callback-path"
type = "String"
value = var.callback_path
tags = var.tags
}

resource "aws_ssm_parameter" "logout_path" {
name = "/${var.name}/logout-path"
type = "String"
value = var.logout_path
tags = var.tags
}

resource "aws_ssm_parameter" "session_duration" {
name = "/${var.name}/session-duration"
type = "String"
value = var.session_duration * 60 * 60
tags = var.tags
}

resource "aws_ssm_parameter" "scope" {
name = "/${var.name}/scope"
type = "String"
value = var.scope
tags = var.tags
}

resource "aws_ssm_parameter" "client_secret" {
name = "/${var.name}/client-secret"
type = "SecureString"
value = var.client_secret
tags = var.tags

}
10 changes: 10 additions & 0 deletions infra/terraform/modules/auth0/provider.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Provider passed in should always be us-east-1

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 3.28"
}
}
}
71 changes: 71 additions & 0 deletions infra/terraform/modules/auth0/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
variable "release_version" {
description = "The name of the GitHub release version to deploy"
type = string
}

variable "name" {
description = "A name for the AWS resources created by this module"
type = string
}

variable "tags" {
description = "Tags to add to each resource"
type = map(string)
default = {}
}

variable "org_url" {
description = "The org URL for the Auth0 environment"
type = string
}

variable "client_id" {
description = "Public identifier for the client (can be found in Auth0 Admin -> Applications)"
type = string
}

variable "client_secret" {
description = "The client secret for the Auth0 application"
type = string
}

variable "domain_name" {
description = "Domain name of the CloudFront distribution"
type = string
}

variable "callback_path" {
description = "The path of the URI where Auth0 will send users after authentication"
type = string
default = "/_callback"
}

variable "logout_path" {
description = "The path of the URI where Auth0 will send users after logout"
type = string
default = "/_logout"
}

variable "session_duration" {
description = "The number of hours that the JWT is valid for"
type = number
default = 2
}

variable "key_pair_rotation_period_days" {
description = "The number of days between automatic scheduled rotations of the key pair"
type = number
default = 7
}

variable "scope" {
description = "A space delimited list of Auth0 scopes which are used by an application during authentication to authorize access to a user's details, openid is required for authentication requests and other scopes like email may also be included."
type = string
default = "openid email"
}

variable "kms_key_arn" {
description = "The ARN of the KMS key used to encrypt the key pair"
type = string
default = null
}