Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add a support for onUnauthenticatedRequest property #7780

Merged

Conversation

kamaz
Copy link
Contributor

@kamaz kamaz commented May 26, 2020

Closes: #7773

@medikoo would be good to get your view on deprecation.

@codecov-commenter
Copy link

codecov-commenter commented May 26, 2020

Codecov Report

Merging #7780 into master will increase coverage by 0.30%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #7780      +/-   ##
==========================================
+ Coverage   88.13%   88.43%   +0.30%     
==========================================
  Files         245      244       -1     
  Lines        9262     9054     -208     
==========================================
- Hits         8163     8007     -156     
+ Misses       1099     1047      -52     
Impacted Files Coverage Δ
...ins/aws/package/compile/events/alb/lib/validate.js 97.93% <100.00%> (+1.27%) ⬆️
lib/utils/getServerlessDir.js 0.00% <0.00%> (-100.00%) ⬇️
lib/plugins/aws/info/getApiKeyValues.js 82.75% <0.00%> (-9.55%) ⬇️
lib/plugins/slstats/slstats.js 90.90% <0.00%> (-9.10%) ⬇️
...ackage/compile/events/websockets/lib/deployment.js 95.65% <0.00%> (-4.35%) ⬇️
lib/plugins/aws/deploy/lib/createStack.js 97.29% <0.00%> (-2.71%) ⬇️
lib/classes/Utils.js 92.95% <0.00%> (-2.32%) ⬇️
lib/plugins/aws/info/getResourceCount.js 88.88% <0.00%> (-1.12%) ⬇️
lib/plugins/config/config.js 88.88% <0.00%> (-0.91%) ⬇️
lib/plugins/create/create.js 90.80% <0.00%> (-0.31%) ⬇️
... and 58 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update af3fbf0...7d22c4e. Read the comment docs.

@medikoo medikoo added cat/aws-event-alb deprecation Deprecation proposal (breaking with next major) enhancement labels May 28, 2020
Copy link
Contributor

@medikoo medikoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kamaz great thanks for that! It looks really good. See my remarks, they're mostly about conventions we strive to obey currently in a project

@@ -7,7 +7,12 @@ layout: Doc
# Serverless Framework Deprecations

<a name="BIN_SERVERLESS"><div>&nbsp;</div></a>
<a name="AWS_ALB_EVENT_ALLOW_UNAUTHENTICATED"><div>&nbsp;</div></a>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be added over the given deprecation header


## `bin/serverless`

Please use `bin/serverless.js` instead. `bin/serverless` will be removed with v2.0.0

## `AWS ALB Event allowUnauthenticated`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove ticks, make it as:

## AWS ALB Event `allowUnauthenticated`

@@ -7,7 +7,12 @@ layout: Doc
# Serverless Framework Deprecations

<a name="BIN_SERVERLESS"><div>&nbsp;</div></a>
<a name="AWS_ALB_EVENT_ALLOW_UNAUTHENTICATED"><div>&nbsp;</div></a>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make deprecation code slightly shorter as: AWS_ALB_ALLOW_UNAUTHENTICATED

@@ -77,7 +77,7 @@ provider:
userPoolArn: 'arn:aws:cognito-idp:us-east-1:123412341234:userpool/us-east-1_123412341', # required
userPoolClientId: '1h57kf5cpq17m0eml12EXAMPLE', # required
userPoolDomain: 'your-test-domain' # required
allowUnauthenticated: true # If set to true this allows the request to be forwarded to the target when user is not authenticated. Omit this parameter to make a HTTP 401 Unauthorized error be returned instead
onUnauthenticatedRequest: 'allow' # If set to allow this allows the request to be forwarded to the target when user is not authenticated. Omit or set to 'deny' to make a HTTP 401 Unauthorized error be returned instead (default). Alternatively configure to 'authenticate' to redirect request to IdP authorization endpoint.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's list default option (so 'deny')

