Skip to content

Commit

Permalink
Merge pull request #48 from HyperBrain/support-custom-authorizers
Browse files Browse the repository at this point in the history
Set authorizer name and Uri
  • Loading branch information
HyperBrain authored May 29, 2017
2 parents f7ca608 + 5756f32 commit 53fa162
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 15 deletions.
51 changes: 36 additions & 15 deletions lib/stackops/apiGateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,12 @@ module.exports = function(currentTemplate, aliasStackTemplates, currentAliasStac
['Properties.Principal', 'apigateway.amazonaws.com']));

const apiMethods = _.assign({}, _.pickBy(stageStack.Resources, [ 'Type', 'AWS::ApiGateway::Method' ]));
//const apiResources = _.assign({}, _.pickBy(stageStack.Resources, [ 'Type', 'AWS::ApiGateway::Resource' ]));
const authorizers = _.assign({}, _.pickBy(stageStack.Resources, [ 'Type', 'AWS::ApiGateway::Authorizer' ]));
const aliases = _.assign({}, _.pickBy(aliasStack.Resources, [ 'Type', 'AWS::Lambda::Alias' ]));
const versions = _.assign({}, _.pickBy(aliasStack.Resources, [ 'Type', 'AWS::Lambda::Version' ]));

// Adjust method API and target function
_.forOwn(apiMethods, (method, name) => {

// Relink to function alias in case we have a lambda endpoint
if (_.includes([ 'AWS', 'AWS_PROXY' ], _.get(method, 'Properties.Integration.Type'))) {
// For methods it is a bit tricky to find the related function name. There is no direct link.
Expand All @@ -127,6 +126,25 @@ module.exports = function(currentTemplate, aliasStackTemplates, currentAliasStac
stageStack.Resources[name] = method;
});

// Audjust authorizer Uri and name (stage variables are not allowed in Uris here)
_.forOwn(authorizers, (authorizer, name) => {
const uriParts = authorizer.Properties.AuthorizerUri['Fn::Join'][1];
const funcIndex = _.findIndex(uriParts, part => _.has(part, 'Fn::GetAtt'));

// Use the SERVERLESS_ALIAS stage variable to determine the called function alias
uriParts.splice(funcIndex + 1, 0, `:${this._alias}`);

authorizer.Properties.Name = `${authorizer.Properties.Name}-${this._alias}`;

// Check for user resource overrides
if (_.has(userResources.Resources, name)) {
_.merge(authorizer, userResources.Resources[name]);
delete userResources.Resources[name];
}

stageStack.Resources[name] = authorizer;
});

// Adjust permission to reference the function aliases
_.forOwn(apiLambdaPermissions, (permission, name) => {
const functionName = _.replace(name, /LambdaPermissionApiGateway$/, '');
Expand All @@ -135,20 +153,23 @@ module.exports = function(currentTemplate, aliasStackTemplates, currentAliasStac

// Adjust references and alias permissions
permission.Properties.FunctionName = { Ref: aliasName };
permission.Properties.SourceArn = {
'Fn::Join': [
'',
[
'arn:aws:execute-api:',
{ Ref: 'AWS::Region' },
':',
{ Ref: 'AWS::AccountId' },
':',
{ 'Fn::ImportValue': `${stackName}-ApiGatewayRestApi` },
'/*/*'
if (permission.Properties.SourceArn) {
// Authorizers do not set the SourceArn property
permission.Properties.SourceArn = {
'Fn::Join': [
'',
[
'arn:aws:execute-api:',
{ Ref: 'AWS::Region' },
':',
{ Ref: 'AWS::AccountId' },
':',
{ 'Fn::ImportValue': `${stackName}-ApiGatewayRestApi` },
'/*/*'
]
]
]
};
};
}

// Add dependency on function version
permission.DependsOn = [ versionName, aliasName ];
Expand Down
69 changes: 69 additions & 0 deletions test/stackops/init.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
'use strict';
/**
* Unit tests for initialization.
*/

const getInstalledPath = require('get-installed-path');
const BbPromise = require('bluebird');
const chai = require('chai');
const sinon = require('sinon');
const AWSAlias = require('../../index');

const serverlessPath = getInstalledPath.sync('serverless', { local: true });
const AwsProvider = require(`${serverlessPath}/lib/plugins/aws/provider/awsProvider`);
const Serverless = require(`${serverlessPath}/lib/Serverless`);

chai.use(require('chai-as-promised'));
chai.use(require('sinon-chai'));
const expect = chai.expect;

describe('SNS Events', () => {
let serverless;
let options;
let awsAlias;
// Sinon and stubs for SLS CF access
let sandbox;
let logStub;

before(() => {
sandbox = sinon.sandbox.create();
});

beforeEach(() => {
options = {
alias: 'myAlias',
stage: 'myStage',
region: 'us-east-1',
};
serverless = new Serverless(options);
serverless.setProvider('aws', new AwsProvider(serverless));
serverless.cli = new serverless.classes.CLI(serverless);
serverless.service.service = 'testService';
serverless.service.provider.compiledCloudFormationAliasTemplate = {};
awsAlias = new AWSAlias(serverless, options);

// Disable logging
logStub = sandbox.stub(serverless.cli, 'log');
logStub.returns();
});

afterEach(() => {
sandbox.restore();
});

describe('#aliasInit()', () => {
it('should set alias flags', () => {
serverless.service.provider.compiledCloudFormationTemplate = require('../data/sls-stack-1.json');
const aliasStack = serverless.service.provider.compiledCloudFormationAliasTemplate = require('../data/alias-stack-1.json');
return expect(awsAlias.aliasInit({}, [], {})).to.be.fulfilled
.then(() => BbPromise.all([
expect(aliasStack).to.have.property('Outputs')
.that.has.property('AliasFlags')
.that.deep.equals({
Description: 'Alias flags.',
Value: { hasRole: false }
})
]));
});
});
});

0 comments on commit 53fa162

Please sign in to comment.