diff --git a/x-pack/plugins/security/server/authentication/authentication_service.ts b/x-pack/plugins/security/server/authentication/authentication_service.ts index cf99084d4d0b..5498175cfd93 100644 --- a/x-pack/plugins/security/server/authentication/authentication_service.ts +++ b/x-pack/plugins/security/server/authentication/authentication_service.ts @@ -194,9 +194,7 @@ export class AuthenticationService { } const isAuthRoute = request.route.options.tags.includes(ROUTE_TAG_AUTH_FLOW); - const isLogoutRoute = - request.route.path === '/api/security/logout' || - request.route.path === '/api/v1/security/logout'; + const isLogoutRoute = request.route.path === '/api/security/logout'; // If users can eventually re-login we want to redirect them directly to the page they tried // to access initially, but we only want to do that for routes that aren't part of the various diff --git a/x-pack/plugins/security/server/authentication/providers/saml.test.ts b/x-pack/plugins/security/server/authentication/providers/saml.test.ts index 15ff615af9ad..1674ea347986 100644 --- a/x-pack/plugins/security/server/authentication/providers/saml.test.ts +++ b/x-pack/plugins/security/server/authentication/providers/saml.test.ts @@ -788,7 +788,7 @@ describe('SAMLAuthenticationProvider', () => { method: 'POST', path: '/_security/saml/prepare', body: { - acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/v1/saml', + acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/saml/callback', }, }); @@ -830,7 +830,7 @@ describe('SAMLAuthenticationProvider', () => { method: 'POST', path: '/_security/saml/prepare', body: { - acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/v1/saml', + acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/saml/callback', }, }); @@ -900,7 +900,7 @@ describe('SAMLAuthenticationProvider', () => { method: 'POST', path: '/_security/saml/prepare', body: { - acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/v1/saml', + acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/saml/callback', }, }); }); @@ -1003,7 +1003,7 @@ describe('SAMLAuthenticationProvider', () => { method: 'POST', path: '/_security/saml/prepare', body: { - acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/v1/saml', + acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/saml/callback', }, }); }); @@ -1294,7 +1294,7 @@ describe('SAMLAuthenticationProvider', () => { path: '/_security/saml/invalidate', body: { query_string: 'SAMLRequest=xxx%20yyy', - acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/v1/saml', + acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/saml/callback', }, }); }); @@ -1408,7 +1408,7 @@ describe('SAMLAuthenticationProvider', () => { path: '/_security/saml/invalidate', body: { query_string: 'SAMLRequest=xxx%20yyy', - acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/v1/saml', + acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/saml/callback', }, }); }); @@ -1430,7 +1430,7 @@ describe('SAMLAuthenticationProvider', () => { path: '/_security/saml/invalidate', body: { query_string: 'SAMLRequest=xxx%20yyy', - acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/v1/saml', + acs: 'test-protocol://test-hostname:1234/mock-server-basepath/api/security/saml/callback', }, }); }); diff --git a/x-pack/plugins/security/server/authentication/providers/saml.ts b/x-pack/plugins/security/server/authentication/providers/saml.ts index 56dbd78b2ef3..5f8545003d04 100644 --- a/x-pack/plugins/security/server/authentication/providers/saml.ts +++ b/x-pack/plugins/security/server/authentication/providers/saml.ts @@ -659,7 +659,7 @@ export class SAMLAuthenticationProvider extends BaseAuthenticationProvider { private getACS() { return `${this.options.getServerBaseURL()}${ this.options.basePath.serverBasePath - }/api/security/v1/saml`; + }/api/security/saml/callback`; } /** diff --git a/x-pack/plugins/security/server/routes/authentication/common.ts b/x-pack/plugins/security/server/routes/authentication/common.ts index 4ee2e57a3351..0b182f706ada 100644 --- a/x-pack/plugins/security/server/routes/authentication/common.ts +++ b/x-pack/plugins/security/server/routes/authentication/common.ts @@ -7,7 +7,6 @@ import type { TypeOf } from '@kbn/config-schema'; import { schema } from '@kbn/config-schema'; -import { i18n } from '@kbn/i18n'; import { parseNextURL } from '@kbn/std'; import type { RouteDefinitionParams } from '..'; @@ -36,124 +35,67 @@ export function defineCommonRoutes({ buildFlavor, docLinks, }: RouteDefinitionParams) { - // Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used. - // For a serverless build, do not register deprecated versioned routes - for (const path of [ - '/api/security/logout', - ...(buildFlavor !== 'serverless' ? ['/api/security/v1/logout'] : []), - ]) { - const isDeprecated = path === '/api/security/v1/logout'; - router.get( - { - path, - security: { - authz: { - enabled: false, - reason: 'This route must remain accessible to 3rd-party IdPs', - }, - }, - // Allow unknown query parameters as this endpoint can be hit by the 3rd-party with any - // set of query string parameters (e.g. SAML/OIDC logout request/response parameters). - validate: { query: schema.object({}, { unknowns: 'allow' }) }, - options: { - access: 'public', - excludeFromOAS: true, - authRequired: false, - tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], - ...(isDeprecated && { - deprecated: { - documentationUrl: docLinks.links.security.deprecatedV1Endpoints, - severity: 'warning', - message: i18n.translate('xpack.security.deprecations.logoutRouteMessage', { - defaultMessage: - 'The "{path}" URL is deprecated and will be removed in the next major version. Use "/api/security/logout" instead.', - values: { path }, - }), - reason: { - type: 'migrate', - newApiMethod: 'GET', - newApiPath: '/api/security/logout', - }, - }, - }), + router.get( + { + path: '/api/security/logout', + security: { + authz: { + enabled: false, + reason: 'This route must remain accessible to 3rd-party IdPs', }, }, - async (context, request, response) => { - const serverBasePath = basePath.serverBasePath; - if (isDeprecated) { - logger.warn( - `The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version. Use "${serverBasePath}/api/security/logout" URL instead.`, - { tags: ['deprecation'] } - ); - } + // Allow unknown query parameters as this endpoint can be hit by the 3rd-party with any + // set of query string parameters (e.g. SAML/OIDC logout request/response parameters). + validate: { query: schema.object({}, { unknowns: 'allow' }) }, + options: { + access: 'public', + excludeFromOAS: true, + authRequired: false, + tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], + }, + }, + async (context, request, response) => { + const serverBasePath = basePath.serverBasePath; + if (!canRedirectRequest(request)) { + return response.badRequest({ + body: 'Client should be able to process redirect response.', + }); + } - if (!canRedirectRequest(request)) { - return response.badRequest({ - body: 'Client should be able to process redirect response.', - }); + try { + const deauthenticationResult = await getAuthenticationService().logout(request); + if (deauthenticationResult.failed()) { + return response.customError(wrapIntoCustomErrorResponse(deauthenticationResult.error)); } - try { - const deauthenticationResult = await getAuthenticationService().logout(request); - if (deauthenticationResult.failed()) { - return response.customError(wrapIntoCustomErrorResponse(deauthenticationResult.error)); - } - - return response.redirected({ - headers: { location: deauthenticationResult.redirectURL || `${serverBasePath}/` }, - }); - } catch (error) { - return response.customError(wrapIntoCustomErrorResponse(error)); - } + return response.redirected({ + headers: { location: deauthenticationResult.redirectURL || `${serverBasePath}/` }, + }); + } catch (error) { + return response.customError(wrapIntoCustomErrorResponse(error)); } - ); - } + } + ); - // Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used. - // For a serverless build, do not register deprecated versioned routes - for (const path of [ - '/internal/security/me', - ...(buildFlavor !== 'serverless' ? ['/api/security/v1/me'] : []), - ]) { - const isDeprecated = path === '/api/security/v1/me'; - router.get( - { - path, - security: { - authz: { - enabled: false, - reason: `This route delegates authorization to Core's security service; there must be an authenticated user for this route to return information`, - }, - }, - validate: false, - options: { - access: isDeprecated ? 'public' : 'internal', - ...(isDeprecated && { - deprecated: { - documentationUrl: docLinks.links.security.deprecatedV1Endpoints, - severity: 'warning', - message: i18n.translate('xpack.security.deprecations.meRouteMessage', { - defaultMessage: - 'The "{path}" endpoint is deprecated and will be removed in the next major version.', - values: { path }, - }), - reason: { type: 'remove' }, - }, - }), + router.get( + { + path: '/internal/security/me', + security: { + authz: { + enabled: false, + reason: `This route delegates authorization to Core's security service; there must be an authenticated user for this route to return information`, }, }, - createLicensedRouteHandler(async (context, request, response) => { - if (isDeprecated) { - logger.warn( - `The "${basePath.serverBasePath}${path}" endpoint is deprecated and will be removed in the next major version.`, - { tags: ['deprecation'] } - ); - } - const { security: coreSecurity } = await context.core; - return response.ok({ body: coreSecurity.authc.getCurrentUser()! }); - }) - ); - } + validate: false, + options: { + access: 'internal', + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + const { security: coreSecurity } = await context.core; + return response.ok({ body: coreSecurity.authc.getCurrentUser()! }); + }) + ); const basicParamsSchema = schema.object({ username: schema.string({ minLength: 1 }), diff --git a/x-pack/plugins/security/server/routes/authentication/oidc.ts b/x-pack/plugins/security/server/routes/authentication/oidc.ts index d1d31f4c49a6..c3e7673e3a19 100644 --- a/x-pack/plugins/security/server/routes/authentication/oidc.ts +++ b/x-pack/plugins/security/server/routes/authentication/oidc.ts @@ -27,58 +27,32 @@ export function defineOIDCRoutes({ basePath, docLinks, }: RouteDefinitionParams) { - // Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used. - for (const path of ['/api/security/oidc/implicit', '/api/security/v1/oidc/implicit']) { - const isDeprecated = path === '/api/security/v1/oidc/implicit'; - /** - * The route should be configured as a redirect URI in OP when OpenID Connect implicit flow - * is used, so that we can extract authentication response from URL fragment and send it to - * the `/api/security/oidc/callback` route. - */ - httpResources.register( - { - path, - validate: false, - options: { - authRequired: false, - excludeFromOAS: true, - ...(isDeprecated && { - deprecated: { - documentationUrl: docLinks.links.security.deprecatedV1Endpoints, - severity: 'warning', - message: i18n.translate('xpack.security.deprecations.oidcImplicitRouteMessage', { - defaultMessage: - 'The "{path}" URL is deprecated and will be removed in the next major version. Use "/api/security/oidc/implicit" instead.', - values: { path }, - }), - reason: { - type: 'migrate', - newApiMethod: 'GET', - newApiPath: '/api/security/oidc/implicit', - }, - }, - }), - }, + /** + * The route should be configured as a redirect URI in OP when OpenID Connect implicit flow + * is used, so that we can extract authentication response from URL fragment and send it to + * the `/api/security/oidc/callback` route. + */ + httpResources.register( + { + path: '/api/security/oidc/implicit', + validate: false, + options: { + authRequired: false, + excludeFromOAS: true, }, - (context, request, response) => { - const serverBasePath = basePath.serverBasePath; - if (isDeprecated) { - logger.warn( - `The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version. Use "${serverBasePath}/api/security/oidc/implicit" URL instead.`, - { tags: ['deprecation'] } - ); - } - return response.renderHtml({ - body: ` + }, + (context, request, response) => { + const serverBasePath = basePath.serverBasePath; + return response.renderHtml({ + body: ` Kibana OpenID Connect Login `, - }); - } - ); - } + }); + } + ); /** * The route that accompanies `/api/security/oidc/implicit` and renders a JavaScript snippet @@ -103,183 +77,122 @@ export function defineOIDCRoutes({ } ); - // Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used. - for (const path of ['/api/security/oidc/callback', '/api/security/v1/oidc']) { - const isDeprecated = path === '/api/security/v1/oidc'; - router.get( - { - path, - security: { - authz: { - enabled: false, - reason: 'This route must remain accessible to 3rd-party OIDC providers', - }, - }, - validate: { - query: schema.object( - { - authenticationResponseURI: schema.maybe(schema.uri()), - code: schema.maybe(schema.string()), - error: schema.maybe(schema.string()), - error_description: schema.maybe(schema.string()), - error_uri: schema.maybe(schema.uri()), - iss: schema.maybe(schema.uri({ scheme: ['https'] })), - login_hint: schema.maybe(schema.string()), - target_link_uri: schema.maybe(schema.uri()), - state: schema.maybe(schema.string()), - }, - // The client MUST ignore unrecognized response parameters according to - // https://openid.net/specs/openid-connect-core-1_0.html#AuthResponseValidation and - // https://tools.ietf.org/html/rfc6749#section-4.1.2. - { unknowns: 'allow' } - ), - }, - options: { - access: 'public', - excludeFromOAS: true, - authRequired: false, - tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], - ...(isDeprecated && { - deprecated: { - documentationUrl: docLinks.links.security.deprecatedV1Endpoints, - severity: 'warning', - message: i18n.translate('xpack.security.deprecations.oidcCallbackRouteMessage', { - defaultMessage: - 'The "{path}" URL is deprecated and will be removed in the next major version. Use "/api/security/oidc/callback" instead.', - values: { path }, - }), - reason: { - type: 'migrate', - newApiMethod: 'GET', - newApiPath: '/api/security/oidc/callback', - }, - }, - }), + router.get( + { + path: '/api/security/oidc/callback', + security: { + authz: { + enabled: false, + reason: 'This route must remain accessible to 3rd-party OIDC providers', }, }, - createLicensedRouteHandler(async (context, request, response) => { - const serverBasePath = basePath.serverBasePath; - - // An HTTP GET request with a query parameter named `authenticationResponseURI` that includes URL fragment OpenID - // Connect Provider sent during implicit authentication flow to the Kibana own proxy page that extracted that URL - // fragment and put it into `authenticationResponseURI` query string parameter for this endpoint. See more details - // at https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth - let loginAttempt: ProviderLoginAttempt | undefined; - if (request.query.authenticationResponseURI) { - loginAttempt = { - type: OIDCLogin.LoginWithImplicitFlow, - authenticationResponseURI: request.query.authenticationResponseURI, - }; - } else if (request.query.code || request.query.error) { - if (isDeprecated) { - logger.warn( - `The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version. Use "${serverBasePath}/api/security/oidc/callback" URL instead.`, - { tags: ['deprecation'] } - ); - } - - // An HTTP GET request with a query parameter named `code` (or `error`) as the response to a successful (or - // failed) authentication from an OpenID Connect Provider during authorization code authentication flow. - // See more details at https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth. - loginAttempt = { - type: OIDCLogin.LoginWithAuthorizationCodeFlow, - // We pass the path only as we can't be sure of the full URL and Elasticsearch doesn't need it anyway. - authenticationResponseURI: request.url.pathname + request.url.search, - }; - } else if (request.query.iss) { - logger.warn( - `The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version. Use "${serverBasePath}/api/security/oidc/initiate_login" URL for Third-Party Initiated login instead.`, - { tags: ['deprecation'] } - ); - // An HTTP GET request with a query parameter named `iss` as part of a 3rd party initiated authentication. - // See more details at https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin - loginAttempt = { - type: OIDCLogin.LoginInitiatedBy3rdParty, - iss: request.query.iss, - loginHint: request.query.login_hint, - }; - } + validate: { + query: schema.object( + { + authenticationResponseURI: schema.maybe(schema.uri()), + code: schema.maybe(schema.string()), + error: schema.maybe(schema.string()), + error_description: schema.maybe(schema.string()), + error_uri: schema.maybe(schema.uri()), + iss: schema.maybe(schema.uri({ scheme: ['https'] })), + login_hint: schema.maybe(schema.string()), + target_link_uri: schema.maybe(schema.uri()), + state: schema.maybe(schema.string()), + }, + // The client MUST ignore unrecognized response parameters according to + // https://openid.net/specs/openid-connect-core-1_0.html#AuthResponseValidation and + // https://tools.ietf.org/html/rfc6749#section-4.1.2. + { unknowns: 'allow' } + ), + }, + options: { + access: 'public', + excludeFromOAS: true, + authRequired: false, + tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + // An HTTP GET request with a query parameter named `authenticationResponseURI` that includes URL fragment OpenID + // Connect Provider sent during implicit authentication flow to the Kibana own proxy page that extracted that URL + // fragment and put it into `authenticationResponseURI` query string parameter for this endpoint. See more details + // at https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth + let loginAttempt: ProviderLoginAttempt | undefined; + if (request.query.authenticationResponseURI) { + loginAttempt = { + type: OIDCLogin.LoginWithImplicitFlow, + authenticationResponseURI: request.query.authenticationResponseURI, + }; + } else if (request.query.code || request.query.error) { + // An HTTP GET request with a query parameter named `code` (or `error`) as the response to a successful (or + // failed) authentication from an OpenID Connect Provider during authorization code authentication flow. + // See more details at https://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth. + loginAttempt = { + type: OIDCLogin.LoginWithAuthorizationCodeFlow, + // We pass the path only as we can't be sure of the full URL and Elasticsearch doesn't need it anyway. + authenticationResponseURI: request.url.pathname + request.url.search, + }; + } else if (request.query.iss) { + // An HTTP GET request with a query parameter named `iss` as part of a 3rd party initiated authentication. + // See more details at https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin + loginAttempt = { + type: OIDCLogin.LoginInitiatedBy3rdParty, + iss: request.query.iss, + loginHint: request.query.login_hint, + }; + } - if (!loginAttempt) { - return response.badRequest({ - body: 'Unrecognized login attempt.', - }); - } + if (!loginAttempt) { + return response.badRequest({ + body: 'Unrecognized login attempt.', + }); + } - return performOIDCLogin(request, response, loginAttempt); - }) - ); - } + return performOIDCLogin(request, response, loginAttempt); + }) + ); - // Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used. - for (const path of ['/api/security/oidc/initiate_login', '/api/security/v1/oidc']) { - const isDeprecated = path === '/api/security/v1/oidc'; - /** - * An HTTP POST request with the payload parameter named `iss` as part of a 3rd party initiated authentication. - * See more details at https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin - */ - router.post( - { - path, - security: { - authz: { - enabled: false, - reason: 'This route must remain accessible to 3rd-party OIDC providers', - }, - }, - validate: { - body: schema.object( - { - iss: schema.uri({ scheme: ['https'] }), - login_hint: schema.maybe(schema.string()), - target_link_uri: schema.maybe(schema.uri()), - }, - // Other parameters MAY be sent, if defined by extensions. Any parameters used that are not understood MUST - // be ignored by the Client according to https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin. - { unknowns: 'allow' } - ), - }, - options: { - access: 'public', - excludeFromOAS: true, - authRequired: false, - xsrfRequired: false, - tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], - ...(isDeprecated && { - deprecated: { - documentationUrl: docLinks.links.security.deprecatedV1Endpoints, - severity: 'warning', - message: i18n.translate('xpack.security.deprecations.oidcInitiateRouteMessage', { - defaultMessage: - 'The "{path}" URL is deprecated and will be removed in the next major version. Use "/api/security/oidc/initiate_login" instead.', - values: { path }, - }), - reason: { - type: 'migrate', - newApiMethod: 'POST', - newApiPath: '/api/security/oidc/initiate_login', - }, - }, - }), + /** + * An HTTP POST request with the payload parameter named `iss` as part of a 3rd party initiated authentication. + * See more details at https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin + */ + router.post( + { + path: '/api/security/oidc/initiate_login', + security: { + authz: { + enabled: false, + reason: 'This route must remain accessible to 3rd-party OIDC providers', }, }, - createLicensedRouteHandler(async (context, request, response) => { - const serverBasePath = basePath.serverBasePath; - if (isDeprecated) { - logger.warn( - `The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version. Use "${serverBasePath}/api/security/oidc/initiate_login" URL for Third-Party Initiated login instead.`, - { tags: ['deprecation'] } - ); - } - - return performOIDCLogin(request, response, { - type: OIDCLogin.LoginInitiatedBy3rdParty, - iss: request.body.iss, - loginHint: request.body.login_hint, - }); - }) - ); - } + validate: { + body: schema.object( + { + iss: schema.uri({ scheme: ['https'] }), + login_hint: schema.maybe(schema.string()), + target_link_uri: schema.maybe(schema.uri()), + }, + // Other parameters MAY be sent, if defined by extensions. Any parameters used that are not understood MUST + // be ignored by the Client according to https://openid.net/specs/openid-connect-core-1_0.html#ThirdPartyInitiatedLogin. + { unknowns: 'allow' } + ), + }, + options: { + access: 'public', + excludeFromOAS: true, + authRequired: false, + xsrfRequired: false, + tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], + }, + }, + createLicensedRouteHandler(async (context, request, response) => { + return performOIDCLogin(request, response, { + type: OIDCLogin.LoginInitiatedBy3rdParty, + iss: request.body.iss, + loginHint: request.body.login_hint, + }); + }) + ); /** * An HTTP GET request with the query string parameter named `iss` as part of a 3rd party initiated authentication. diff --git a/x-pack/plugins/security/server/routes/authentication/saml.test.ts b/x-pack/plugins/security/server/routes/authentication/saml.test.ts index f693d20354e8..e7aa7bc5cc4b 100644 --- a/x-pack/plugins/security/server/routes/authentication/saml.test.ts +++ b/x-pack/plugins/security/server/routes/authentication/saml.test.ts @@ -43,15 +43,6 @@ describe('SAML authentication routes', () => { routeHandler = acsRouteHandler; }); - it('additionally registers BWC route', () => { - expect( - router.post.mock.calls.find(([{ path }]) => path === '/api/security/saml/callback') - ).toBeDefined(); - expect( - router.post.mock.calls.find(([{ path }]) => path === '/api/security/v1/saml') - ).toBeDefined(); - }); - it('correctly defines route.', () => { expect(routeConfig.options).toEqual({ access: 'public', diff --git a/x-pack/plugins/security/server/routes/authentication/saml.ts b/x-pack/plugins/security/server/routes/authentication/saml.ts index c45f1eed3aff..8da7ff284a4b 100644 --- a/x-pack/plugins/security/server/routes/authentication/saml.ts +++ b/x-pack/plugins/security/server/routes/authentication/saml.ts @@ -6,7 +6,6 @@ */ import { schema } from '@kbn/config-schema'; -import { i18n } from '@kbn/i18n'; import type { RouteDefinitionParams } from '..'; import { SAMLAuthenticationProvider, SAMLLogin } from '../../authentication'; @@ -23,79 +22,47 @@ export function defineSAMLRoutes({ buildFlavor, docLinks, }: RouteDefinitionParams) { - // Generate two identical routes with new and deprecated URL and issue a warning if route with deprecated URL is ever used. - // For a serverless build, do not register deprecated versioned routes - for (const path of [ - '/api/security/saml/callback', - ...(buildFlavor !== 'serverless' ? ['/api/security/v1/saml'] : []), - ]) { - const isDeprecated = path === '/api/security/v1/saml'; - router.post( - { - path, - security: { - authz: { - enabled: false, - reason: 'This route must remain accessible to 3rd-party SAML providers', - }, - }, - validate: { - body: schema.object( - { SAMLResponse: schema.string(), RelayState: schema.maybe(schema.string()) }, - { unknowns: 'ignore' } - ), - }, - options: { - access: 'public', - excludeFromOAS: true, - authRequired: false, - xsrfRequired: false, - tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], - ...(isDeprecated && { - deprecated: { - documentationUrl: docLinks.links.security.deprecatedV1Endpoints, - severity: 'warning', - message: i18n.translate('xpack.security.deprecations.samlPostRouteMessage', { - defaultMessage: - 'The "{path}" URL is deprecated and will be removed in the next major version. Use "/api/security/saml/callback" instead.', - values: { path }, - }), - reason: { - type: 'migrate', - newApiMethod: 'POST', - newApiPath: '/api/security/saml/callback', - }, - }, - }), + router.post( + { + path: '/api/security/saml/callback', + security: { + authz: { + enabled: false, + reason: 'This route must remain accessible to 3rd-party SAML providers', }, }, - async (context, request, response) => { - if (isDeprecated) { - const serverBasePath = basePath.serverBasePath; - logger.warn( - // When authenticating using SAML we _expect_ to redirect to the SAML Identity provider. - `The "${serverBasePath}${path}" URL is deprecated and might stop working in a future release. Use "${serverBasePath}/api/security/saml/callback" URL instead.` - ); - } + validate: { + body: schema.object( + { SAMLResponse: schema.string(), RelayState: schema.maybe(schema.string()) }, + { unknowns: 'ignore' } + ), + }, + options: { + access: 'public', + excludeFromOAS: true, + authRequired: false, + xsrfRequired: false, + tags: [ROUTE_TAG_CAN_REDIRECT, ROUTE_TAG_AUTH_FLOW], + }, + }, + async (context, request, response) => { + // When authenticating using SAML we _expect_ to redirect to the Kibana target location. + const authenticationResult = await getAuthenticationService().login(request, { + provider: { type: SAMLAuthenticationProvider.type }, + value: { + type: SAMLLogin.LoginWithSAMLResponse, + samlResponse: request.body.SAMLResponse, + relayState: request.body.RelayState, + }, + }); - // When authenticating using SAML we _expect_ to redirect to the Kibana target location. - const authenticationResult = await getAuthenticationService().login(request, { - provider: { type: SAMLAuthenticationProvider.type }, - value: { - type: SAMLLogin.LoginWithSAMLResponse, - samlResponse: request.body.SAMLResponse, - relayState: request.body.RelayState, - }, + if (authenticationResult.redirected()) { + return response.redirected({ + headers: { location: authenticationResult.redirectURL! }, }); - - if (authenticationResult.redirected()) { - return response.redirected({ - headers: { location: authenticationResult.redirectURL! }, - }); - } - - return response.unauthorized({ body: authenticationResult.error }); } - ); - } + + return response.unauthorized({ body: authenticationResult.error }); + } + ); }