validateAlbAuth(auth) {
auth.onUnauthenticatedRequest = auth.allowUnauthenticated ? 'allow' : 'deny';
validateAlbAuth(auth, authName) {
const hasAllowUnauthenticated = _.has(auth, ['allowUnauthenticated']);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not use lodash for constructs which can easily be written in plain JS (see #7747)

@@ -455,6 +455,20 @@ describe('#validate()', () => {
});
});

it('returns valid authorizer when valid object provided with disabled allowUnauthenticated', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's construct tests using runServerless as documented here: https://github.com/serverless/serverless/blob/master/tests/README.md#unit-tests
If something is still unclear please do not hesitate to ask.

As it'll be first tests like that in this file, you can create another describe at bottom of test file to host them

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for sharing a new way of testing. It looks good as it tests full configuration, not just a single method outside the context.

I'm not sure if the validate.test.js is the right place to add tests when using runServerless as my understanding it imitates serverless framework.

Would it be better to move these tests to index.test.js and have describe dedicated to onUnauthenticatedRequest and allowUnauthenticated?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kamaz yes that's a very good point. Indeed in that case index.test.js is better (and it's where we usually put all tests for newly introduced plugins)

hasOnUnauthenticatedRequest &&
!_.includes(supportedValues, auth.onUnauthenticatedRequest)
) {
throw new this.serverless.classes.Error(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this validation (this will be in scope of schema config validation which is handled here: #6562)

Here just assume that passed value is valid

@kamaz
Copy link
Contributor Author

kamaz commented May 28, 2020

@kamaz great thanks for that! It looks really good. See my remarks, they're mostly about conventions we strive to obey currently in a project

@medikoo
Thanks all make sense made the changes except the tests where I need a little bit clarifications.

When it comes to lodash I didn't want to break the convention that was already set up in the file but it is good to know for future that you are moving more towards native js.

@medikoo
Copy link
Contributor

medikoo commented Jun 8, 2020

@kamaz is it read for review? If yes, please re-request review. Thank you!

@kamaz
Copy link
Contributor Author

kamaz commented Jun 8, 2020

hi @medikoo, sorry for the delay but last week was a little bit crazy for me. I should have something ready by tomorrow.

@@ -79,4 +81,55 @@ describe('AwsCompileAlbEvents', () => {
return awsCompileAlbEvents.hooks['package:compileEvents']();
});
});

describe('onUnauthenticatedRequest', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@medikoo I thought before I start writing a set of tests to migrate them to use runServerless I will check what would like to change in the example test that tests the change to onUnauthenticatedRequest.

Do you expect to have an assertion to https://github.com/serverless/serverless/pull/7780/files#diff-f210397c5bba20a4235eaae4251556f9R131 ?

Or

Should the generated cloudformation be asserted as that is the final result?

I would probably opt-out for the latter one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally if we confirm on generated template. So something as:

expect(resource.Properties.StageName).to.equal('$default');
which will validate that we have "deny" set at given property.

Still if for some reason you'll find troublesome getting right path to resource to be validated, let me know


## AWS ALB `allowUnauthenticated`

Please use `onUnauthenticatedRequest` instead `allowUnauthenticated` will be removed with v2.0.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's put . after "instead"

@@ -79,4 +81,55 @@ describe('AwsCompileAlbEvents', () => {
return awsCompileAlbEvents.hooks['package:compileEvents']();
});
});

