diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..b7486394 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +If you discover a vulnerability in the package, please raise an issue with the description of the security problem you have discovered. + +Contributions with the fixes are welcome, so feel free to create a Pull Request with a fix :) diff --git a/src/runtime/server/middleware/basicAuth.ts b/src/runtime/server/middleware/basicAuth.ts index 82fee4f2..32e869d1 100644 --- a/src/runtime/server/middleware/basicAuth.ts +++ b/src/runtime/server/middleware/basicAuth.ts @@ -20,11 +20,22 @@ const securityConfig = useRuntimeConfig().private export default defineEventHandler((event) => { const credentials = getCredentials(event.node.req) - const basicAuthConfig: BasicAuth = securityConfig.basicAuth + const basicAuthConfig = securityConfig.basicAuth - if (basicAuthConfig?.exclude?.some(el => event.path?.startsWith(el)) || basicAuthConfig?.include?.some(el => !event.path?.startsWith(el))) { return } + // Check for exclusion paths + const excludePaths = basicAuthConfig?.exclude || ['/'] + const isPathExcluded = excludePaths.some(el => event.path?.startsWith(el)) - if (!credentials || !validateCredentials(credentials!, basicAuthConfig)) { + // Check for inclusion paths + const includePaths = basicAuthConfig?.include || [] + const isPathIncluded = includePaths.some(el => event.path?.startsWith(el)) + + if (isPathExcluded && !isPathIncluded) { + return + } + + if (!credentials || !validateCredentials(credentials, basicAuthConfig)) { + // Set the authentication header and send an error response setHeader(event, 'WWW-Authenticate', `Basic realm=${basicAuthConfig.message || 'Please enter username and password'}`) sendError(event, createError({ statusCode: 401, statusMessage: 'Access denied' })) } diff --git a/test/basicAuth.test.ts b/test/basicAuth.test.ts index a45477b5..a8601f39 100644 --- a/test/basicAuth.test.ts +++ b/test/basicAuth.test.ts @@ -19,4 +19,28 @@ describe('[nuxt-security] Basic Auth', async () => { expect(res.status).toBe(200) }) + + it ('should return 401 status code for included route', async () => { + const res = await fetch('/api/hello/world/nuxt') + + expect(res.status).toBe(401) + }) + + it ('should return 200 status code for multiple included route', async () => { + const res = await fetch('/admin') + + expect(res.status).toBe(401) + }) + + it ('should return 200 status code for multiple excluded route', async () => { + const res = await fetch('/content') + + expect(res.status).toBe(200) + }) + + it ('should return a 401 status code for any arbitrary path', async () => { + const res = await fetch('/arbitrary') + + expect(res.status).toBe(401) + }) }) diff --git a/test/fixtures/basicAuth/nuxt.config.ts b/test/fixtures/basicAuth/nuxt.config.ts index 21c4e02f..eba75824 100644 --- a/test/fixtures/basicAuth/nuxt.config.ts +++ b/test/fixtures/basicAuth/nuxt.config.ts @@ -6,7 +6,8 @@ export default defineNuxtConfig({ ], security: { basicAuth: { - exclude: ['/api'], + exclude: ['/api', '/content'], + include: ['/api/hello/world', '/admin'], name: 'test', pass: 'test', enabled: true,