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
feat: add a support for onUnauthenticatedRequest property #7780
Conversation
Codecov Report
@@ 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
Continue to review full report at Codecov.
|
There was a problem hiding this 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
docs/deprecations.md
Outdated
@@ -7,7 +7,12 @@ layout: Doc | |||
# Serverless Framework Deprecations | |||
|
|||
<a name="BIN_SERVERLESS"><div> </div></a> | |||
<a name="AWS_ALB_EVENT_ALLOW_UNAUTHENTICATED"><div> </div></a> |
There was a problem hiding this comment.
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
docs/deprecations.md
Outdated
|
||
## `bin/serverless` | ||
|
||
Please use `bin/serverless.js` instead. `bin/serverless` will be removed with v2.0.0 | ||
|
||
## `AWS ALB Event allowUnauthenticated` |
There was a problem hiding this comment.
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`
docs/deprecations.md
Outdated
@@ -7,7 +7,12 @@ layout: Doc | |||
# Serverless Framework Deprecations | |||
|
|||
<a name="BIN_SERVERLESS"><div> </div></a> | |||
<a name="AWS_ALB_EVENT_ALLOW_UNAUTHENTICATED"><div> </div></a> |
There was a problem hiding this comment.
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
docs/providers/aws/events/alb.md
Outdated
@@ -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. |
There was a problem hiding this comment.
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']); |
There was a problem hiding this comment.
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', () => { |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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
@medikoo When it comes to |
@kamaz is it read for review? If yes, please re-request review. Thank you! |
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', () => { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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'); |
"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
docs/deprecations.md
Outdated
|
||
## AWS ALB `allowUnauthenticated` | ||
|
||
Please use `onUnauthenticatedRequest` instead `allowUnauthenticated` will be removed with v2.0.0 |
There was a problem hiding this comment.
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', () => { |
There was a problem hiding this comment.
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'); |
"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
Looking forward to this change. At the moment, I'm having to override the generated
|
@medikoo thanks for sharing the initial thoughts about the testing. I hope all the comments should be done now. |
There was a problem hiding this 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; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 explicitlynull
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; |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
happy to change see comment https://github.com/serverless/serverless/pull/7780/files#r441055404
); | ||
|
||
expect(rule.Properties.Actions[1].Type).to.equal('forward'); | ||
expect(rule.Properties.Actions[1].Order).to.equal(2); |
There was a problem hiding this comment.
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"', () => |
There was a problem hiding this comment.
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"', () => |
There was a problem hiding this comment.
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"', () => |
There was a problem hiding this comment.
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"', () => |
There was a problem hiding this comment.
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"', () => |
There was a problem hiding this comment.
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"', () => |
There was a problem hiding this comment.
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
@kamaz is this ready for re-review? If it is, can you re-request review (top right box) from me? Thank you! |
There was a problem hiding this 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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @kamaz !
Closes: #7773
@medikoo would be good to get your view on
deprecation
.