-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: Add tests for authentication strategies (#64)
Co-authored-by: Lukas Jost <[email protected]>
- Loading branch information
Showing
2 changed files
with
179 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { makeLocalStrategy } from '../../src/auth/local-strategy.js' | ||
import assert from 'node:assert' | ||
|
||
describe('auth/local-strategy.ts', () => { | ||
describe('makeLocalStrategy()', () => { | ||
it('has name "local"', async () => { | ||
const strategy = await makeLocalStrategy({ username: 'admin', password: 'password' }) | ||
assert.strictEqual(strategy.name, 'local') | ||
}) | ||
|
||
it('denies access if the admin user has no password', async () => { | ||
const mockRequest = { | ||
body: { | ||
username: 'admin', | ||
password: '' | ||
} | ||
} | ||
const strategy = await makeLocalStrategy({ username: 'admin', password: '' }) | ||
const promise = new Promise<void>((resolve, reject) => { | ||
strategy.fail = () => resolve() | ||
strategy.success = () => reject(new Error('should not have succeeded')) | ||
}) | ||
strategy.authenticate(mockRequest as any) | ||
await promise | ||
}) | ||
|
||
it('denies access if the username is incorrect', async () => { | ||
const mockRequest = { | ||
body: { | ||
username: 'aaaaa', | ||
password: 'password' | ||
} | ||
} | ||
const strategy = await makeLocalStrategy({ username: 'admin', password: 'password' }) | ||
const promise = new Promise<void>((resolve, reject) => { | ||
strategy.fail = () => resolve() | ||
strategy.success = () => reject(new Error('should not have succeeded')) | ||
}) | ||
strategy.authenticate(mockRequest as any) | ||
await promise | ||
}) | ||
|
||
it('denies access if the password is incorrect', async () => { | ||
const mockRequest = { | ||
body: { | ||
username: 'admin', | ||
password: 'wrongpassword' | ||
} | ||
} | ||
const strategy = await makeLocalStrategy({ username: 'admin', password: 'password' }) | ||
const promise = new Promise<void>((resolve, reject) => { | ||
strategy.fail = () => resolve() | ||
strategy.success = () => reject(new Error('should not have succeeded')) | ||
}) | ||
strategy.authenticate(mockRequest as any) | ||
await promise | ||
}) | ||
|
||
it('allows access if the username and password are correct', async () => { | ||
const mockRequest = { | ||
body: { | ||
username: 'admin', | ||
password: 'password' | ||
} | ||
} | ||
const strategy = await makeLocalStrategy({ username: 'admin', password: 'password' }) | ||
const promise = new Promise<void>((resolve, reject) => { | ||
strategy.fail = () => reject(new Error('should not have failed')) | ||
strategy.success = (user, info) => { | ||
assert.deepStrictEqual(user, { | ||
strategy: 'local', | ||
username: 'admin', | ||
createdAt: user.createdAt | ||
}) | ||
assert.ok(Math.abs(user.createdAt - Date.now()) < 1000) | ||
assert.strictEqual(info, undefined) | ||
resolve() | ||
} | ||
}) | ||
strategy.authenticate(mockRequest as any) | ||
await promise | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { fastify, FastifyInstance } from 'fastify' | ||
import { makeOidcStrategy } from '../../src/auth/oidc-strategy.js' | ||
import assert from 'node:assert' | ||
import { Strategy } from 'openid-client' | ||
|
||
describe('auth/oidc-strategy.ts', () => { | ||
describe('makeOidcStrategy()', () => { | ||
let app: FastifyInstance | undefined | ||
|
||
afterEach(async () => { | ||
await app?.close() | ||
app = undefined | ||
}) | ||
|
||
it('performs issuer discovery', async () => { | ||
app = fastify() | ||
let called = false | ||
app.get('/.well-known/openid-configuration', async (req, reply) => { | ||
called = true | ||
return { issuer: 'http://127.0.0.1:58080' } | ||
}) | ||
await app.listen({ host: '127.0.0.1', port: 58080 }) | ||
const strategy = await makeOidcStrategy({ | ||
issuer: 'http://127.0.0.1:58080', | ||
clientId: 'foobar', | ||
clientSecret: 'bazqux', | ||
redirectUri: 'http://localhost:3000/oidc/callback' | ||
}) | ||
assert.ok(strategy instanceof Strategy) | ||
assert.ok(called) | ||
}) | ||
|
||
it('accepts issuer URL with full .well-known path', async () => { | ||
app = fastify() | ||
let called = false | ||
app.get('/.well-known/openid-configuration', async (req, reply) => { | ||
called = true | ||
return { issuer: 'http://127.0.0.1:58080' } | ||
}) | ||
await app.listen({ host: '127.0.0.1', port: 58080 }) | ||
const strategy = await makeOidcStrategy({ | ||
issuer: 'http://127.0.0.1:58080/.well-known/openid-configuration', | ||
clientId: 'foobar', | ||
clientSecret: 'bazqux', | ||
redirectUri: 'http://localhost:3000/oidc/callback' | ||
}) | ||
assert.ok(strategy instanceof Strategy) | ||
assert.ok(called) | ||
}) | ||
|
||
it('redirects unauthenticated users to the OIDC provider', async () => { | ||
app = fastify() | ||
app.get('/.well-known/openid-configuration', async (req, reply) => { | ||
return { | ||
// https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata | ||
issuer: 'http://127.0.0.1:58080', | ||
authorization_endpoint: 'http://127.0.0.1:58080/authorize', | ||
token_endpoint: 'http://127.0.0.1:58080/token', | ||
jwks_uri: 'http://127.0.0.1:58080/jwks', | ||
response_types_supported: ['code'] | ||
} | ||
}) | ||
await app.listen({ host: '127.0.0.1', port: 58080 }) | ||
const strategy = await makeOidcStrategy({ | ||
issuer: 'http://127.0.0.1:58080', | ||
clientId: 'foobar', | ||
clientSecret: 'bazqux', | ||
redirectUri: 'http://localhost:3000/oidc/callback' | ||
}) | ||
const mockRequest = { | ||
method: 'GET', | ||
url: '/', | ||
body: {}, | ||
session: {} | ||
} | ||
const promise = new Promise<void>((resolve, reject) => { | ||
strategy.error = (err: any) => reject(err) | ||
strategy.fail = () => reject(new Error('should not have failed')) | ||
strategy.success = () => reject(new Error('should not have succeeded')) | ||
strategy.pass = () => reject(new Error('should not have passed')) | ||
strategy.redirect = (url: string) => { | ||
const urlObj = new URL(url) | ||
assert.strictEqual(urlObj.origin, 'http://127.0.0.1:58080') | ||
assert.strictEqual(urlObj.pathname, '/authorize') | ||
assert.strictEqual(urlObj.searchParams.get('client_id'), 'foobar') | ||
assert.strictEqual(urlObj.searchParams.get('response_type'), 'code') | ||
assert.strictEqual(urlObj.searchParams.get('redirect_uri'), 'http://localhost:3000/oidc/callback') | ||
resolve() | ||
} | ||
}) | ||
strategy.authenticate(mockRequest as any) | ||
await promise | ||
}) | ||
}) | ||
}) |