Skip to content
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

fix: Remove isAUTFrame qualification from cross origin cookie check #22963

Merged
merged 10 commits into from Jul 29, 2022
284 changes: 154 additions & 130 deletions 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<string, any>
context('#consoleProps', () => {
const { _ } = Cypress
let logs: Map<string, any>

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')
})
})
})
Expand Down
8 changes: 8 additions & 0 deletions packages/driver/cypress/plugins/server.js
Expand Up @@ -283,6 +283,14 @@ const createApp = (port) => {
res.send(`<html><body><h1>Welcome, ${user}!</h1></body></html>`)
})

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) => {
Expand Down
10 changes: 4 additions & 6 deletions packages/proxy/lib/http/response-middleware.ts
Expand Up @@ -400,14 +400,12 @@ const MaybePreventCaching: ResponseMiddleware = function () {
const checkIfNeedsCrossOriginHandling = (ctx: HttpMiddlewareThis<ResponseMiddlewareProps>) => {
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)
Expand Down
1 change: 0 additions & 1 deletion packages/proxy/test/unit/http/response-middleware.spec.ts
Expand Up @@ -932,7 +932,6 @@ describe('http/response-middleware', function () {
req: {
proxiedUrl: 'http://www.foobar.com/login',
headers: {},
isAUTFrame: true,
...props.req,
},
incomingResStream: {
Expand Down