-
Notifications
You must be signed in to change notification settings - Fork 8.2k
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
Adding Global Access Agreement #139217
Adding Global Access Agreement #139217
Conversation
Pinging @elastic/kibana-security (Team:Security) |
@legrego @azasypkin Should the docs be updated to reflect this as well? |
@kc13greiner yes, docs changes need to be done to teach our users about this new setting:
Additionally, we will need to add a corresponding changes to allow this new setting to be configured by end users within the Elastic Cloud console. We'll follow up with you separately about that. |
ACK: will review today |
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.
Looks good! Just two questions.
@@ -237,6 +238,7 @@ export const ConfigSchema = schema.object({ | |||
}), | |||
authc: schema.object({ | |||
selector: schema.object({ enabled: schema.maybe(schema.boolean()) }), | |||
accessAgreement: schema.maybe(schema.object({ message: schema.string() })), |
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.
question: I'm wondering if it would make sense to move accessAgreement
one level above authc
, like we did with global session
since it's not strictly related to the authentication and it's fine if provider's config overrides any config, whether it's auth related or not?
What do you think @kc13greiner @legrego?
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.
question: I'm wondering if it would make sense to move
accessAgreement
one level aboveauthc
, like we did with globalsession
since it's not strictly related to the authentication and it's fine if provider's config overrides any config, whether it's auth related or not?
Hmm, that's a good question! I could make an argument either way, but since we have session
at the global level, I think it would be slightly more consistent to move accessAgreement
one level up.
I don't have a strong opinion here, so I'm happy to defer to you both.
(Also @/kurt
should be @kc13greiner)
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.
Sounds good to me! Ill move it up
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.
for (const [type, providerGroup] of Object.entries(providers)) { | ||
for (const [name, { enabled, order, accessAgreement }] of Object.entries(providerGroup ?? {})) { | ||
const hasLocalAccessAgreement: boolean = !!accessAgreement?.message; |
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.
question: wouldn't it be easier (implementation/readability) if we keep global and provider-specific accessAgreement
configs separate and just slightly update Authenticator.shouldRedirectToAccessAgreement
and /security/access_agreement
route handler to account for the global access agreement message if provider doesn't have any? It'd also allow us to diverge these configs in the future if we want to (e.g. we can restrict global access agreement settings that providers can or cannot override, like we did for xpack.session.cleanupInterval
).
What do you think?
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.
Yea, good call! Ill make the change
@@ -814,20 +815,26 @@ export class Authenticator { | |||
*/ | |||
private shouldRedirectToAccessAgreement(sessionValue: SessionValue | null) { | |||
// Request should be redirected to Access Agreement UI only if all following conditions are met: |
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.
@azasypkin Can you help me clean up the comments in this function?
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.
Sure, let me try:
// Request can be redirected (not API call)
// And it's not a request to the Access Agreement UI itself
We can remove these two - since we check for canRedirectRequest
and access agreement URL before we invoke this function.
// If user doesn't have an active session or if they already acknowledged
// access agreement (based on the flag we store in the session) - bail out.
if (sessionValue == null || sessionValue.accessAgreementAcknowledged) {
return false;
}
// If access agreement is neither enabled globally (for all providers)
// nor for the provider that authenticated user request - bail out.
const providerConfig = this.options.config.authc.providers as Record<string, any>)[
sessionValue.provider.type
]?.[sessionValue.provider.name];
if (!this.options.config.accessAgreement && !providerConfig?.accessAgreement) {
return false;
}
// Check if the current license allows access agreement.
return this.options.license.getFeatures().allowAccessAgreement;
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.
Perfect! Fixed in latest commit.
…-ref HEAD~1..HEAD --fix'
@@ -343,6 +343,7 @@ export class AuthenticationService { | |||
license: this.license, | |||
session, | |||
isElasticCloudDeployment, | |||
accessAgreement: { message: config.accessAgreement?.message }, |
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.
nit: I think you can just add accessAgreement
property directly to the config
argument above (we do the same with authc
).
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.
Fixed in latest commit!
@@ -814,20 +815,26 @@ export class Authenticator { | |||
*/ | |||
private shouldRedirectToAccessAgreement(sessionValue: SessionValue | null) { | |||
// Request should be redirected to Access Agreement UI only if all following conditions are met: |
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.
Sure, let me try:
// Request can be redirected (not API call)
// And it's not a request to the Access Agreement UI itself
We can remove these two - since we check for canRedirectRequest
and access agreement URL before we invoke this function.
// If user doesn't have an active session or if they already acknowledged
// access agreement (based on the flag we store in the session) - bail out.
if (sessionValue == null || sessionValue.accessAgreementAcknowledged) {
return false;
}
// If access agreement is neither enabled globally (for all providers)
// nor for the provider that authenticated user request - bail out.
const providerConfig = this.options.config.authc.providers as Record<string, any>)[
sessionValue.provider.type
]?.[sessionValue.provider.name];
if (!this.options.config.accessAgreement && !providerConfig?.accessAgreement) {
return false;
}
// Check if the current license allows access agreement.
return this.options.license.getFeatures().allowAccessAgreement;
let accessAgreement: string = ''; | ||
|
||
if (sessionValue) { | ||
const localAccessAgreement = |
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.
optional nit: we used "global vs provider-specific" terminology in the past, but I'm happy to change that if you think "local" makes more sense.
const accessAgreementMessage = providerSpecificAccessAgreement?.message ??
globalAccessAgreement?.message ?? '';
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.
done!
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.
Looks great, just two more minor questions and I think we're good to go!
@@ -235,6 +236,7 @@ export const ConfigSchema = schema.object({ | |||
hostname: schema.maybe(schema.string({ hostname: true })), | |||
port: schema.maybe(schema.number({ min: 0, max: 65535 })), | |||
}), | |||
accessAgreement: schema.maybe(schema.object({ message: schema.maybe(schema.string()) })), |
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.
question: is there any value in making message
optional (schema.maybe
) in addition to already optional accessAgreement
top-level property? It feels like message
would be always required if access agreement is required.
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 believe I have it how you're recommending, please double check I got it right!
const hasProviderSpecificAccessAgreement: boolean = !!accessAgreement?.message; | ||
const hasGlobalAccessAgreement: boolean = !!config.accessAgreement?.message; | ||
|
||
if (!enabled) { | ||
delete providerGroup![name]; | ||
} else { | ||
const hasAccessAgreement: boolean = | ||
hasProviderSpecificAccessAgreement || hasGlobalAccessAgreement; | ||
|
||
sortedProviders.push({ | ||
type: type as any, | ||
name, | ||
order, | ||
hasAccessAgreement: !!accessAgreement?.message, | ||
hasAccessAgreement, |
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.
question: do we really need this change? I'm just trying to reduce changes only to those that are relevant to the change we'd like to make and are absolutely necessary (makes reviewing much easier), and it looks like we only need change in line 239 🙂
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.
The security_usage_collector.ts
references that field. Do you think the change would be better there or should I remove it?
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.
Ah, I didn't realize that we introduced that field just for usage collector! I'd still make this check directly in the security_usage_collector.ts
(the place that actually needs these two settings to be merged to a single accessAgreementEnabled
field), but since hasAccessAgreement
is used solely for the usage collector feel free to pick the option you like the most.
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.
Ill make the change in the collector!
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.
Done!
x-pack/plugins/security/server/routes/views/access_agreement.ts
Outdated
Show resolved
Hide resolved
Co-authored-by: Aleh Zasypkin <aleh.zasypkin@gmail.com>
…-ref HEAD~1..HEAD --fix'
…-ref HEAD~1..HEAD --fix'
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.
LGTM, great job!
for (const [type, providerGroup] of Object.entries(providers)) { | ||
for (const [name, { enabled, order, accessAgreement }] of Object.entries(providerGroup ?? {})) { | ||
if (!enabled) { | ||
delete providerGroup![name]; | ||
} else { | ||
const hasAccessAgreement: boolean = !!accessAgreement?.message; |
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.
optional nit: boolean
is inferred automatically.
const hasAccessAgreement: boolean = !!accessAgreement?.message; | |
const hasAccessAgreement = !!accessAgreement?.message; |
Sorry @kc13greiner, I forgot to leave a note during review: would you mind allowing this new setting in our docker image (setting needs to be included in https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker)? |
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.
kibana-docker
@gchaps I think this PR is finally ready - do the docs changes look alright? |
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.
A few minor comments but otherwise LGTM.
@@ -162,6 +162,15 @@ Adds a message accessible at the login UI with additional help information for t | |||
xpack.security.authc.selector.enabled {ess-icon}:: | |||
Determines if the login selector UI should be enabled. By default, this setting is set to `true` if more than one authentication provider is configured. | |||
|
|||
[float] | |||
[[authentication-access-agreement-settings]] | |||
==== Configure a default access agreement |
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.
Other sections include this as a lead-in sentence:
You can configure the following settings in the
kibana.yml
file.
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.
Oo! I'll add that in, thanks!!
Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>
Co-authored-by: gchaps <33642766+gchaps@users.noreply.github.com>
💚 Build Succeeded
Metrics [docs]
History
To update your PR or re-run it, just comment with: |
Summary
Adding a config for a default, global access agreement message for all configured authc providers that do no have a local access agreement message
Release Notes
A default Access Agreement can now be set for all authentication providers at the
xpack.security
level