Skip to content

Commit

Permalink
Merge branch 'main' of github.com:redwoodjs/redwood into chore/move-m…
Browse files Browse the repository at this point in the history
…iddleware

* 'main' of github.com:redwoodjs/redwood:
  fix(docs): Fix introduction link (redwoodjs#10938)
  fix(cli-helpers): Fix CJS support (redwoodjs#10936)
  chore(cli-helpers): Formatting
  chore(cli-helpers): loadEnvFiles cleanup (redwoodjs#10935)
  feat(cli-helpers): Add loadEnvFiles (redwoodjs#10931)
  chore(cli-helpers): Fix dual package build. Align with new pattern (redwoodjs#10933)
  fix(dbAuth): Don't throw errors under normal auth flow conditions (redwoodjs#10927)
  chore(dbAuth): Fix typo in comment, and refactor dbAuthSession (redwoodjs#10928)
  • Loading branch information
GitHub Actions committed Jul 12, 2024
2 parents 59b5ade + 4cfdb84 commit 974629f
Show file tree
Hide file tree
Showing 15 changed files with 378 additions and 58 deletions.
2 changes: 1 addition & 1 deletion docs/docs/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ That said, there are some references you should consider reading at some point i
Especially if you want to become an advanced user.
For example, [Services](services.md) are fundamental to Redwood.
It's worth getting to know them inside and out.
And if you're not writing [tests](testing.md) and [stories](storybook.md), you're not using Redwood to its full potential.
And if you're not writing [tests](testing.md) and [stories](storybook/about.md), you're not using Redwood to its full potential.

> **We realize that the content doesn't always match the organization**
>
Expand Down
3 changes: 2 additions & 1 deletion packages/api-server/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
{ "path": "../internal" },
{ "path": "../project-config" },
{ "path": "../adapters/fastify/web" },
{ "path": "../web-server" }
{ "path": "../web-server" },
{ "path": "../realtime" }
],
"exclude": [
"dist",
Expand Down
16 changes: 8 additions & 8 deletions packages/auth-providers/dbAuth/api/src/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export const decryptSession = (text: string | null) => {

let decoded
// if cookie contains a pipe then it was encrypted using the `node:crypto`
// algorithm (first element is the ecrypted data, second is the initialization vector)
// algorithm (first element is the encrypted data, second is the initialization vector)
// otherwise fall back to using the older CryptoJS algorithm
const [encryptedText, iv] = text.split('|')

Expand Down Expand Up @@ -186,15 +186,15 @@ export const dbAuthSession = (
) => {
const sessionCookie = extractCookie(event)

if (sessionCookie) {
// i.e. Browser making a request
const [session, _csrfToken] = decryptSession(
getSession(sessionCookie, cookieNameOption),
)
return session
} else {
if (!sessionCookie) {
return null
}

// This is a browser making a request
const [session, _csrfToken] = decryptSession(
getSession(sessionCookie, cookieNameOption),
)
return session
}

export const webAuthnSession = (event: APIGatewayProxyEvent | Request) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ describe('dbAuthMiddleware', () => {
expect(res).toEqual({ passthrough: true })
})

it('When it has a cookie header, decrypts and sets server auth context', async () => {
const cookieHeader = 'session=this_is_the_only_correct_session'
it('decrypts and sets server auth context when it has a cookie header with session and auth-provider cookies', async () => {
const cookieHeader =
'session=this_is_the_only_correct_session;auth-provider=dbAuth'

const options: DbAuthMiddlewareOptions = {
getCurrentUser: vi.fn(async () => {
Expand All @@ -91,7 +92,7 @@ describe('dbAuthMiddleware', () => {
const res = await middleware(mwReq, MiddlewareResponse.next())

expect(mwReq.serverAuthState.get()).toEqual({
cookieHeader: 'session=this_is_the_only_correct_session',
cookieHeader,
currentUser: {
email: 'user-1@example.com',
id: 'mocked-current-user-1',
Expand Down Expand Up @@ -120,7 +121,8 @@ describe('dbAuthMiddleware', () => {
})

it('Will use the cookie name option correctly', async () => {
const cookieHeader = 'bazinga_8911=this_is_the_only_correct_session'
const cookieHeader =
'bazinga_8911=this_is_the_only_correct_session;auth-provider=dbAuth'

const options: DbAuthMiddlewareOptions = {
getCurrentUser: vi.fn(async () => {
Expand All @@ -143,7 +145,7 @@ describe('dbAuthMiddleware', () => {
const res = await middleware(mwReq, MiddlewareResponse.next())

expect(mwReq.serverAuthState.get()).toEqual({
cookieHeader: 'bazinga_8911=this_is_the_only_correct_session',
cookieHeader,
currentUser: {
email: 'user-1@example.com',
id: 'mocked-current-user-1',
Expand Down Expand Up @@ -382,6 +384,7 @@ describe('dbAuthMiddleware', () => {
const res = await middleware(req, MiddlewareResponse.next())
expect(res?.body).toEqual(resetToken)
})

it('handles a getToken request', async () => {
const cookieHeader =
'session=ko6iXKV11DSjb6kFJ4iwcf1FEqa5wPpbL1sdtKiV51Y=|cQaYkOPG/r3ILxWiFiz90w=='
Expand Down Expand Up @@ -504,7 +507,7 @@ describe('dbAuthMiddleware', () => {
// })
})

describe('handle exception cases', async () => {
describe('exception case handling', async () => {
const unauthenticatedServerAuthState = {
...middlewareDefaultAuthProviderState,
cookieHeader: null,
Expand Down Expand Up @@ -602,6 +605,182 @@ describe('dbAuthMiddleware', () => {
])
})

it('handles a GET request with some cookies, but no auth related cookies', async () => {
const request = new Request(
'http://localhost:8911/functions/bad-cookie',
{
method: 'GET',
headers: {
Cookie: 'not-auth=some-value;other-cookie=foobar',
},
},
)

const mwReq = new MWRequest(request)

const options: DbAuthMiddlewareOptions = {
cookieName: 'session_8911',
getCurrentUser: async () => {
return {}
},
dbAuthHandler: async () => {
return {
body: JSON.stringify({}),
headers: {},
statusCode: 200,
}
},
}
const [middleware] = initDbAuthMiddleware(options)

const res = await middleware(mwReq, MiddlewareResponse.next())
expect(res).toBeDefined()

const serverAuthState = mwReq.serverAuthState.get()
expect(serverAuthState).toEqual({
...unauthenticatedServerAuthState,
cookieHeader: 'not-auth=some-value;other-cookie=foobar',
})

expect(res?.toResponse().headers.getSetCookie()).toEqual([
// Not setting any cookies to expire
])
})

it('handles a GET request with auth-provider cookie, but no session cookie', async () => {
const request = new Request(
'http://localhost:8911/functions/bad-cookie',
{
method: 'GET',
headers: {
Cookie: 'not-auth=some-value;auth-provider=dbAuth',
},
},
)

const mwReq = new MWRequest(request)

const options: DbAuthMiddlewareOptions = {
cookieName: 'session_8911',
getCurrentUser: async () => {
return {}
},
dbAuthHandler: async () => {
return {
body: JSON.stringify({}),
headers: {},
statusCode: 200,
}
},
}
const [middleware] = initDbAuthMiddleware(options)

const res = await middleware(mwReq, MiddlewareResponse.next())
expect(res).toBeDefined()

const serverAuthState = mwReq.serverAuthState.get()
expect(serverAuthState).toEqual({
...unauthenticatedServerAuthState,
cookieHeader: 'not-auth=some-value;auth-provider=dbAuth',
})

expect(res?.toResponse().headers.getSetCookie()).toEqual([
// Expired cookies, will be removed by browser
'session_8911=; Expires=Thu, 01 Jan 1970 00:00:00 GMT',
'auth-provider=; Expires=Thu, 01 Jan 1970 00:00:00 GMT',
])
})

it('handles a GET request with valid session cookie, but no auth-provider cookie', async () => {
const request = new Request(
'http://localhost:8911/functions/bad-cookie',
{
method: 'GET',
headers: {
Cookie: 'session_8911=this_is_the_only_correct_session',
},
},
)

const mwReq = new MWRequest(request)

const options: DbAuthMiddlewareOptions = {
cookieName: 'session_8911',
getCurrentUser: async () => {
return {}
},
dbAuthHandler: async () => {
return {
body: JSON.stringify({}),
headers: {},
statusCode: 200,
}
},
}
const [middleware] = initDbAuthMiddleware(options)

const res = await middleware(mwReq, MiddlewareResponse.next())
expect(res).toBeDefined()

const serverAuthState = mwReq.serverAuthState.get()
expect(serverAuthState).toEqual({
...unauthenticatedServerAuthState,
cookieHeader: 'session_8911=this_is_the_only_correct_session',
})

// Because we don't have the dbAuth auth-provider cookie set the code
// should not expire the session cookie, because it could belong to
// someone else (i.e. not dbAuth)
expect(res?.toResponse().headers.getSetCookie()).toEqual([
// Don't set any cookies to expire
])
})

it('handles a GET request with invalid session cookie and no auth-provider cookie', async () => {
const request = new Request(
'http://localhost:8911/functions/bad-cookie',
{
method: 'GET',
headers: {
Cookie: 'session_8911=invalid',
},
},
)

const mwReq = new MWRequest(request)

const options: DbAuthMiddlewareOptions = {
cookieName: 'session_8911',
getCurrentUser: async () => {
return {}
},
dbAuthHandler: async () => {
return {
body: JSON.stringify({}),
headers: {},
statusCode: 200,
}
},
}
const [middleware] = initDbAuthMiddleware(options)

const res = await middleware(mwReq, MiddlewareResponse.next())
expect(res).toBeDefined()

const serverAuthState = mwReq.serverAuthState.get()
expect(serverAuthState).toEqual({
...unauthenticatedServerAuthState,
cookieHeader: 'session_8911=invalid',
})

// Because we don't have the dbAuth auth-provider cookie set the code
// should not expire the session cookie, because it could belong to
// someone else (i.e. not dbAuth)
expect(res?.toResponse().headers.getSetCookie()).toEqual([
// Don't set any cookies to expire
])
})

it('handles a GET request with no cookies', async () => {
const request = new Request('http://localhost:8911/functions/no-cookie', {
method: 'GET',
Expand Down
Loading

0 comments on commit 974629f

Please sign in to comment.