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

Migrate authentication functionality to a new Elasticsearch client. #87094

Merged
merged 5 commits into from
Jan 21, 2021

Conversation

azasypkin
Copy link
Member

@azasypkin azasypkin commented Dec 31, 2020

The last PR in a series of PRs to migrate Security plugin to a new Elasticsearch client:

  • Authentication sub-system is migrated to a new ES client
  • Session management sub-system is migrated to a new ES client
  • Completely removed ElasticsearchClientPlugin as we can now use either Client's default method or transport.request (for SAML/OIDC/PKI only)

Blocked by: #87091

@azasypkin azasypkin added chore Feature:New Platform Team:Security Team focused on: Auth, Users, Roles, Spaces, Audit Logging, and more! Feature:Security/Authentication Platform Security - Authentication release_note:skip Skip the PR/issue when compiling release notes v7.12.0 labels Dec 31, 2020
@azasypkin azasypkin force-pushed the issue-xxx-new-es-client branch 3 times, most recently from c587775 to a585f9c Compare January 11, 2021 13:47
@azasypkin azasypkin force-pushed the issue-xxx-new-es-client branch 2 times, most recently from 07dbc21 to 3d97e8c Compare January 12, 2021 14:58
@azasypkin azasypkin force-pushed the issue-xxx-new-es-client branch from 3d97e8c to c85de9d Compare January 15, 2021 09:58
@@ -332,11 +335,14 @@ export class KerberosAuthenticationProvider extends BaseAuthenticationProvider {
* Extracts `Negotiate` challenge from the list of challenges returned with Elasticsearch error if any.
* @param error Error to extract challenges from.
*/
private getNegotiateChallenge(error: LegacyElasticsearchError) {
private getNegotiateChallenge(error: errors.ResponseError) {
// We extract headers from the original Elasticsearch error and not from the top-level `headers`
Copy link
Member Author

Choose a reason for hiding this comment

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

note: well, in fact it's NodeJS that merges these headers, but we can pretend we don't know that 🙂

body: { x509_certificate_chain: certificateChain },
});
result = (
await this.options.client.asInternalUser.transport.request({
Copy link
Member Author

@azasypkin azasypkin Jan 15, 2021

Choose a reason for hiding this comment

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

note: hopefully we can publish spec for this API in the future (being discussed in https://github.com/elastic/elasticsearch/issues/67189)

const { body: response } = await this.options.elasticsearchClient.deleteByQuery(
{
index: this.indexName,
refresh: true,
Copy link
Member Author

Choose a reason for hiding this comment

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

note: wait_for is actually not supported by the deleteByQuery

Copy link
Member

Choose a reason for hiding this comment

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

TIL!

@azasypkin azasypkin removed the blocked label Jan 15, 2021
@azasypkin azasypkin marked this pull request as ready for review January 15, 2021 12:32
@azasypkin azasypkin requested a review from a team as a code owner January 15, 2021 12:32
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-security (Team:Security)

@legrego
Copy link
Member

legrego commented Jan 21, 2021

ACK: reviewing

Copy link
Member

@legrego legrego left a comment

Choose a reason for hiding this comment

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

This was a ton of work, nice job! Just a few optional nits and questions, so I won't hold up approval. Thanks for taking care of this 💚

We also have some stray setup of the legacy client in plugin.test.ts that we can cleanup:

mockClusterClient = elasticsearchServiceMock.createLegacyCustomClusterClient();
mockCoreSetup.elasticsearch.legacy.createClient.mockReturnValue(mockClusterClient);

@@ -60,7 +56,7 @@ export interface SecurityPluginSetup {
/**
* @deprecated Use `authc` methods from the `SecurityServiceStart` contract instead.
*/
authc: Pick<AuthenticationServiceSetup, 'getCurrentUser'>;
authc: Pick<AuthenticationServiceStart, 'getCurrentUser'>;
Copy link
Member

Choose a reason for hiding this comment

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

It feels strange to export a start service from our setup contract. I can live with this since it's deprecated though

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, you're right, I'll just duplicate definition here.

* you may not use this file except in compliance with the Elastic License.
*/

export function elasticsearchClientPlugin(Client: any, config: unknown, components: any) {
Copy link
Member

Choose a reason for hiding this comment

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

🎉

const { body: response } = await this.options.elasticsearchClient.deleteByQuery(
{
index: this.indexName,
refresh: true,
Copy link
Member

Choose a reason for hiding this comment

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

TIL!

@@ -4,50 +4,52 @@
* you may not use this file except in compliance with the Elastic License.
*/
Copy link
Member

Choose a reason for hiding this comment

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

I really like how we can mock the explicit API calls that we expect to make, without having to mock the generic callAsInternalUser anymore and hope that we're calling it correctly 🏅

});
} = (
await this.options.client.security.getToken<{
access_token: string;
Copy link
Member

Choose a reason for hiding this comment

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

question Do you know if there type improvements we can eventually upstream to the ES client, or is this intentionally generic? I know there are varied responses from ES that we can get here, but there appers to be some common fields that we could potentially leverage.

Copy link
Member Author

Choose a reason for hiding this comment

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

AFAIK we'll get much better type definitions soon, see #83808 for more details.

Once this merges I think we can improve missing pieces on case-by-case basis.

http.registerAuth(async (request, response, t) => {
// If security is disabled continue with no user credentials and delete the client cookie as well.
if (!license.isEnabled()) {
return t.authenticated();
}

if (!this.authenticator) {
this.logger.error('Authenticator is not initialized yet.');
return response.internalError();
Copy link
Member

Choose a reason for hiding this comment

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

Would 503 be more appropriate?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, agree, will change, thanks!

const apiKeys = new APIKeys({
clusterClient,
logger: this.logger.get('api-key'),
license: this.license,
});

const getCurrentUser = (request: KibanaRequest) => {
if (!this.license.isEnabled()) {
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 know you just moved this as-is from setup, but is there a reason we need to perform a license check here?

If the license doesn't enable security, then we'd presumably not have an AuthenticatedUser on the request state, so we'd still end up returning null.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point, let me double check.

const challenges = ([] as string[]).concat(
(error.output.headers as { [key: string]: string })[WWWAuthenticateHeaderName]
error.body?.error?.header?.[WWWAuthenticateHeaderName] || []
Copy link
Member

Choose a reason for hiding this comment

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

note: I didn't test this as part of my review, but I will if you'd like me to.

Copy link
Member Author

Choose a reason for hiding this comment

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

No worries, I specifically checked this. We have integration tests that test this behavior and they failed when I initially tried to use error.headers.

realm: this.realm,
},
});
result = (
Copy link
Member

Choose a reason for hiding this comment

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

nit: for the endpoints where we need to use transport.request, can we add a comment linking to https://github.com/elastic/elasticsearch/issues/67189? That will be really helpful for future me to remember why we did it this way 🙂

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, will do, thanks!

path: '/_security/oidc/prepare',
body: params,
})
).body as any;
Copy link
Member

Choose a reason for hiding this comment

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

image

I kid, I think this is tolerable for now given our usage

Copy link
Member Author

Choose a reason for hiding this comment

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

🤣 Yeah, that's exactly how I feel about it 🙈

@kibanamachine
Copy link
Contributor

💚 Build Succeeded

Metrics [docs]

✅ unchanged

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

@azasypkin azasypkin merged commit f668972 into elastic:master Jan 21, 2021
@azasypkin azasypkin deleted the issue-xxx-new-es-client branch January 21, 2021 20:10
azasypkin added a commit to azasypkin/kibana that referenced this pull request Jan 21, 2021
…lastic#87094)

# Conflicts:
#	x-pack/plugins/security/server/authentication/authentication_service.ts
#	x-pack/plugins/security/server/authentication/providers/base.mock.ts
#	x-pack/plugins/security/server/authentication/providers/saml.test.ts
#	x-pack/plugins/security/server/authentication/providers/saml.ts
@azasypkin
Copy link
Member Author

7.x/7.12.0: 22d85e7

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backported chore Feature:New Platform Feature:Security/Authentication Platform Security - Authentication release_note:skip Skip the PR/issue when compiling release notes Team:Security Team focused on: Auth, Users, Roles, Spaces, Audit Logging, and more! v7.12.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants