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

Surface Kibana security route deprecations in Upgrade Assistant #199656

Merged
merged 14 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
38 changes: 26 additions & 12 deletions docs/upgrade-notes.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,32 @@ For Elastic Security release information, refer to {security-guide}/release-note
[float]
==== Kibana APIs

[discrete]
[[breaking-199656]]
.Removed all security v1 endpoints (9.0.0)
[%collapsible]
====
*Details* +
All `v1` Kibana security HTTP endpoints have been removed.

`GET /api/security/v1/logout` has been replaced by `GET /api/security/logout`
`GET /api/security/v1/oidc/implicit` has been replaced by `GET /api/security/oidc/implicit`
`GET /api/security/v1/oidc` has been replaced by GET `/api/security/oidc/callback`
`POST /api/security/v1/oidc` has been replaced by POST `/api/security/oidc/initiate_login`
`POST /api/security/v1/saml` has been replaced by POST `/api/security/saml/callback`
`GET /api/security/v1/me` has been removed with no replacement.

For more information, refer to {kibana-pull}199656[#199656].

*Impact* +
Any HTTP API calls to the `v1` Kibana security endpoints will fail with a 404 status code starting from version 9.0.0.
Third party OIDC and SAML identity providers configured with `v1` endpoints will no longer work.

*Action* +
Update any OIDC and SAML identity providers to reference the corresponding replacement endpoint listed above.
Remove references to the `/api/security/v1/me` endpoint from any automations, applications, tooling, and scripts.
====

[discrete]
[[breaking-193792]]
.Access to all internal APIs is blocked (9.0.0)
Expand Down Expand Up @@ -814,18 +840,6 @@ The legacy audit logger has been removed. For more information, refer to {kibana
Audit logs will be written to the default location in the new ECS format. To change the output file, filter events, and more, use the <<audit-logging-settings, audit logging settings>>.
====

[discrete]
[[breaking-47929]]
.[Security] Removed `/api/security/v1/saml` route. (8.0)
[%collapsible]
====
*Details* +
The `/api/security/v1/saml` route has been removed and is reflected in the kibana.yml `server.xsrf.whitelist` setting, {es}, and the Identity Provider SAML settings. For more information, refer to {kibana-pull}47929[#47929]

*Impact* +
Use the `/api/security/saml/callback` route, or wait to upgrade to 8.0.0-alpha2 when the `/api/security/saml/callback` route breaking change is reverted.
====
Comment on lines -817 to -827
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opted to remove this section as it seemed redundant with the new section. Plus it was only applicable to 8.0.0-alpha1.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After #199519 main will only contain 9.0+ changes for this file


[discrete]
[[breaking-41700]]
.[Security] Legacy browsers rejected by default. (8.0)
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-doc-links/src/get_doc_links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,7 @@ export const getDocLinks = ({ kibanaBranch, buildFlavor }: GetDocLinkOptions): D
mappingRoles: `${ELASTICSEARCH_DOCS}mapping-roles.html`,
mappingRolesFieldRules: `${ELASTICSEARCH_DOCS}role-mapping-resources.html#mapping-roles-rule-field`,
runAsPrivilege: `${ELASTICSEARCH_DOCS}security-privileges.html#_run_as_privilege`,
deprecatedV1Endpoints: `${KIBANA_DOCS}breaking-changes-summary.html#breaking-199656`,
},
spaces: {
kibanaLegacyUrlAliases: `${KIBANA_DOCS}legacy-url-aliases.html`,
Expand Down
1 change: 1 addition & 0 deletions packages/kbn-doc-links/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,7 @@ export interface DocLinks {
mappingRoles: string;
mappingRolesFieldRules: string;
runAsPrivilege: string;
deprecatedV1Endpoints: string;
}>;
readonly spaces: Readonly<{
kibanaLegacyUrlAliases: string;
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/security/server/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ export class SecurityPlugin
getUserProfileService: this.getUserProfileService,
analyticsService: this.analyticsService.setup({ analytics: core.analytics }),
buildFlavor: this.initializerContext.env.packageInfo.buildFlavor,
docLinks: core.docLinks,
});

return Object.freeze<SecurityPluginSetup>({
Expand Down
43 changes: 38 additions & 5 deletions x-pack/plugins/security/server/routes/authentication/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

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 '..';
Expand All @@ -33,13 +34,15 @@ export function defineCommonRoutes({
license,
logger,
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,
Expand All @@ -57,13 +60,29 @@ export function defineCommonRoutes({
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',
},
},
}),
},
},
async (context, request, response) => {
const serverBasePath = basePath.serverBasePath;
if (path === '/api/security/v1/logout') {
if (isDeprecated) {
logger.warn(
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/logout" URL instead.`,
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version. Use "${serverBasePath}/api/security/logout" URL instead.`,
{ tags: ['deprecation'] }
);
}
Expand Down Expand Up @@ -96,7 +115,7 @@ export function defineCommonRoutes({
'/internal/security/me',
...(buildFlavor !== 'serverless' ? ['/api/security/v1/me'] : []),
]) {
const deprecated = path === '/api/security/v1/me';
const isDeprecated = path === '/api/security/v1/me';
router.get(
{
path,
Expand All @@ -107,10 +126,24 @@ export function defineCommonRoutes({
},
},
validate: false,
options: { access: deprecated ? 'public' : 'internal' },
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' },
},
}),
},
},
createLicensedRouteHandler(async (context, request, response) => {
if (deprecated) {
if (isDeprecated) {
logger.warn(
`The "${basePath.serverBasePath}${path}" endpoint is deprecated and will be removed in the next major version.`,
{ tags: ['deprecation'] }
Expand Down
71 changes: 63 additions & 8 deletions x-pack/plugins/security/server/routes/authentication/oidc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@ export function defineOIDCRoutes({
logger,
getAuthenticationService,
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
Expand All @@ -37,13 +39,32 @@ export function defineOIDCRoutes({
{
path,
validate: false,
options: { authRequired: false, excludeFromOAS: true },
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',
},
},
}),
},
},
(context, request, response) => {
const serverBasePath = basePath.serverBasePath;
if (path === '/api/security/v1/oidc/implicit') {
if (isDeprecated) {
logger.warn(
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/oidc/implicit" URL instead.`,
`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'] }
);
}
Expand Down Expand Up @@ -84,6 +105,7 @@ 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,
Expand Down Expand Up @@ -117,6 +139,22 @@ export function defineOIDCRoutes({
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',
},
},
}),
},
},
createLicensedRouteHandler(async (context, request, response) => {
Expand All @@ -133,9 +171,9 @@ export function defineOIDCRoutes({
authenticationResponseURI: request.query.authenticationResponseURI,
};
} else if (request.query.code || request.query.error) {
if (path === '/api/security/v1/oidc') {
if (isDeprecated) {
logger.warn(
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/oidc/callback" URL instead.`,
`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'] }
);
}
Expand All @@ -150,7 +188,7 @@ export function defineOIDCRoutes({
};
} else if (request.query.iss) {
logger.warn(
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/oidc/initiate_login" URL for Third-Party Initiated login instead.`,
`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.
Expand All @@ -175,6 +213,7 @@ 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/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
Expand Down Expand Up @@ -206,13 +245,29 @@ export function defineOIDCRoutes({
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',
},
},
}),
},
},
createLicensedRouteHandler(async (context, request, response) => {
const serverBasePath = basePath.serverBasePath;
if (path === '/api/security/v1/oidc') {
if (isDeprecated) {
logger.warn(
`The "${serverBasePath}${path}" URL is deprecated and will stop working in the next major version, please use "${serverBasePath}/api/security/oidc/initiate_login" URL for Third-Party Initiated login instead.`,
`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'] }
);
}
Expand Down
23 changes: 21 additions & 2 deletions x-pack/plugins/security/server/routes/authentication/saml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import { schema } from '@kbn/config-schema';
import { i18n } from '@kbn/i18n';

import type { RouteDefinitionParams } from '..';
import { SAMLAuthenticationProvider, SAMLLogin } from '../../authentication';
Expand All @@ -20,13 +21,15 @@ export function defineSAMLRoutes({
basePath,
logger,
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,
Expand All @@ -48,14 +51,30 @@ export function defineSAMLRoutes({
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',
},
},
}),
},
},
async (context, request, response) => {
if (path === '/api/security/v1/saml') {
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. Please use "${serverBasePath}/api/security/saml/callback" URL instead.`
`The "${serverBasePath}${path}" URL is deprecated and might stop working in a future release. Use "${serverBasePath}/api/security/saml/callback" URL instead.`
);
}

Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/security/server/routes/index.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
httpServiceMock,
loggingSystemMock,
} from '@kbn/core/server/mocks';
import { getDocLinks } from '@kbn/doc-links';
import { licensingMock } from '@kbn/licensing-plugin/server/mocks';
import type { DeeplyMockedKeys } from '@kbn/utility-types-jest';

Expand Down Expand Up @@ -50,6 +51,8 @@ export const routeDefinitionParamsMock = {
getAnonymousAccessService: jest.fn(),
getUserProfileService: jest.fn().mockReturnValue(userProfileServiceMock.createStart()),
analyticsService: analyticsServiceMock.createSetup(),
buildFlavor: 'traditional',
docLinks: { links: getDocLinks({ kibanaBranch: 'main', buildFlavor: 'traditional' }) },
} as unknown as DeeplyMockedKeys<RouteDefinitionParams>;
},
};
Expand Down
3 changes: 2 additions & 1 deletion x-pack/plugins/security/server/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import type { Observable } from 'rxjs';

import type { BuildFlavor } from '@kbn/config/src/types';
import type { HttpResources, IBasePath, Logger } from '@kbn/core/server';
import type { DocLinksServiceSetup, HttpResources, IBasePath, Logger } from '@kbn/core/server';
import type { KibanaFeature } from '@kbn/features-plugin/server';
import type { SubFeaturePrivilegeIterator } from '@kbn/features-plugin/server/feature_privilege_iterator';
import type { PublicMethodsOf } from '@kbn/utility-types';
Expand Down Expand Up @@ -59,6 +59,7 @@ export interface RouteDefinitionParams {
getAnonymousAccessService: () => AnonymousAccessServiceStart;
analyticsService: AnalyticsServiceSetup;
buildFlavor: BuildFlavor;
docLinks: DocLinksServiceSetup;
}

export function defineRoutes(params: RouteDefinitionParams) {
Expand Down
Loading