[6.8] Allow SAML IdP initiated login when SAML authentication provider is NOT configured as the first provider. (#60240)

This commit is contained in:
Aleh Zasypkin 2020-03-17 07:29:59 +01:00 committed by GitHub
parent 34147e8f79
commit dc91d17ffc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 509 additions and 12 deletions

View file

@ -134,7 +134,7 @@ class Authenticator {
const existingSession = await this._session.get(request);
let authenticationResult;
for (const [providerType, provider] of this._providerIterator(existingSession)) {
for (const [providerType, provider] of this._providerIterator(existingSession, request)) {
// Check if current session has been set by this provider.
const ownsSession = existingSession && existingSession.provider === providerType;
@ -208,7 +208,7 @@ class Authenticator {
// SP associated with the current user session to do the logout. So if Kibana (without active session)
// receives such a request it shouldn't redirect user to the home page, but rather redirect back to IdP
// with correct logout response and only Elasticsearch knows how to do that.
if (request.query.SAMLRequest && this._providers.has('saml')) {
if (this._isSAMLRequest(request) && this._providers.has('saml')) {
return this._providers.get('saml').deauthenticate(request);
}
@ -234,19 +234,22 @@ class Authenticator {
/**
* Returns provider iterator where providers are sorted in the order of priority (based on the session ownership).
* @param {Object} sessionValue Current session value.
* @param {Hapi.Request} request HapiJS request instance.
* @returns {Iterator.<Object>}
*/
*_providerIterator(sessionValue) {
// If there is no session to predict which provider to use first, let's use the order
// providers are configured in. Otherwise return provider that owns session first, and only then the rest
// of providers.
if (!sessionValue) {
*_providerIterator(sessionValue, request) {
// If there is no way to predict which provider to use first, let's use the order providers are configured in.
// Otherwise return provider that either owns session or can handle 3rd-party login request first, and only then
// the rest of providers.
const shouldHandleSAMLResponse = this._isSAMLResponse(request) && this._providers.has('saml');
if (!sessionValue && !shouldHandleSAMLResponse) {
yield* this._providers;
} else {
yield [sessionValue.provider, this._providers.get(sessionValue.provider)];
const provider = shouldHandleSAMLResponse ? 'saml' : sessionValue.provider;
yield [provider, this._providers.get(provider)];
for (const [providerType, provider] of this._providers) {
if (providerType !== sessionValue.provider) {
if (providerType !== provider) {
yield [providerType, provider];
}
}
@ -273,6 +276,27 @@ class Authenticator {
return sessionValue;
}
/**
* Checks whether specified request represents SAML Request.
* @param {Hapi.Request} request HapiJS request instance.
* @returns {boolean}
* @private
*/
_isSAMLRequest(request) {
return !!(request.query && request.query.SAMLRequest);
}
/**
* Checks whether specified request represents SAML Response.
* @param {Hapi.Request} request HapiJS request instance.
* @returns {boolean}
* @private
*/
_isSAMLResponse(request) {
return !!(request.payload && request.payload.SAMLResponse)
&& request.path === '/api/security/v1/saml';
}
}
export async function initAuthenticator(server, authorizationMode) {