mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[6.8] Allow SAML IdP initiated login when SAML authentication provider is NOT configured as the first provider. (#60240)
This commit is contained in:
parent
34147e8f79
commit
dc91d17ffc
8 changed files with 509 additions and 12 deletions
|
@ -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) {
|
||||
|
|
|
@ -21,6 +21,7 @@ require('@kbn/test').runTestsCli([
|
|||
require.resolve('../test/api_integration/config.js'),
|
||||
require.resolve('../test/plugin_api_integration/config.js'),
|
||||
require.resolve('../test/saml_api_integration/config.js'),
|
||||
require.resolve('../test/saml_api_integration/with_basic.config.js'),
|
||||
require.resolve('../test/token_api_integration/config.js'),
|
||||
require.resolve('../test/spaces_api_integration/spaces_only/config'),
|
||||
require.resolve('../test/spaces_api_integration/security_and_spaces/config_trial'),
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
export default function ({ loadTestFile }) {
|
||||
describe('apis SAML', function () {
|
||||
this.tags('ciGroup6');
|
||||
loadTestFile(require.resolve('./security'));
|
||||
loadTestFile(require.resolve('./saml_login'));
|
||||
});
|
||||
}
|
|
@ -5,7 +5,8 @@
|
|||
*/
|
||||
|
||||
export default function ({ loadTestFile }) {
|
||||
describe('security', () => {
|
||||
describe('apis SAML (with Basic)', function () {
|
||||
this.tags('ciGroup6');
|
||||
loadTestFile(require.resolve('./saml_login'));
|
||||
});
|
||||
}
|
443
x-pack/test/saml_api_integration/apis/with_basic/saml_login.js
Normal file
443
x-pack/test/saml_api_integration/apis/with_basic/saml_login.js
Normal file
|
@ -0,0 +1,443 @@
|
|||
/*
|
||||
* 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 querystring from 'querystring';
|
||||
import url from 'url';
|
||||
import { delay } from 'bluebird';
|
||||
import { getLogoutRequest, getSAMLResponse } from '../../fixtures/saml_tools';
|
||||
import expect from 'expect.js';
|
||||
import request from 'request';
|
||||
|
||||
export default function ({ getService }) {
|
||||
const chance = getService('chance');
|
||||
const supertest = getService('supertestWithoutAuth');
|
||||
const config = getService('config');
|
||||
|
||||
const kibanaServerConfig = config.get('servers.kibana');
|
||||
const basicUsername = kibanaServerConfig.username;
|
||||
const basicPassword = kibanaServerConfig.password;
|
||||
|
||||
function createSAMLResponse(options = {}) {
|
||||
return getSAMLResponse({
|
||||
destination: `http://localhost:${kibanaServerConfig.port}/api/security/v1/saml`,
|
||||
sessionIndex: chance.natural(),
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
function createLogoutRequest(options = {}) {
|
||||
return getLogoutRequest({
|
||||
destination: `http://localhost:${kibanaServerConfig.port}/logout`,
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
describe('SAML authentication (IdP initiated login)', () => {
|
||||
describe('initiating handshake', () => {
|
||||
it('should not initiate handshake and redirect to Kibana own login page.', async () => {
|
||||
const response = await supertest.get('/abc/xyz/handshake?one=two three')
|
||||
.expect(302);
|
||||
|
||||
expect(response.headers['set-cookie']).to.be(undefined);
|
||||
expect(response.headers.location).to.eql('/login?next=%2Fabc%2Fxyz%2Fhandshake%3Fone%3Dtwo%2520three');
|
||||
});
|
||||
});
|
||||
|
||||
describe('finishing handshake', () => {
|
||||
let basicCookie;
|
||||
beforeEach(async () => {
|
||||
const loginResponse = await supertest.post('/api/security/v1/login')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ username: basicUsername, password: basicPassword })
|
||||
.expect(204);
|
||||
|
||||
basicCookie = request.cookie(loginResponse.headers['set-cookie'][0]);
|
||||
});
|
||||
|
||||
it('should succeed in case of IdP initiated login', async () => {
|
||||
const samlAuthenticationResponse = await supertest.post('/api/security/v1/saml')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ SAMLResponse: await createSAMLResponse() }, {})
|
||||
.expect(302);
|
||||
|
||||
expect(samlAuthenticationResponse.headers.location).to.be('/');
|
||||
|
||||
const cookies = samlAuthenticationResponse.headers['set-cookie'];
|
||||
expect(cookies).to.have.length(1);
|
||||
|
||||
const sessionCookie = request.cookie(cookies[0]);
|
||||
expect(sessionCookie.key).to.be('sid');
|
||||
expect(sessionCookie.value).to.not.be.empty();
|
||||
expect(sessionCookie.path).to.be('/');
|
||||
expect(sessionCookie.httpOnly).to.be(true);
|
||||
|
||||
const apiResponse = await supertest
|
||||
.get('/api/security/v1/me')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(200);
|
||||
|
||||
expect(apiResponse.body).to.only.have.keys([
|
||||
'username',
|
||||
'full_name',
|
||||
'email',
|
||||
'roles',
|
||||
'scope',
|
||||
'metadata',
|
||||
'enabled',
|
||||
'authentication_realm',
|
||||
'lookup_realm',
|
||||
]);
|
||||
|
||||
expect(apiResponse.body.username).to.be('a@b.c');
|
||||
});
|
||||
|
||||
it('should succeed if both SAML response and basic cookie are provided', async () => {
|
||||
const samlAuthenticationResponse = await supertest.post('/api/security/v1/saml')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', basicCookie.cookieString())
|
||||
.send({ SAMLResponse: await createSAMLResponse() }, {})
|
||||
.expect(302);
|
||||
|
||||
expect(samlAuthenticationResponse.headers.location).to.be('/');
|
||||
|
||||
const cookies = samlAuthenticationResponse.headers['set-cookie'];
|
||||
expect(cookies).to.have.length(1);
|
||||
|
||||
const sessionCookie = request.cookie(cookies[0]);
|
||||
expect(sessionCookie.key).to.be('sid');
|
||||
expect(sessionCookie.value).to.not.be.empty();
|
||||
expect(sessionCookie.path).to.be('/');
|
||||
expect(sessionCookie.httpOnly).to.be(true);
|
||||
|
||||
const apiResponse = await supertest
|
||||
.get('/api/security/v1/me')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(200);
|
||||
|
||||
expect(apiResponse.body).to.only.have.keys([
|
||||
'username',
|
||||
'full_name',
|
||||
'email',
|
||||
'roles',
|
||||
'scope',
|
||||
'metadata',
|
||||
'enabled',
|
||||
'authentication_realm',
|
||||
'lookup_realm',
|
||||
]);
|
||||
|
||||
expect(apiResponse.body.username).to.be('a@b.c');
|
||||
});
|
||||
|
||||
it('should fail if SAML response is not valid', async () => {
|
||||
await supertest.post('/api/security/v1/saml')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', basicCookie.cookieString())
|
||||
.send({ SAMLResponse: await createSAMLResponse({ inResponseTo: 'some-invalid-request-id' }) }, {})
|
||||
.expect(401);
|
||||
});
|
||||
});
|
||||
|
||||
describe('logging out', () => {
|
||||
let sessionCookie;
|
||||
let idpSessionIndex;
|
||||
|
||||
beforeEach(async () => {
|
||||
idpSessionIndex = chance.natural();
|
||||
const samlAuthenticationResponse = await supertest.post('/api/security/v1/saml')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ SAMLResponse: await createSAMLResponse({ sessionIndex: idpSessionIndex }) }, {})
|
||||
.expect(302);
|
||||
|
||||
sessionCookie = request.cookie(samlAuthenticationResponse.headers['set-cookie'][0]);
|
||||
});
|
||||
|
||||
it('should redirect to IdP with SAML request to complete logout', async () => {
|
||||
const logoutResponse = await supertest.get('/api/security/v1/logout')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(302);
|
||||
|
||||
const cookies = logoutResponse.headers['set-cookie'];
|
||||
expect(cookies).to.have.length(1);
|
||||
|
||||
const logoutCookie = request.cookie(cookies[0]);
|
||||
expect(logoutCookie.key).to.be('sid');
|
||||
expect(logoutCookie.value).to.be.empty();
|
||||
expect(logoutCookie.path).to.be('/');
|
||||
expect(logoutCookie.httpOnly).to.be(true);
|
||||
expect(logoutCookie.maxAge).to.be(0);
|
||||
|
||||
const redirectURL = url.parse(logoutResponse.headers.location, true /* parseQueryString */);
|
||||
expect(redirectURL.href.startsWith(`https://elastic.co/slo/saml`)).to.be(true);
|
||||
expect(redirectURL.query.SAMLRequest).to.not.be.empty();
|
||||
|
||||
// Tokens that were stored in the previous cookie should be invalidated as well and old
|
||||
// session cookie should not allow API access.
|
||||
const apiResponse = await supertest
|
||||
.get('/api/security/v1/me')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(400);
|
||||
|
||||
expect(apiResponse.body).to.eql({
|
||||
error: 'Bad Request',
|
||||
message: 'Both access and refresh tokens are expired.',
|
||||
statusCode: 400
|
||||
});
|
||||
});
|
||||
|
||||
it('should redirect to home page if session cookie is not provided', async () => {
|
||||
const logoutResponse = await supertest.get('/api/security/v1/logout')
|
||||
.expect(302);
|
||||
|
||||
expect(logoutResponse.headers['set-cookie']).to.be(undefined);
|
||||
expect(logoutResponse.headers.location).to.be('/');
|
||||
});
|
||||
|
||||
it('should reject AJAX requests', async () => {
|
||||
const ajaxResponse = await supertest.get('/api/security/v1/logout')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(400);
|
||||
|
||||
expect(ajaxResponse.headers['set-cookie']).to.be(undefined);
|
||||
expect(ajaxResponse.body).to.eql({
|
||||
error: 'Bad Request',
|
||||
message: 'Client should be able to process redirect response.',
|
||||
statusCode: 400
|
||||
});
|
||||
});
|
||||
|
||||
it('should invalidate access token on IdP initiated logout', async () => {
|
||||
const logoutRequest = await createLogoutRequest({ sessionIndex: idpSessionIndex });
|
||||
const logoutResponse = await supertest.get(`/api/security/v1/logout?${querystring.stringify(logoutRequest)}`)
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(302);
|
||||
|
||||
const cookies = logoutResponse.headers['set-cookie'];
|
||||
expect(cookies).to.have.length(1);
|
||||
|
||||
const logoutCookie = request.cookie(cookies[0]);
|
||||
expect(logoutCookie.key).to.be('sid');
|
||||
expect(logoutCookie.value).to.be.empty();
|
||||
expect(logoutCookie.path).to.be('/');
|
||||
expect(logoutCookie.httpOnly).to.be(true);
|
||||
expect(logoutCookie.maxAge).to.be(0);
|
||||
|
||||
const redirectURL = url.parse(logoutResponse.headers.location, true /* parseQueryString */);
|
||||
expect(redirectURL.href.startsWith(`https://elastic.co/slo/saml`)).to.be(true);
|
||||
expect(redirectURL.query.SAMLResponse).to.not.be.empty();
|
||||
|
||||
// Tokens that were stored in the previous cookie should be invalidated as well and old session
|
||||
// cookie should not allow API access.
|
||||
const apiResponse = await supertest
|
||||
.get('/api/security/v1/me')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(400);
|
||||
|
||||
expect(apiResponse.body).to.eql({
|
||||
error: 'Bad Request',
|
||||
message: 'Both access and refresh tokens are expired.',
|
||||
statusCode: 400
|
||||
});
|
||||
});
|
||||
|
||||
it('should invalidate access token on IdP initiated logout even if there is no Kibana session', async () => {
|
||||
const logoutRequest = await createLogoutRequest({ sessionIndex: idpSessionIndex });
|
||||
const logoutResponse = await supertest.get(`/api/security/v1/logout?${querystring.stringify(logoutRequest)}`)
|
||||
.expect(302);
|
||||
|
||||
expect(logoutResponse.headers['set-cookie']).to.be(undefined);
|
||||
|
||||
const redirectURL = url.parse(logoutResponse.headers.location, true /* parseQueryString */);
|
||||
expect(redirectURL.href.startsWith(`https://elastic.co/slo/saml`)).to.be(true);
|
||||
expect(redirectURL.query.SAMLResponse).to.not.be.empty();
|
||||
|
||||
// Elasticsearch should find and invalidate access and refresh tokens that correspond to provided
|
||||
// IdP session id (encoded in SAML LogoutRequest) even if Kibana doesn't provide them and session
|
||||
// cookie with these tokens should not allow API access.
|
||||
const apiResponse = await supertest
|
||||
.get('/api/security/v1/me')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(400);
|
||||
|
||||
expect(apiResponse.body).to.eql({
|
||||
error: 'Bad Request',
|
||||
message: 'Both access and refresh tokens are expired.',
|
||||
statusCode: 400
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('API access with expired access token.', () => {
|
||||
let sessionCookie;
|
||||
|
||||
beforeEach(async () => {
|
||||
const samlAuthenticationResponse = await supertest.post('/api/security/v1/saml')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ SAMLResponse: await createSAMLResponse() }, {})
|
||||
.expect(302);
|
||||
|
||||
sessionCookie = request.cookie(samlAuthenticationResponse.headers['set-cookie'][0]);
|
||||
});
|
||||
|
||||
it('expired access token should be automatically refreshed', async function () {
|
||||
this.timeout(40000);
|
||||
|
||||
// Access token expiration is set to 15s for API integration tests.
|
||||
// Let's wait for 20s to make sure token expires.
|
||||
await delay(20000);
|
||||
|
||||
// This api call should succeed and automatically refresh token. Returned cookie will contain
|
||||
// the new access and refresh token pair.
|
||||
const apiResponse = await supertest
|
||||
.get('/api/security/v1/me')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(200);
|
||||
|
||||
const cookies = apiResponse.headers['set-cookie'];
|
||||
expect(cookies).to.have.length(1);
|
||||
|
||||
const newSessionCookie = request.cookie(cookies[0]);
|
||||
expect(newSessionCookie.key).to.be('sid');
|
||||
expect(newSessionCookie.value).to.not.be.empty();
|
||||
expect(newSessionCookie.path).to.be('/');
|
||||
expect(newSessionCookie.httpOnly).to.be(true);
|
||||
expect(newSessionCookie.value).to.not.be(sessionCookie.value);
|
||||
|
||||
// Request with old cookie should fail with `400` since it contains expired access token and
|
||||
// already used refresh tokens.
|
||||
const apiResponseWithExpiredToken = await supertest
|
||||
.get('/api/security/v1/me')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(400);
|
||||
expect(apiResponseWithExpiredToken.headers['set-cookie']).to.be(undefined);
|
||||
expect(apiResponseWithExpiredToken.body).to.eql({
|
||||
error: 'Bad Request',
|
||||
message: 'Both access and refresh tokens are expired.',
|
||||
statusCode: 400
|
||||
});
|
||||
|
||||
// The new cookie with fresh pair of access and refresh tokens should work.
|
||||
await supertest
|
||||
.get('/api/security/v1/me')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', newSessionCookie.cookieString())
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
it('expired access token should be automatically refreshed with two concurrent requests', async function () {
|
||||
this.timeout(40000);
|
||||
|
||||
// Access token expiration is set to 15s for API integration tests.
|
||||
// Let's wait for 20s to make sure token expires.
|
||||
await delay(20000);
|
||||
|
||||
// Issue two concurrent requests with the same cookie that contains expired access token.
|
||||
// First request that uses refresh token should succeed, the second should fail since refresh
|
||||
// token is one-time use only token.
|
||||
const apiResponseOnePromise = supertest
|
||||
.get('/api/security/v1/me')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(200);
|
||||
|
||||
const apiResponseTwoPromise = supertest
|
||||
.get('/api/security/v1/me')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(400);
|
||||
|
||||
const apiResponseOne = await apiResponseOnePromise;
|
||||
const cookies = apiResponseOne.headers['set-cookie'];
|
||||
expect(cookies).to.have.length(1);
|
||||
|
||||
const newSessionCookie = request.cookie(cookies[0]);
|
||||
expect(newSessionCookie.key).to.be('sid');
|
||||
expect(newSessionCookie.value).to.not.be.empty();
|
||||
expect(newSessionCookie.path).to.be('/');
|
||||
expect(newSessionCookie.httpOnly).to.be(true);
|
||||
expect(newSessionCookie.value).to.not.be(sessionCookie.value);
|
||||
|
||||
const apiResponseTwo = await apiResponseTwoPromise;
|
||||
expect(apiResponseTwo.headers['set-cookie']).to.be(undefined);
|
||||
expect(apiResponseTwo.body).to.eql({
|
||||
error: 'Bad Request',
|
||||
message: 'Both access and refresh tokens are expired.',
|
||||
statusCode: 400
|
||||
});
|
||||
|
||||
// Request with old cookie should fail with `400` since it contains expired access token and
|
||||
// already used refresh tokens.
|
||||
const apiResponseWithExpiredToken = await supertest
|
||||
.get('/api/security/v1/me')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(400);
|
||||
expect(apiResponseWithExpiredToken.body).to.eql({
|
||||
error: 'Bad Request',
|
||||
message: 'Both access and refresh tokens are expired.',
|
||||
statusCode: 400
|
||||
});
|
||||
|
||||
// The new cookie with fresh pair of access and refresh tokens should work.
|
||||
await supertest
|
||||
.get('/api/security/v1/me')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.set('Cookie', newSessionCookie.cookieString())
|
||||
.expect(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('API access with missing access token document.', () => {
|
||||
let sessionCookie;
|
||||
|
||||
beforeEach(async () => {
|
||||
const samlAuthenticationResponse = await supertest.post('/api/security/v1/saml')
|
||||
.set('kbn-xsrf', 'xxx')
|
||||
.send({ SAMLResponse: await createSAMLResponse() }, {})
|
||||
.expect(302);
|
||||
|
||||
sessionCookie = request.cookie(samlAuthenticationResponse.headers['set-cookie'][0]);
|
||||
});
|
||||
|
||||
it('should properly set cookie and start new SAML handshake', async function () {
|
||||
// Let's delete tokens from `.security` index directly to simulate the case when
|
||||
// Elasticsearch automatically removes access/refresh token document from the index
|
||||
// after some period of time.
|
||||
const esResponse = await getService('es').deleteByQuery({
|
||||
index: '.security',
|
||||
q: 'doc_type:token',
|
||||
refresh: true,
|
||||
});
|
||||
expect(esResponse).to.have.property('deleted').greaterThan(0);
|
||||
|
||||
const handshakeResponse = await supertest.get('/abc/xyz/handshake?one=two three')
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(302);
|
||||
|
||||
const cookies = handshakeResponse.headers['set-cookie'];
|
||||
expect(cookies).to.have.length(1);
|
||||
|
||||
const handshakeCookie = request.cookie(cookies[0]);
|
||||
expect(handshakeCookie.key).to.be('sid');
|
||||
expect(handshakeCookie.value).to.not.be.empty();
|
||||
expect(handshakeCookie.path).to.be('/');
|
||||
expect(handshakeCookie.httpOnly).to.be(true);
|
||||
|
||||
const redirectURL = url.parse(handshakeResponse.headers.location, true /* parseQueryString */);
|
||||
expect(redirectURL.href.startsWith(`https://elastic.co/sso/saml`)).to.be(true);
|
||||
expect(redirectURL.query.SAMLRequest).to.not.be.empty();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -41,7 +41,7 @@ export default async function ({ readConfigFile }) {
|
|||
];
|
||||
|
||||
return {
|
||||
testFiles: [require.resolve('./apis')],
|
||||
testFiles: [require.resolve('./apis/saml_only')],
|
||||
servers: xPackAPITestsConfig.get('servers'),
|
||||
services: {
|
||||
chance: kibanaAPITestsConfig.get('services.chance'),
|
||||
|
|
28
x-pack/test/saml_api_integration/with_basic.config.js
Normal file
28
x-pack/test/saml_api_integration/with_basic.config.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export default async function ({ readConfigFile }) {
|
||||
const samlAPITestsConfig = await readConfigFile(require.resolve('./config.js'));
|
||||
|
||||
return {
|
||||
testFiles: [require.resolve('./apis/with_basic')],
|
||||
servers: samlAPITestsConfig.get('servers'),
|
||||
services: samlAPITestsConfig.get('services'),
|
||||
junit: {
|
||||
reportName: 'X-Pack SAML API Integration Tests (with Basic)',
|
||||
},
|
||||
|
||||
esTestCluster: samlAPITestsConfig.get('esTestCluster'),
|
||||
|
||||
kbnTestServer: {
|
||||
...samlAPITestsConfig.get('kbnTestServer'),
|
||||
serverArgs: [
|
||||
...samlAPITestsConfig.get('kbnTestServer.serverArgs'),
|
||||
'--xpack.security.authProviders=[\"basic\",\"saml\"]',
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue