-
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
Implement HTTP Authentication provider and allow ApiKey
authentication by default.
#58126
Changes from 1 commit
dd03c4f
caed9b3
f7df6fd
f5c22f1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -149,14 +149,8 @@ export class CaseService { | |
} | ||
}, | ||
getUser: async ({ request, response }: GetUserArgs) => { | ||
let user; | ||
try { | ||
this.log.debug(`Attempting to authenticate a user`); | ||
user = await authentication!.getCurrentUser(request); | ||
} catch (error) { | ||
this.log.debug(`Error on GET user: ${error}`); | ||
throw error; | ||
} | ||
this.log.debug(`Attempting to authenticate a user`); | ||
const user = authentication!.getCurrentUser(request); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note: |
||
if (!user) { | ||
this.log.debug(`Error on GET user: Bad User`); | ||
throw new Error('Bad User - the user is not authenticated'); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ import { | |
TokenAuthenticationProvider, | ||
OIDCAuthenticationProvider, | ||
PKIAuthenticationProvider, | ||
HTTPAuthenticationProvider, | ||
isSAMLRequestQuery, | ||
} from './providers'; | ||
import { AuthenticationResult } from './authentication_result'; | ||
|
@@ -105,6 +106,7 @@ const providerMap = new Map< | |
[TokenAuthenticationProvider.type, TokenAuthenticationProvider], | ||
[OIDCAuthenticationProvider.type, OIDCAuthenticationProvider], | ||
[PKIAuthenticationProvider.type, PKIAuthenticationProvider], | ||
[HTTPAuthenticationProvider.type, HTTPAuthenticationProvider], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we get some benefit I'm not realizing from making the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Not really, was experimenting with different options and just stopped at some point.
Yep, that would simplify the config part.
That's a great idea! But I'd propose slightly modified version - |
||
]); | ||
|
||
function assertRequest(request: KibanaRequest) { | ||
|
@@ -191,6 +193,7 @@ export class Authenticator { | |
client: this.options.clusterClient, | ||
logger: this.options.loggers.get('tokens'), | ||
}), | ||
isProviderEnabled: this.isProviderEnabled.bind(this), | ||
}; | ||
|
||
const authProviders = this.options.config.authc.providers; | ||
|
@@ -206,6 +209,8 @@ export class Authenticator { | |
? (this.options.config.authc as Record<string, any>)[providerType] | ||
: undefined; | ||
|
||
this.logger.debug(`Enabling "${providerType}" authentication provider.`); | ||
|
||
return [ | ||
providerType, | ||
instantiateProvider( | ||
|
@@ -385,6 +390,14 @@ export class Authenticator { | |
return null; | ||
} | ||
|
||
/** | ||
* Checks whether specified provider type is currently enabled. | ||
* @param providerType Type of the provider (`basic`, `saml`, `pki` etc.). | ||
*/ | ||
isProviderEnabled(providerType: string) { | ||
return this.providers.has(providerType); | ||
} | ||
|
||
/** | ||
* Returns provider iterator where providers are sorted in the order of priority (based on the session ownership). | ||
* @param sessionValue Current session value. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { httpServerMock } from '../../../../../src/core/server/http/http_server.mocks'; | ||
|
||
import { getHTTPAuthenticationScheme } from './get_http_authentication_scheme'; | ||
|
||
describe('getHTTPAuthenticationScheme', () => { | ||
it('returns `null` if request does not have authorization header', () => { | ||
expect(getHTTPAuthenticationScheme(httpServerMock.createKibanaRequest())).toBeNull(); | ||
}); | ||
|
||
it('returns `null` if authorization header value isn not a string', () => { | ||
expect( | ||
getHTTPAuthenticationScheme( | ||
httpServerMock.createKibanaRequest({ | ||
headers: { authorization: ['Basic xxx', 'Bearer xxx'] as any }, | ||
}) | ||
) | ||
).toBeNull(); | ||
}); | ||
|
||
it('returns `null` if authorization header value is an empty string', () => { | ||
expect( | ||
getHTTPAuthenticationScheme( | ||
httpServerMock.createKibanaRequest({ headers: { authorization: '' } }) | ||
) | ||
).toBeNull(); | ||
}); | ||
|
||
it('returns only scheme portion of the authorization header value in lower case', () => { | ||
const headerValueAndSchemeMap = [ | ||
['Basic xxx', 'basic'], | ||
['Basic xxx yyy', 'basic'], | ||
['basic xxx', 'basic'], | ||
['basic', 'basic'], | ||
// We don't trim leading whitespaces in scheme. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. note: we never trimmed so we're not changing anything here (not sure if Core HTTP service does this though). |
||
[' Basic xxx', ''], | ||
['Negotiate xxx', 'negotiate'], | ||
['negotiate xxx', 'negotiate'], | ||
['negotiate', 'negotiate'], | ||
['ApiKey xxx', 'apikey'], | ||
['apikey xxx', 'apikey'], | ||
['Api Key xxx', 'api'], | ||
]; | ||
|
||
for (const [authorization, scheme] of headerValueAndSchemeMap) { | ||
expect( | ||
getHTTPAuthenticationScheme( | ||
httpServerMock.createKibanaRequest({ headers: { authorization } }) | ||
) | ||
).toBe(scheme); | ||
} | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License; | ||
* you may not use this file except in compliance with the Elastic License. | ||
*/ | ||
|
||
import { KibanaRequest } from '../../../../../src/core/server'; | ||
|
||
/** | ||
* Parses request's `Authorization` HTTP header if present and extracts authentication scheme. | ||
* https://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml#authschemes | ||
* @param request Request instance to extract authentication scheme for. | ||
*/ | ||
export function getHTTPAuthenticationScheme(request: KibanaRequest) { | ||
const authorizationHeaderValue = request.headers.authorization; | ||
if (!authorizationHeaderValue || typeof authorizationHeaderValue !== 'string') { | ||
return null; | ||
} | ||
|
||
return authorizationHeaderValue.split(/\s+/)[0].toLowerCase(); | ||
} |
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: consumers are supposed to use mocks provided by the plugin itself and to not redefine it to be as much in sync with real types as possible.