From 5eaf4727f567c70c4c8eeacb776654bf1575eee9 Mon Sep 17 00:00:00 2001 From: Aleh Zasypkin Date: Mon, 19 Jul 2021 09:42:56 +0200 Subject: [PATCH] Provide sensible defaults for `xpack.security.session.{lifespan|idleTimeout}`. --- docs/settings/security-settings.asciidoc | 6 +-- .../user/security/session-management.asciidoc | 8 +-- x-pack/plugins/security/server/config.test.ts | 54 ++++++++++--------- x-pack/plugins/security/server/config.ts | 23 +++----- .../server/session_management/session.test.ts | 16 +++--- .../session_management/session_index.test.ts | 12 +++-- 6 files changed, 60 insertions(+), 59 deletions(-) diff --git a/docs/settings/security-settings.asciidoc b/docs/settings/security-settings.asciidoc index bd714c62ff5437..32f086072b157b 100644 --- a/docs/settings/security-settings.asciidoc +++ b/docs/settings/security-settings.asciidoc @@ -271,7 +271,7 @@ You can configure the following settings in the `kibana.yml` file. |[[xpack-session-idleTimeout]] `xpack.security.session.idleTimeout` {ess-icon} | Ensures that user sessions will expire after a period of inactivity. This and <> are both -highly recommended. You can also specify this setting for <>. If this is _not_ set or set to `0`, then sessions will never expire due to inactivity. By default, this setting is not set. +highly recommended. You can also specify this setting for <>. If this is set to `0`, then sessions will never expire due to inactivity. By default, this value is 1 hour. 2+a| [TIP] @@ -281,8 +281,8 @@ Use a string of `[ms\|s\|m\|h\|d\|w\|M\|Y]` (e.g. '20m', '24h', '7d', '1w |[[xpack-session-lifespan]] `xpack.security.session.lifespan` {ess-icon} | Ensures that user sessions will expire after the defined time period. This behavior is also known as an "absolute timeout". If -this is _not_ set or set to `0`, user sessions could stay active indefinitely. This and <> are both highly -recommended. You can also specify this setting for <>. By default, this setting is not set. +this is set to `0`, user sessions could stay active indefinitely. This and <> are both highly +recommended. You can also specify this setting for <>. By default, this value is 30 days. 2+a| [TIP] diff --git a/docs/user/security/session-management.asciidoc b/docs/user/security/session-management.asciidoc index ac7a777eb05807..4c1792fc9ab7e3 100644 --- a/docs/user/security/session-management.asciidoc +++ b/docs/user/security/session-management.asciidoc @@ -12,24 +12,24 @@ To manage user sessions programmatically, {kib} exposes <[ms|s|m|h|d|w|M|Y]` (e.g. '20m', '24h', '7d', '1w'). For example, set the idle timeout to expire sessions after 1 hour of inactivity: +By default, sessions expire after 1 hour of inactivity. To define another value for a sliding session expiration, set the property in the `kibana.yml` configuration file. The idle timeout is formatted as a duration of `[ms|s|m|h|d|w|M|Y]` (e.g. '20m', '24h', '7d', '1w'). For example, set the idle timeout to expire sessions after 30 minutes of inactivity: -- [source,yaml] -------------------------------------------------------------------------------- -xpack.security.session.idleTimeout: "1h" +xpack.security.session.idleTimeout: "30m" -------------------------------------------------------------------------------- -- [[session-lifespan]] ==== Session lifespan -You can use `xpack.security.session.lifespan` to configure the maximum session duration or "lifespan" -- also known as the "absolute timeout". This and `xpack.security.session.idleTimeout` are both highly recommended. By default, sessions don't have a fixed lifespan, and if an idle timeout is defined, a session can still be extended indefinitely. To define a maximum session lifespan, set the property in the `kibana.yml` configuration file. The lifespan is formatted as a duration of `[ms|s|m|h|d|w|M|Y]` (e.g. '20m', '24h', '7d', '1w'). For example, set the lifespan to expire sessions after 30 days: +You can use `xpack.security.session.lifespan` to configure the maximum session duration or "lifespan" -- also known as the "absolute timeout". This and `xpack.security.session.idleTimeout` are both highly recommended. By default, a maximum session lifespan is 30 days. To define another lifespan, set the property in the `kibana.yml` configuration file. The lifespan is formatted as a duration of `[ms|s|m|h|d|w|M|Y]` (e.g. '20m', '24h', '7d', '1w'). For example, set the lifespan to expire sessions after 7 days: -- [source,yaml] -------------------------------------------------------------------------------- -xpack.security.session.lifespan: "30d" +xpack.security.session.lifespan: "7d" -------------------------------------------------------------------------------- -- diff --git a/x-pack/plugins/security/server/config.test.ts b/x-pack/plugins/security/server/config.test.ts index 9e266d774e86ec..4593d9a7ad6820 100644 --- a/x-pack/plugins/security/server/config.test.ts +++ b/x-pack/plugins/security/server/config.test.ts @@ -61,6 +61,8 @@ describe('config schema', () => { "secureCookies": false, "session": Object { "cleanupInterval": "PT1H", + "idleTimeout": "PT1H", + "lifespan": "P30D", }, } `); @@ -110,6 +112,8 @@ describe('config schema', () => { "secureCookies": false, "session": Object { "cleanupInterval": "PT1H", + "idleTimeout": "PT1H", + "lifespan": "P30D", }, } `); @@ -158,6 +162,8 @@ describe('config schema', () => { "secureCookies": false, "session": Object { "cleanupInterval": "PT1H", + "idleTimeout": "PT1H", + "lifespan": "P30D", }, } `); @@ -1615,11 +1621,11 @@ describe('createConfig()', () => { it('returns default values if neither global nor provider specific settings are set', async () => { expect(createMockConfig().session.getExpirationTimeouts({ type: 'basic', name: 'basic1' })) .toMatchInlineSnapshot(` - Object { - "idleTimeout": null, - "lifespan": null, - } - `); + Object { + "idleTimeout": "PT1H", + "lifespan": "P30D", + } + `); }); it('correctly handles explicitly disabled global settings', async () => { @@ -1653,11 +1659,11 @@ describe('createConfig()', () => { name: 'basic1', }) ).toMatchInlineSnapshot(` - Object { - "idleTimeout": "PT0.123S", - "lifespan": null, - } - `); + Object { + "idleTimeout": "PT0.123S", + "lifespan": "P30D", + } + `); expect( createMockConfig({ session: { lifespan: 456 } }).session.getExpirationTimeouts({ @@ -1665,11 +1671,11 @@ describe('createConfig()', () => { name: 'basic1', }) ).toMatchInlineSnapshot(` - Object { - "idleTimeout": null, - "lifespan": "PT0.456S", - } - `); + Object { + "idleTimeout": "PT1H", + "lifespan": "PT0.456S", + } + `); expect( createMockConfig({ @@ -1692,7 +1698,7 @@ describe('createConfig()', () => { ).toMatchInlineSnapshot(` Object { "idleTimeout": "PT0.123S", - "lifespan": null, + "lifespan": "P30D", } `); @@ -1703,7 +1709,7 @@ describe('createConfig()', () => { }) ).toMatchInlineSnapshot(` Object { - "idleTimeout": null, + "idleTimeout": "PT1H", "lifespan": "PT0.456S", } `); @@ -1734,14 +1740,14 @@ describe('createConfig()', () => { .toMatchInlineSnapshot(` Object { "idleTimeout": "PT0.321S", - "lifespan": null, + "lifespan": "P30D", } `); expect(configWithoutGlobal.session.getExpirationTimeouts({ type: 'saml', name: 'saml1' })) .toMatchInlineSnapshot(` Object { "idleTimeout": "PT5M32.211S", - "lifespan": null, + "lifespan": "P30D", } `); @@ -1758,14 +1764,14 @@ describe('createConfig()', () => { .toMatchInlineSnapshot(` Object { "idleTimeout": "PT0.321S", - "lifespan": null, + "lifespan": "P30D", } `); expect(configWithGlobal.session.getExpirationTimeouts({ type: 'saml', name: 'saml1' })) .toMatchInlineSnapshot(` Object { "idleTimeout": "PT5M32.211S", - "lifespan": null, + "lifespan": "P30D", } `); }); @@ -1783,14 +1789,14 @@ describe('createConfig()', () => { expect(configWithoutGlobal.session.getExpirationTimeouts({ type: 'basic', name: 'basic1' })) .toMatchInlineSnapshot(` Object { - "idleTimeout": null, + "idleTimeout": "PT1H", "lifespan": "PT0.654S", } `); expect(configWithoutGlobal.session.getExpirationTimeouts({ type: 'saml', name: 'saml1' })) .toMatchInlineSnapshot(` Object { - "idleTimeout": null, + "idleTimeout": "PT1H", "lifespan": "PT11M5.544S", } `); @@ -1807,7 +1813,7 @@ describe('createConfig()', () => { expect(configWithGlobal.session.getExpirationTimeouts({ type: 'basic', name: 'basic1' })) .toMatchInlineSnapshot(` Object { - "idleTimeout": null, + "idleTimeout": "PT1H", "lifespan": "PT0.654S", } `); diff --git a/x-pack/plugins/security/server/config.ts b/x-pack/plugins/security/server/config.ts index ce83a92e23ae7f..6ce161a8988109 100644 --- a/x-pack/plugins/security/server/config.ts +++ b/x-pack/plugins/security/server/config.ts @@ -209,8 +209,12 @@ export const ConfigSchema = schema.object({ schema.string({ minLength: 32, defaultValue: 'a'.repeat(32) }) ), session: schema.object({ - idleTimeout: schema.maybe(schema.oneOf([schema.duration(), schema.literal(null)])), - lifespan: schema.maybe(schema.oneOf([schema.duration(), schema.literal(null)])), + idleTimeout: schema.oneOf([schema.duration(), schema.literal(null)], { + defaultValue: schema.duration().validate('1h'), + }), + lifespan: schema.oneOf([schema.duration(), schema.literal(null)], { + defaultValue: schema.duration().validate('30d'), + }), cleanupInterval: schema.duration({ defaultValue: '1h', validate(value) { @@ -385,7 +389,6 @@ export function createConfig( } function getSessionConfig(session: RawConfigType['session'], providers: ProvidersConfigType) { - const defaultAnonymousSessionLifespan = schema.duration().validate('30d'); return { cleanupInterval: session.cleanupInterval, getExpirationTimeouts({ type, name }: AuthenticationProvider) { @@ -393,21 +396,9 @@ function getSessionConfig(session: RawConfigType['session'], providers: Provider // possible types of values: `Duration`, `null` and `undefined`. The `undefined` type means that // provider doesn't override session config and we should fall back to the global one instead. const providerSessionConfig = providers[type as keyof ProvidersConfigType]?.[name]?.session; - - // We treat anonymous sessions differently since users can create them without realizing it. This may lead to a - // non controllable amount of sessions stored in the session index. To reduce the impact we set a 30 days lifespan - // for the anonymous sessions in case neither global nor provider specific lifespan is configured explicitly. - // We can remove this code once https://github.com/elastic/kibana/issues/68885 is resolved. - const providerLifespan = - type === 'anonymous' && - providerSessionConfig?.lifespan === undefined && - session.lifespan === undefined - ? defaultAnonymousSessionLifespan - : providerSessionConfig?.lifespan; - const [idleTimeout, lifespan] = [ [session.idleTimeout, providerSessionConfig?.idleTimeout], - [session.lifespan, providerLifespan], + [session.lifespan, providerSessionConfig?.lifespan], ].map(([globalTimeout, providerTimeout]) => { const timeout = providerTimeout === undefined ? globalTimeout ?? null : providerTimeout; return timeout && timeout.asMilliseconds() > 0 ? timeout : null; diff --git a/x-pack/plugins/security/server/session_management/session.test.ts b/x-pack/plugins/security/server/session_management/session.test.ts index dfe6ba343ca3c0..e1c67dca667f75 100644 --- a/x-pack/plugins/security/server/session_management/session.test.ts +++ b/x-pack/plugins/security/server/session_management/session.test.ts @@ -358,7 +358,7 @@ describe('Session', () => { session = new Session({ logger: loggingSystemMock.createLogger(), config: createConfig( - ConfigSchema.validate({ session: { idleTimeout: 123 } }), + ConfigSchema.validate({ session: { idleTimeout: 123, lifespan: null } }), loggingSystemMock.createLogger(), { isTLSEnabled: false } ), @@ -398,7 +398,7 @@ describe('Session', () => { session = new Session({ logger: loggingSystemMock.createLogger(), config: createConfig( - ConfigSchema.validate({ session: { lifespan } }), + ConfigSchema.validate({ session: { idleTimeout: null, lifespan } }), loggingSystemMock.createLogger(), { isTLSEnabled: false } ), @@ -472,9 +472,11 @@ describe('Session', () => { session = new Session({ logger: loggingSystemMock.createLogger(), - config: createConfig(ConfigSchema.validate({}), loggingSystemMock.createLogger(), { - isTLSEnabled: false, - }), + config: createConfig( + ConfigSchema.validate({ session: { idleTimeout: null, lifespan: null } }), + loggingSystemMock.createLogger(), + { isTLSEnabled: false } + ), sessionCookie: mockSessionCookie, sessionIndex: mockSessionIndex, }); @@ -527,7 +529,7 @@ describe('Session', () => { session = new Session({ logger: loggingSystemMock.createLogger(), config: createConfig( - ConfigSchema.validate({ session: { idleTimeout: 123 } }), + ConfigSchema.validate({ session: { idleTimeout: 123, lifespan: null } }), loggingSystemMock.createLogger(), { isTLSEnabled: false } ), @@ -718,7 +720,7 @@ describe('Session', () => { session = new Session({ logger: loggingSystemMock.createLogger(), config: createConfig( - ConfigSchema.validate({ session: { lifespan } }), + ConfigSchema.validate({ session: { idleTimeout: null, lifespan } }), loggingSystemMock.createLogger(), { isTLSEnabled: false } ), diff --git a/x-pack/plugins/security/server/session_management/session_index.test.ts b/x-pack/plugins/security/server/session_management/session_index.test.ts index 11fb4ca27f5902..bf99f4926b1d67 100644 --- a/x-pack/plugins/security/server/session_management/session_index.test.ts +++ b/x-pack/plugins/security/server/session_management/session_index.test.ts @@ -26,9 +26,11 @@ describe('Session index', () => { const sessionIndexOptions = { logger: loggingSystemMock.createLogger(), kibanaIndexName: '.kibana_some_tenant', - config: createConfig(ConfigSchema.validate({}), loggingSystemMock.createLogger(), { - isTLSEnabled: false, - }), + config: createConfig( + ConfigSchema.validate({ session: { idleTimeout: null, lifespan: null } }), + loggingSystemMock.createLogger(), + { isTLSEnabled: false } + ), elasticsearchClient: mockElasticsearchClient, }; @@ -239,7 +241,7 @@ describe('Session index', () => { logger: loggingSystemMock.createLogger(), kibanaIndexName: '.kibana_some_tenant', config: createConfig( - ConfigSchema.validate({ session: { lifespan: 456 } }), + ConfigSchema.validate({ session: { idleTimeout: null, lifespan: 456 } }), loggingSystemMock.createLogger(), { isTLSEnabled: false } ), @@ -315,7 +317,7 @@ describe('Session index', () => { logger: loggingSystemMock.createLogger(), kibanaIndexName: '.kibana_some_tenant', config: createConfig( - ConfigSchema.validate({ session: { idleTimeout } }), + ConfigSchema.validate({ session: { idleTimeout, lifespan: null } }), loggingSystemMock.createLogger(), { isTLSEnabled: false } ),