From 45dd0e821ec123a480f0fcb2bd7cc4eccff513d1 Mon Sep 17 00:00:00 2001 From: Matt Schile Date: Wed, 27 Jul 2022 15:50:23 -0600 Subject: [PATCH] Remove isAUTFrame qualification from cross origin cookie check --- .../e2e/e2e/origin/commands/cookies.cy.ts | 284 ++++++++++-------- packages/driver/cypress/plugins/server.js | 8 + .../proxy/lib/http/response-middleware.ts | 10 +- .../unit/http/response-middleware.spec.ts | 1 - 4 files changed, 166 insertions(+), 137 deletions(-) diff --git a/packages/driver/cypress/e2e/e2e/origin/commands/cookies.cy.ts b/packages/driver/cypress/e2e/e2e/origin/commands/cookies.cy.ts index 7c69da0c2908..70ed2c7b162f 100644 --- a/packages/driver/cypress/e2e/e2e/origin/commands/cookies.cy.ts +++ b/packages/driver/cypress/e2e/e2e/origin/commands/cookies.cy.ts @@ -1,176 +1,200 @@ import { findCrossOriginLogs } from '../../../../support/utils' -context('cy.origin cookies', () => { - beforeEach(() => { - cy.visit('/fixtures/primary-origin.html') - cy.get('a[data-cy="cross-origin-secondary-link"]').click() - }) +describe('cy.origin cookies', () => { + context('client side', () => { + beforeEach(() => { + cy.visit('/fixtures/primary-origin.html') + cy.get('a[data-cy="cross-origin-secondary-link"]').click() + }) - it('.getCookie(), .getCookies(), and .setCookie()', () => { - cy.origin('http://foobar.com:3500', () => { - cy.getCookies().should('be.empty') + it('.getCookie(), .getCookies(), and .setCookie()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.getCookies().should('be.empty') - cy.setCookie('foo', 'bar') + cy.setCookie('foo', 'bar') - cy.getCookie('foo').should('have.property', 'value', 'bar') - cy.getCookies().should('have.length', 1) + cy.getCookie('foo').should('have.property', 'value', 'bar') + cy.getCookies().should('have.length', 1) + }) }) - }) - it('.clearCookie()', () => { - cy.origin('http://foobar.com:3500', () => { - cy.setCookie('foo', 'bar') - cy.getCookie('foo').should('not.be.null') - cy.clearCookie('foo') - cy.getCookie('foo').should('be.null') + it('.clearCookie()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.setCookie('foo', 'bar') + cy.getCookie('foo').should('not.be.null') + cy.clearCookie('foo') + cy.getCookie('foo').should('be.null') + }) }) - }) - it('.clearCookies()', () => { - cy.origin('http://foobar.com:3500', () => { - cy.setCookie('foo', 'bar') - cy.setCookie('faz', 'baz') + it('.clearCookies()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.setCookie('foo', 'bar') + cy.setCookie('faz', 'baz') - cy.getCookies().should('have.length', 2) - cy.clearCookies() - cy.getCookies().should('be.empty') + cy.getCookies().should('have.length', 2) + cy.clearCookies() + cy.getCookies().should('be.empty') + }) }) - }) - context('#consoleProps', () => { - const { _ } = Cypress - let logs: Map + context('#consoleProps', () => { + const { _ } = Cypress + let logs: Map - beforeEach(() => { - logs = new Map() + beforeEach(() => { + logs = new Map() - cy.on('log:changed', (attrs, log) => { - logs.set(attrs.id, log) + cy.on('log:changed', (attrs, log) => { + logs.set(attrs.id, log) + }) }) - }) - it('.getCookie()', () => { - cy.origin('http://foobar.com:3500', () => { - cy.getCookies().should('be.empty') - cy.setCookie('foo', 'bar') - cy.getCookie('foo') - }) + it('.getCookie()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.getCookies().should('be.empty') + cy.setCookie('foo', 'bar') + cy.getCookie('foo') + }) - cy.shouldWithTimeout(() => { - const { consoleProps } = findCrossOriginLogs('getCookie', logs, 'foobar.com') - - expect(consoleProps.Command).to.equal('getCookie') - expect(consoleProps.Yielded).to.have.property('domain').that.includes('foobar.com') - expect(consoleProps.Yielded).to.have.property('expiry').that.is.a('number') - expect(consoleProps.Yielded).to.have.property('httpOnly').that.equals(false) - expect(consoleProps.Yielded).to.have.property('secure').that.equals(false) - expect(consoleProps.Yielded).to.have.property('name').that.equals('foo') - expect(consoleProps.Yielded).to.have.property('value').that.equals('bar') - expect(consoleProps.Yielded).to.have.property('path').that.is.a('string') + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('getCookie', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('getCookie') + expect(consoleProps.Yielded).to.have.property('domain').that.includes('foobar.com') + expect(consoleProps.Yielded).to.have.property('expiry').that.is.a('number') + expect(consoleProps.Yielded).to.have.property('httpOnly').that.equals(false) + expect(consoleProps.Yielded).to.have.property('secure').that.equals(false) + expect(consoleProps.Yielded).to.have.property('name').that.equals('foo') + expect(consoleProps.Yielded).to.have.property('value').that.equals('bar') + expect(consoleProps.Yielded).to.have.property('path').that.is.a('string') + }) }) - }) - it('.getCookies()', () => { - cy.origin('http://foobar.com:3500', () => { - cy.getCookies().should('be.empty') + it('.getCookies()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.getCookies().should('be.empty') - cy.setCookie('foo', 'bar') - cy.getCookies() - }) + cy.setCookie('foo', 'bar') + cy.getCookies() + }) - cy.shouldWithTimeout(() => { + cy.shouldWithTimeout(() => { // get the last 'getCookies' command, which is the one we care about for this test - const allGetCookieLogs = findCrossOriginLogs('getCookies', logs, 'foobar.com') + const allGetCookieLogs = findCrossOriginLogs('getCookies', logs, 'foobar.com') - const { consoleProps } = allGetCookieLogs.pop() as any + const { consoleProps } = allGetCookieLogs.pop() as any - expect(consoleProps.Command).to.equal('getCookies') - expect(consoleProps['Num Cookies']).to.equal(1) + expect(consoleProps.Command).to.equal('getCookies') + expect(consoleProps['Num Cookies']).to.equal(1) - // can't exactly assert on length() as this is a array proxy object - expect(consoleProps.Yielded.length).to.equal(1) - expect(consoleProps.Yielded[0]).to.have.property('expiry').that.is.a('number') - expect(consoleProps.Yielded[0]).to.have.property('httpOnly').that.equals(false) - expect(consoleProps.Yielded[0]).to.have.property('secure').that.equals(false) - expect(consoleProps.Yielded[0]).to.have.property('name').that.equals('foo') - expect(consoleProps.Yielded[0]).to.have.property('value').that.equals('bar') - expect(consoleProps.Yielded[0]).to.have.property('path').that.is.a('string') + // can't exactly assert on length() as this is a array proxy object + expect(consoleProps.Yielded.length).to.equal(1) + expect(consoleProps.Yielded[0]).to.have.property('expiry').that.is.a('number') + expect(consoleProps.Yielded[0]).to.have.property('httpOnly').that.equals(false) + expect(consoleProps.Yielded[0]).to.have.property('secure').that.equals(false) + expect(consoleProps.Yielded[0]).to.have.property('name').that.equals('foo') + expect(consoleProps.Yielded[0]).to.have.property('value').that.equals('bar') + expect(consoleProps.Yielded[0]).to.have.property('path').that.is.a('string') + }) }) - }) - it('.setCookie()', () => { - cy.origin('http://foobar.com:3500', () => { - cy.getCookies().should('be.empty') + it('.setCookie()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.getCookies().should('be.empty') - cy.setCookie('foo', 'bar') - }) + cy.setCookie('foo', 'bar') + }) - cy.shouldWithTimeout(() => { - const { consoleProps } = findCrossOriginLogs('setCookie', logs, 'foobar.com') - - expect(consoleProps.Command).to.equal('setCookie') - expect(consoleProps.Yielded).to.have.property('domain').that.includes('foobar.com') - expect(consoleProps.Yielded).to.have.property('expiry').that.is.a('number') - expect(consoleProps.Yielded).to.have.property('httpOnly').that.equals(false) - expect(consoleProps.Yielded).to.have.property('secure').that.equals(false) - expect(consoleProps.Yielded).to.have.property('name').that.equals('foo') - expect(consoleProps.Yielded).to.have.property('value').that.equals('bar') - expect(consoleProps.Yielded).to.have.property('path').that.is.a('string') + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('setCookie', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('setCookie') + expect(consoleProps.Yielded).to.have.property('domain').that.includes('foobar.com') + expect(consoleProps.Yielded).to.have.property('expiry').that.is.a('number') + expect(consoleProps.Yielded).to.have.property('httpOnly').that.equals(false) + expect(consoleProps.Yielded).to.have.property('secure').that.equals(false) + expect(consoleProps.Yielded).to.have.property('name').that.equals('foo') + expect(consoleProps.Yielded).to.have.property('value').that.equals('bar') + expect(consoleProps.Yielded).to.have.property('path').that.is.a('string') + }) }) - }) - it('.clearCookie()', () => { - cy.origin('http://foobar.com:3500', () => { - cy.setCookie('foo', 'bar') - cy.getCookie('foo').should('not.be.null') - cy.clearCookie('foo') - }) + it('.clearCookie()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.setCookie('foo', 'bar') + cy.getCookie('foo').should('not.be.null') + cy.clearCookie('foo') + }) - cy.shouldWithTimeout(() => { - const { consoleProps } = findCrossOriginLogs('clearCookie', logs, 'foobar.com') - - expect(consoleProps.Command).to.equal('clearCookie') - expect(consoleProps.Yielded).to.equal('null') - expect(consoleProps['Cleared Cookie']).to.have.property('domain').that.includes('foobar.com') - expect(consoleProps['Cleared Cookie']).to.have.property('expiry').that.is.a('number') - expect(consoleProps['Cleared Cookie']).to.have.property('httpOnly').that.equals(false) - expect(consoleProps['Cleared Cookie']).to.have.property('secure').that.equals(false) - expect(consoleProps['Cleared Cookie']).to.have.property('name').that.equals('foo') - expect(consoleProps['Cleared Cookie']).to.have.property('value').that.equals('bar') - expect(consoleProps['Cleared Cookie']).to.have.property('path').that.is.a('string') + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('clearCookie', logs, 'foobar.com') + + expect(consoleProps.Command).to.equal('clearCookie') + expect(consoleProps.Yielded).to.equal('null') + expect(consoleProps['Cleared Cookie']).to.have.property('domain').that.includes('foobar.com') + expect(consoleProps['Cleared Cookie']).to.have.property('expiry').that.is.a('number') + expect(consoleProps['Cleared Cookie']).to.have.property('httpOnly').that.equals(false) + expect(consoleProps['Cleared Cookie']).to.have.property('secure').that.equals(false) + expect(consoleProps['Cleared Cookie']).to.have.property('name').that.equals('foo') + expect(consoleProps['Cleared Cookie']).to.have.property('value').that.equals('bar') + expect(consoleProps['Cleared Cookie']).to.have.property('path').that.is.a('string') + }) }) - }) - it('.clearCookies()', () => { - cy.origin('http://foobar.com:3500', () => { - cy.setCookie('foo', 'bar') - cy.setCookie('faz', 'baz') + it('.clearCookies()', () => { + cy.origin('http://foobar.com:3500', () => { + cy.setCookie('foo', 'bar') + cy.setCookie('faz', 'baz') - cy.getCookies().should('have.length', 2) - cy.clearCookies() - }) + cy.getCookies().should('have.length', 2) + cy.clearCookies() + }) + + cy.shouldWithTimeout(() => { + const { consoleProps } = findCrossOriginLogs('clearCookies', logs, 'foobar.com') - cy.shouldWithTimeout(() => { - const { consoleProps } = findCrossOriginLogs('clearCookies', logs, 'foobar.com') + expect(consoleProps.Command).to.equal('clearCookies') + expect(consoleProps['Num Cookies']).to.equal(2) - expect(consoleProps.Command).to.equal('clearCookies') - expect(consoleProps['Num Cookies']).to.equal(2) + expect(consoleProps.Yielded).to.equal('null') - expect(consoleProps.Yielded).to.equal('null') + expect(consoleProps['Cleared Cookies'].length).to.equal(2) - expect(consoleProps['Cleared Cookies'].length).to.equal(2) + expect(consoleProps['Cleared Cookies'][0]).to.have.property('name').that.equals('foo') + expect(consoleProps['Cleared Cookies'][0]).to.have.property('value').that.equals('bar') - expect(consoleProps['Cleared Cookies'][0]).to.have.property('name').that.equals('foo') - expect(consoleProps['Cleared Cookies'][0]).to.have.property('value').that.equals('bar') + expect(consoleProps['Cleared Cookies'][1]).to.have.property('name').that.equals('faz') + expect(consoleProps['Cleared Cookies'][1]).to.have.property('value').that.equals('baz') - expect(consoleProps['Cleared Cookies'][1]).to.have.property('name').that.equals('faz') - expect(consoleProps['Cleared Cookies'][1]).to.have.property('value').that.equals('baz') + _.forEach(consoleProps['Cleared Cookies'], (clearedCookie) => { + expect(clearedCookie).to.have.property('httpOnly').that.equals(false) + expect(clearedCookie).to.have.property('secure').that.equals(false) + expect(clearedCookie).to.have.property('path').that.is.a('string') + }) + }) + }) + }) + }) + + context('server side', () => { + it('supports Set-Cookie response header through fetch request', () => { + cy.intercept('/dump-headers').as('headers') - _.forEach(consoleProps['Cleared Cookies'], (clearedCookie) => { - expect(clearedCookie).to.have.property('httpOnly').that.equals(false) - expect(clearedCookie).to.have.property('secure').that.equals(false) - expect(clearedCookie).to.have.property('path').that.is.a('string') + cy.origin('http://www.foobar.com:3500', () => { + cy.visit('/') + cy.window().then((win) => { + return cy.wrap(win.fetch('/set-cookie?cookie=foo=bar;')) }) + + cy.window().then((win) => { + win.location.href = 'http://www.foobar.com:3500/dump-headers' + }) + + cy.wait('@headers') + + cy.contains('"cookie":"foo=bar"') + cy.getCookie('foo').its('value').should('equal', 'bar') }) }) }) diff --git a/packages/driver/cypress/plugins/server.js b/packages/driver/cypress/plugins/server.js index 31314d67bd1f..999e8c3dba30 100644 --- a/packages/driver/cypress/plugins/server.js +++ b/packages/driver/cypress/plugins/server.js @@ -283,6 +283,14 @@ const createApp = (port) => { res.send(`

Welcome, ${user}!

`) }) + app.get('/set-cookie', (req, res) => { + const { cookie } = req.query + + res + .append('Set-Cookie', cookie) + .sendStatus(200) + }) + let _var = '' app.get('/set-var', (req, res) => { diff --git a/packages/proxy/lib/http/response-middleware.ts b/packages/proxy/lib/http/response-middleware.ts index 575b43eb5dc2..d0b1dcbd334a 100644 --- a/packages/proxy/lib/http/response-middleware.ts +++ b/packages/proxy/lib/http/response-middleware.ts @@ -400,14 +400,12 @@ const MaybePreventCaching: ResponseMiddleware = function () { const checkIfNeedsCrossOriginHandling = (ctx: HttpMiddlewareThis) => { const currentAUTUrl = ctx.getAUTUrl() - // A cookie needs cross origin handling if it's an AUT request and - // either the request itself is cross-origin or the origins between - // requests don't match, since the browser won't set them in that - // case and if it's secondary-origin -> primary-origin, we don't - // recognize the request as cross-origin + // A cookie needs cross origin handling if the request itself is + // cross-origin or the origins between requests don't match, + // since the browser won't set them in that case and if it's + // secondary-origin -> primary-origin, we don't recognize the request as cross-origin return ( ctx.config.experimentalSessionAndOrigin - && ctx.req.isAUTFrame && ( (currentAUTUrl && !cors.urlOriginsMatch(currentAUTUrl, ctx.req.proxiedUrl)) || !ctx.remoteStates.isPrimaryOrigin(ctx.req.proxiedUrl) diff --git a/packages/proxy/test/unit/http/response-middleware.spec.ts b/packages/proxy/test/unit/http/response-middleware.spec.ts index 22f720d83555..e3298970bfc7 100644 --- a/packages/proxy/test/unit/http/response-middleware.spec.ts +++ b/packages/proxy/test/unit/http/response-middleware.spec.ts @@ -932,7 +932,6 @@ describe('http/response-middleware', function () { req: { proxiedUrl: 'http://www.foobar.com/login', headers: {}, - isAUTFrame: true, ...props.req, }, incomingResStream: {