-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
Conversation
c587775
to
a585f9c
Compare
07dbc21
to
3d97e8c
Compare
3d97e8c
to
c85de9d
Compare
@@ -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` |
There was a problem hiding this comment.
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({ |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL!
Pinging @elastic/kibana-security (Team:Security) |
ACK: reviewing |
There was a problem hiding this 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:
kibana/x-pack/plugins/security/server/plugin.test.ts
Lines 46 to 47 in 951aa66
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'>; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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. | |||
*/ |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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()) { |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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] || [] |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 = ( |
There was a problem hiding this comment.
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 🙂
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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 🙈
💚 Build SucceededMetrics [docs]
History
To update your PR or re-run it, just comment with: |
…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
7.x/7.12.0: 22d85e7 |
The last PR in a series of PRs to migrate Security plugin to a new Elasticsearch client:
ElasticsearchClientPlugin
as we can now use either Client's default method ortransport.request
(for SAML/OIDC/PKI only)Blocked by: #87091