import { parse as parseCookie , Cookie } from 'tough-cookie' ; import expect from '@kbn/expect' ; import { FtrProviderContext } from '../../ftr_provider_context' ; const delay = ( ms ) => new Promise ( ( resolve ) => setTimeout ( resolve , ms ) ) ; export default function ( { getService } ) { const supertest = getService ( 'supertestWithoutAuth' ) ; function extractSessionCookie ( response ) { const cookie = ( response . headers [ 'set-cookie' ] || [ ] ) . find ( ( header ) => header . startsWith ( 'sid=' ) ) ; return cookie ? parseCookie ( cookie ) : undefined ; } async function createSessionCookie ( ) { const response = await supertest . post ( '/internal/security/login' ) . set ( 'kbn-xsrf' , 'true' ) . send ( { providerType : 'token' , providerName : 'token' , currentURL : '/' , params : { username : 'elastic' , password : 'changeme' } , } ) ; const cookie = extractSessionCookie ( response ) ; if ( ! cookie ) { throw new Error ( 'No session cookie set after login' ) ; } return cookie ; } describe ( 'session' , ( ) => { it ( 'accepts valid session cookie' , async ( ) => { const cookie = await createSessionCookie ( ) ; await supertest . get ( '/internal/security/me' ) . set ( 'kbn-xsrf' , 'true' ) . set ( 'cookie' , cookie . cookieString ( ) ) . expect ( 200 ) ; } ) ; it ( 'accepts multiple requests for a single valid session cookie' , async ( ) => { const cookie = await createSessionCookie ( ) ; await supertest . get ( '/internal/security/me' ) . set ( 'kbn-xsrf' , 'true' ) . set ( 'cookie' , cookie . cookieString ( ) ) . expect ( 200 ) ; await supertest . get ( '/internal/security/me' ) . set ( 'kbn-xsrf' , 'true' ) . set ( 'cookie' , cookie . cookieString ( ) ) . expect ( 200 ) ; } ) ; describe ( 'API access with expired access token.' , function ( ) { const expectNewSessionCookie = ( originalCookie , newCookie ) => { if ( ! newCookie ) { throw new Error ( 'No session cookie set after token refresh' ) ; } if ( ! newCookie . httpOnly ) { throw new Error ( 'Session cookie is not marked as HttpOnly' ) ; } if ( newCookie . value === originalCookie . value ) { throw new Error ( 'Session cookie has not changed after refresh' ) ; } } ; it ( 'expired access token should be automatically refreshed' , async function ( ) { this . timeout ( 40000 ) ; const originalCookie = await createSessionCookie ( ) ; await delay ( 20000 ) ; const firstResponse = await supertest . get ( '/internal/security/me' ) . set ( 'kbn-xsrf' , 'true' ) . set ( 'cookie' , originalCookie . cookieString ( ) ) . expect ( 200 ) ; const firstNewCookie = extractSessionCookie ( firstResponse ) ! ; expectNewSessionCookie ( originalCookie , firstNewCookie ) ; const secondResponse = await supertest . get ( '/internal/security/me' ) . set ( 'kbn-xsrf' , 'true' ) . set ( 'Cookie' , originalCookie . cookieString ( ) ) . expect ( 200 ) ; const secondNewCookie = extractSessionCookie ( secondResponse ) ! ; expectNewSessionCookie ( originalCookie , secondNewCookie ) ; if ( secondNewCookie . value === firstNewCookie . value ) { throw new Error ( 'Second new cookie is the same as the first new cookie' ) ; } await supertest . get ( '/internal/security/me' ) . set ( 'kbn-xsrf' , 'true' ) . set ( 'Cookie' , firstNewCookie . cookieString ( ) ) . expect ( 200 ) ; await supertest . get ( '/internal/security/me' ) . set ( 'kbn-xsrf' , 'true' ) . set ( 'Cookie' , secondNewCookie . cookieString ( ) ) . expect ( 200 ) ; } ) ; } ) ; describe ( 'API access with missing access token document.' , ( ) => { let sessionCookie ; beforeEach ( async ( ) => ( sessionCookie = await createSessionCookie ( ) ) ) ; it ( 'should clear cookie and redirect to login' , async function ( ) { const esResponse = await getService ( 'es' ) . deleteByQuery ( { index : '.security-tokens' , body : { query : { match : { doc_type : 'token' } } } , refresh : true , } ) ; expect ( esResponse ) . to . have . property ( 'deleted' ) . greaterThan ( 0 ) ; const response = await supertest . get ( '/abc/xyz/' ) . set ( 'Cookie' , sessionCookie . cookieString ( ) ) . expect ( 'location' , '/login?next=%2Fabc%2Fxyz%2F' ) . expect ( 302 ) ; const cookies = response . headers [ 'set-cookie' ] ; expect ( cookies ) . to . have . length ( 1 ) ; const cookie = parseCookie ( cookies [ 0 ] ) ! ; expect ( cookie . key ) . to . be ( 'sid' ) ; expect ( cookie . value ) . to . be . empty ( ) ; expect ( cookie . path ) . to . be ( '/' ) ; expect ( cookie . httpOnly ) . to . be ( true ) ; } ) ; } ) ; } ) ; }