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

Adding Global Access Agreement #139217

Merged
merged 35 commits into from
Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
680dc12
Adding Global Access Agreement
kc13greiner Aug 22, 2022
055b6ae
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Aug 22, 2022
76049fe
Merge branch 'main' into feature/global_access_agreement
kc13greiner Aug 22, 2022
f6135fc
Adding docs
kc13greiner Aug 23, 2022
ddf492d
Merge branch 'main' into feature/global_access_agreement
kc13greiner Aug 24, 2022
c68be02
Merge branch 'main' into feature/global_access_agreement
kc13greiner Aug 24, 2022
d8d8f1d
Merge branch 'main' into feature/global_access_agreement
kc13greiner Aug 24, 2022
60e0c5f
PR Review changes
kc13greiner Aug 24, 2022
af8a6fd
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Aug 24, 2022
a3f6250
PR Review changes
kc13greiner Aug 26, 2022
809d491
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Aug 26, 2022
613ae7b
Fixing global access agreement redirect logic
kc13greiner Aug 26, 2022
1a2fc33
Merge branch 'main' into feature/global_access_agreement
kc13greiner Aug 26, 2022
a04f166
Fixing unit test
kc13greiner Aug 29, 2022
fc8c260
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Aug 29, 2022
f4876e7
Merge branch 'main' into feature/global_access_agreement
kc13greiner Aug 29, 2022
85e8db5
Changing verbiage
kc13greiner Aug 29, 2022
9aa9cb9
Changing local -> provider specific
kc13greiner Aug 29, 2022
2da003b
Merge branch 'main' into feature/global_access_agreement
kc13greiner Aug 29, 2022
53e3ce5
Merge branch 'main' into feature/global_access_agreement
kibanamachine Aug 29, 2022
6c059dd
Update x-pack/plugins/security/server/routes/views/access_agreement.ts
kc13greiner Aug 31, 2022
4ed8ce4
PR Feedback
kc13greiner Aug 31, 2022
9b9128d
Merge branch 'main' into feature/global_access_agreement
kc13greiner Aug 31, 2022
e70f02e
removing `only`
kc13greiner Aug 31, 2022
255a56a
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Aug 31, 2022
9c77a54
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Aug 31, 2022
fcc2b9a
Changing the accessAgreement to be optional
kc13greiner Aug 31, 2022
a15e0aa
[CI] Auto-commit changed files from 'node scripts/precommit_hook.js -…
kibanamachine Aug 31, 2022
8b49ada
Adding docker config
kc13greiner Sep 1, 2022
6f7c9c9
Update docs/user/security/access-agreement.asciidoc
kc13greiner Sep 6, 2022
319c2c9
Update docs/user/security/access-agreement.asciidoc
kc13greiner Sep 6, 2022
11d0ec6
Adding PR Review feedback
kc13greiner Sep 6, 2022
fd81dcc
Merge branch 'main' into feature/global_access_agreement
kc13greiner Sep 6, 2022
d534b4b
Merge branch 'main' into feature/global_access_agreement
kc13greiner Sep 6, 2022
4f2350a
Merge branch 'main' into feature/global_access_agreement
kc13greiner Sep 6, 2022
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
9 changes: 9 additions & 0 deletions docs/settings/security-settings.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ xpack.security.authc:
<3> Specifies the settings for the SAML authentication provider with a `saml1` name.
<4> Specifies the settings for the SAML authentication provider with a `saml2` name.

[float]
[[authentication-access-agreement-settings]]
==== Configure a default access agreement

xpack.security.authc.accessAgreement.message {ess-icon}::
This setting specifies the access agreement text in Markdown format that will be used as the default access agreement for all providers that do not
specify a value for `xpack.security.authc.providers.<provider-type>.<provider-name>.accessAgreement.message`.
For more information, refer to <<xpack-security-access-agreement>>.

[float]
[[authentication-provider-settings]]
==== Valid settings for all authentication providers
Expand Down
3 changes: 3 additions & 0 deletions docs/user/security/access-agreement.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Access agreement is a https://www.elastic.co/subscriptions[subscription feature]
agreement before accessing {kib}. The agreement text supports Markdown format and can be specified using the
`xpack.security.authc.providers.<provider-type>.<provider-name>.accessAgreement.message` setting.

A default access agreement setting can also be specified using `xpack.security.authc.accessAgreement.message`.
This message will be used for each provider that doesn't specify its own access agreement.
kc13greiner marked this conversation as resolved.
Show resolved Hide resolved

[NOTE]
============================================================================
You need to acknowledge the access agreement only once per session, and {kib} reports the acknowledgement in the audit logs.
Expand Down
33 changes: 33 additions & 0 deletions x-pack/plugins/security/server/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1789,6 +1789,39 @@ describe('createConfig()', () => {
).toThrow('[audit.appender.1.layout]: expected at least one defined value but got [undefined]');
});