describe('onUnauthenticatedRequest', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally if we confirm on generated template. So something as:

expect(resource.Properties.StageName).to.equal('$default');
which will validate that we have "deny" set at given property.

Still if for some reason you'll find troublesome getting right path to resource to be validated, let me know

@rwestergren
Copy link

Looking forward to this change. At the moment, I'm having to override the generated AlbListenerRule, with resource extensions, for example:

  extensions:
    BillerAlbListenerRule1:
      Properties:
        Actions:
          - Type: authenticate-oidc
            Order: 1
            AuthenticateOidcConfig:
              OnUnauthenticatedRequest: authenticate
              AuthorizationEndpoint: https://login.microsoftonline.com/***REMOVED***/oauth2/v2.0/authorize
              ClientId: ***REMOVED***
              Issuer: https://login.microsoftonline.com/***REMOVED***/v2.0
              TokenEndpoint: https://login.microsoftonline.com/***REMOVED***/oauth2/v2.0/token
              UserInfoEndpoint: https://graph.microsoft.com/oidc/userinfo
              ClientSecret: ***REMOVED***
          - Type: forward
            TargetGroupArn: !Ref BillerAlbTargetGroupLoadBalancerListener
            Order: 2

@kamaz
Copy link
Contributor Author

kamaz commented Jun 13, 2020

@medikoo thanks for sharing the initial thoughts about the testing. I hope all the comments should be done now.

@kamaz kamaz requested a review from medikoo June 13, 2020 19:04
Copy link
Contributor

@medikoo medikoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kamaz looks great, thank you! I've just proposed some minor style improvements

@@ -217,7 +218,21 @@ module.exports = {
},

validateAlbAuth(auth) {
auth.onUnauthenticatedRequest = auth.allowUnauthenticated ? 'allow' : 'deny';
const hasAllowUnauthenticated = auth.allowUnauthenticated !== undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use more natural != null

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy to change that but not sure if != null makes it clearer. In this particular case, we only care about a case were the property is not defined not if the value is null 0 or any other.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we only care about a case were the property is not defined

If that would be the case, then proper check would be 'allowUnauthenticated' in auth.

Still in JS it's not common to do such checks. Usually best practice is just to check whether a property holds some value, where lack of value is represented by three possible scenarios:

  • property not defined at all
  • undefined assigned explicitly
  • null assigned explicitly.

Having that, the most straightforward way to confirm property holds a value, is to follow with obj.prop != null (that excludes just three above cases and nothing more)

@@ -217,7 +218,21 @@ module.exports = {
},

validateAlbAuth(auth) {
auth.onUnauthenticatedRequest = auth.allowUnauthenticated ? 'allow' : 'deny';
const hasAllowUnauthenticated = auth.allowUnauthenticated !== undefined;
const hasOnUnauthenticatedRequest = auth.onUnauthenticatedRequest !== undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a string property, so technically natural check would be Boolean(auth.onUnauthenticatedRequest)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

);

expect(rule.Properties.Actions[1].Type).to.equal('forward');
expect(rule.Properties.Actions[1].Order).to.equal(2);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll be nice if this test matches one that confirms for allow, so just checks for deny.

I wouldn't check for every CF property, as that technically means reimplementing CF configuration in unit tests, and it's not what I think tests should be about (Testing that given CF configuration results with desired outcome is in scope of integration tests)

override
);

it('maps undefined allowUnauthenticated to "deny"', () =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Title should rather be:

should be "deny" by default

);
}));

it('maps allowUnauthenticated set to false to onUnauthenticatedRequest "allow"', () =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

 `allowUnauthenticated` set to false should be ineffective

);
}));

it('supports setting value to "deny"', () =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think either we can skip that test ("deny" is default) or name it as:

`allowUnauthenticated` should remain "deny" when set to "deny"

expect(rule.Properties.Actions[1].Order).to.equal(2);
}));

it('maps allowUnauthenticated set to true to onUnauthenticatedRequest "allow"', () =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we're in context of suite titled onUnauthenticatedRequest. I would name test as:

maps `allowUnauthenticated` set to true to "allow"

);
}));

it('takes precedence over allowUnauthenticated set "deny"', () =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove that test. I think that testing that onUnauthenticatedRequest takes precedence over allowUnauthenticated shouldn't require more than one test (and anyway such tests will be removed with removal of support for allowUnauthenticated)

);
}));

it('takes precedence over allowUnauthenticated set "allow"', () =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just: takes precedence over allowUnauthenticated

@medikoo
Copy link
Contributor

medikoo commented Jun 22, 2020

@kamaz is this ready for re-review? If it is, can you re-request review (top right box) from me? Thank you!

@kamaz kamaz requested a review from medikoo June 22, 2020 16:00
Copy link
Contributor

@medikoo medikoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kamaz great thanks for update! It looks very good, just one minor suggestion towards documentation, so it aligns our convention (although I know old version didn't follow that)

@@ -88,7 +88,7 @@ provider:
userPoolArn: 'arn:aws:cognito-idp:us-east-1:123412341234:userpool/us-east-1_123412341', # required
userPoolClientId: '1h57kf5cpq17m0eml12EXAMPLE', # required
userPoolDomain: 'your-test-domain' # required
allowUnauthenticated: true # If set to true this allows the request to be forwarded to the target when user is not authenticated. Omit this parameter to make a HTTP 401 Unauthorized error be returned instead
onUnauthenticatedRequest: 'allow' # If set to 'allow' this allows the request to be forwarded to the target when user is not authenticated. When omitted it defaults 'deny' which makes a HTTP 401 Unauthorized error be returned. Alternatively configure to 'authenticate' to redirect request to IdP authorization endpoint.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By convention for optional parameters we put defaults as values. So let's use 'deny' as value.

@kamaz kamaz requested a review from medikoo June 25, 2020 20:39
Copy link
Contributor

@medikoo medikoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @kamaz !

@medikoo medikoo merged commit b976677 into serverless:master Jun 26, 2020
@kamaz kamaz deleted the feat/alb-on-unauthenticated-request branch June 26, 2020 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cat/aws-event-alb deprecation Deprecation proposal (breaking with next major) enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

AWS ALB support for built-in authentication
4 participants