describe('Global accessAgreement', () => {
it('should not override local access agreement', () => {
const resultConfig = createConfig(
ConfigSchema.validate({
authc: {
accessAgreement: { message: 'foo' },
providers: {
basic: {
basic1: { order: 0, accessAgreement: { message: 'bar' } },
},
saml: {
saml1: { order: 1, realm: 'saml1', accessAgreement: { message: 'baz' } },
saml2: { order: 2, realm: 'saml2' },
},
oidc: {
oidc1: { order: 3, realm: 'oidc1' },
oidc2: { order: 4, realm: 'oidc2', accessAgreement: { message: 'qux' } },
},
},
},
}),
loggingSystemMock.create().get(),
{ isTLSEnabled: true }
);

expect(resultConfig.authc.providers.basic?.basic1.accessAgreement?.message).toBe('bar');
expect(resultConfig.authc.providers.saml?.saml1.accessAgreement?.message).toBe('baz');
expect(resultConfig.authc.providers.saml?.saml2.accessAgreement?.message).toBe('foo');
expect(resultConfig.authc.providers.oidc?.oidc1.accessAgreement?.message).toBe('foo');
expect(resultConfig.authc.providers.oidc?.oidc2.accessAgreement?.message).toBe('qux');
});
});

describe('#getExpirationTimeouts', () => {
function createMockConfig(config: Record<string, any> = {}) {
return createConfig(ConfigSchema.validate(config), loggingSystemMock.createLogger(), {
Expand Down
40 changes: 38 additions & 2 deletions x-pack/plugins/security/server/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ function getUniqueProviderSchema<TProperties extends Record<string, Type<any>>>(
}

type ProvidersConfigType = TypeOf<typeof providersConfigSchema>;

const providersConfigSchema = schema.object(
{
basic: getUniqueProviderSchema('basic', {
Expand Down Expand Up @@ -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() })),
Copy link
Member

@azasypkin azasypkin Aug 24, 2022

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?

Copy link
Member

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?

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)

Copy link
Contributor Author

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

Copy link
Member

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

Awesome, thanks!

(Also @/kurt should be @kc13greiner)

😬 ugh

providers: schema.oneOf([schema.arrayOf(schema.string()), providersConfigSchema], {
defaultValue: {
basic: {
Expand Down Expand Up @@ -306,6 +308,7 @@ export function createConfig(
}

let secureCookies = config.secureCookies;

if (!isTLSEnabled) {
if (secureCookies) {
logger.warn(
Expand All @@ -322,7 +325,8 @@ export function createConfig(
}

const isUsingLegacyProvidersFormat = Array.isArray(config.authc.providers);
const providers = (

let providers = (
isUsingLegacyProvidersFormat
? [...new Set(config.authc.providers as Array<keyof ProvidersConfigType>)].reduce(
(legacyProviders, providerType, order) => {
Expand All @@ -332,35 +336,66 @@ export function createConfig(
? { enabled: true, showInSelector: true, order, ...config.authc[providerType] }
: { enabled: true, showInSelector: true, order },
};

return legacyProviders;
},
{} as Record<string, unknown>
)
: config.authc.providers
) as ProvidersConfigType;

const updatedProvidersWithAccessAgreement: Record<string, object> = {};

// Remove disabled providers and sort the rest.
const sortedProviders: Array<{
type: keyof ProvidersConfigType;
name: string;
order: number;
hasAccessAgreement: boolean;
}> = [];

for (const [type, providerGroup] of Object.entries(providers)) {
for (const [name, { enabled, order, accessAgreement }] of Object.entries(providerGroup ?? {})) {
const hasLocalAccessAgreement: boolean = !!accessAgreement?.message;
Copy link
Member

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?

Copy link
Contributor Author

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

const globalAccessAgreement = config.authc?.accessAgreement?.message;

const currType = {
...updatedProvidersWithAccessAgreement[type],
[name]: {
...providerGroup[name],
},
};

if (!hasLocalAccessAgreement) {
if (globalAccessAgreement) {
currType[name] = {
...currType[name],
accessAgreement: {
message: globalAccessAgreement,
},
};
}
}

updatedProvidersWithAccessAgreement[type] = currType;

if (!enabled) {
delete providerGroup![name];
} else {
const hasAccessAgreement: boolean = hasLocalAccessAgreement || !!globalAccessAgreement;

sortedProviders.push({
type: type as any,
name,
order,
hasAccessAgreement: !!accessAgreement?.message,
hasAccessAgreement,
});
}
}
}

providers = updatedProvidersWithAccessAgreement as ProvidersConfigType;

sortedProviders.sort(({ order: orderA }, { order: orderB }) =>
orderA < orderB ? -1 : orderA > orderB ? 1 : 0
);
Expand Down Expand Up @@ -391,6 +426,7 @@ export function createConfig(
max: 10,
},
} as AppenderConfigType);

return {
...config,
audit: {
Expand Down