diff --git a/packages/authentication-local/src/hooks/hash-password.ts b/packages/authentication-local/src/hooks/hash-password.ts index 69ed6d7a27..371f1914f5 100644 --- a/packages/authentication-local/src/hooks/hash-password.ts +++ b/packages/authentication-local/src/hooks/hash-password.ts @@ -2,6 +2,7 @@ import { get, set, cloneDeep } from 'lodash'; import { BadRequest } from '@feathersjs/errors'; import Debug from 'debug'; import { HookContext } from '@feathersjs/feathers'; +import { LocalStrategy } from '../strategy'; const debug = Debug('@feathersjs/authentication-local/hooks/hash-password'); @@ -28,15 +29,14 @@ export default function hashPassword (field: string, options: HashPasswordOption return context; } - const serviceName = options.authentication || app.get('defaultAuthentication'); - const authService = app.service(serviceName); + const authService = app.defaultAuthentication(options.authentication); const { strategy = 'local' } = options; if (!authService || typeof authService.getStrategies !== 'function') { - throw new BadRequest(`Could not find '${serviceName}' service to hash password`); + throw new BadRequest(`Could not find an authentication service to hash password`); } - const [ localStrategy ] = authService.getStrategies(strategy); + const [ localStrategy ] = authService.getStrategies(strategy) as LocalStrategy[]; if (!localStrategy || typeof localStrategy.hashPassword !== 'function') { throw new BadRequest(`Could not find '${strategy}' strategy to hash password`); diff --git a/packages/authentication-local/src/strategy.ts b/packages/authentication-local/src/strategy.ts index febde71737..28faf7c56b 100644 --- a/packages/authentication-local/src/strategy.ts +++ b/packages/authentication-local/src/strategy.ts @@ -108,7 +108,7 @@ export class LocalStrategy extends AuthenticationBaseStrategy { throw new NotAuthenticated(errorMessage); } - async hashPassword (password: string) { + async hashPassword (password: string, _params: Params) { return bcrypt.hash(password, this.configuration.hashSize); } diff --git a/packages/authentication-local/test/hooks/hash-password.test.ts b/packages/authentication-local/test/hooks/hash-password.test.ts index 8cfbe56360..7a97b5768c 100644 --- a/packages/authentication-local/test/hooks/hash-password.test.ts +++ b/packages/authentication-local/test/hooks/hash-password.test.ts @@ -35,7 +35,7 @@ describe('@feathersjs/authentication-local/hooks/hash-password', () => { assert.fail('Should never get here'); } catch (error) { assert.strictEqual(error.message, - `Could not find 'authentication' service to hash password` + 'Could not find an authentication service to hash password' ); } }); diff --git a/packages/authentication-oauth/src/express.ts b/packages/authentication-oauth/src/express.ts index 8c36b257b4..ff17f76cf1 100644 --- a/packages/authentication-oauth/src/express.ts +++ b/packages/authentication-oauth/src/express.ts @@ -2,7 +2,7 @@ import { express as grantExpress } from 'grant'; import Debug from 'debug'; import { Application } from '@feathersjs/feathers'; -import { AuthenticationService, AuthenticationResult } from '@feathersjs/authentication'; +import { AuthenticationResult } from '@feathersjs/authentication'; import qs from 'querystring'; import { Application as ExpressApplication, @@ -49,7 +49,7 @@ export default (options: OauthSetupSettings) => { authApp.get('/:name/authenticate', async (req, res, next) => { const { name } = req.params; const { accessToken, grant } = req.session; - const service: AuthenticationService = app.service(authService); + const service = app.defaultAuthentication(authService); const [ strategy ] = service.getStrategies(name) as OAuthStrategy[]; const sendResponse = async (data: AuthenticationResult|Error) => { try { diff --git a/packages/authentication-oauth/src/index.ts b/packages/authentication-oauth/src/index.ts index 25f616b3cf..92290aab06 100644 --- a/packages/authentication-oauth/src/index.ts +++ b/packages/authentication-oauth/src/index.ts @@ -1,7 +1,6 @@ import Debug from 'debug'; import { merge, each, omit } from 'lodash'; import { Application } from '@feathersjs/feathers'; -import { AuthenticationService } from '@feathersjs/authentication'; import { OAuthStrategy, OAuthProfile } from './strategy'; import { default as setupExpress } from './express'; import { OauthSetupSettings, getDefaultSettings } from './utils'; @@ -11,17 +10,16 @@ const debug = Debug('@feathersjs/authentication-oauth'); export { OauthSetupSettings, OAuthStrategy, OAuthProfile }; export const setup = (options: OauthSetupSettings) => (app: Application) => { - const authPath = options.authService; - const service: AuthenticationService = app.service(authPath); + const service = app.defaultAuthentication ? app.defaultAuthentication(options.authService) : null; if (!service) { - throw new Error(`'${authPath}' authentication service must exist before registering @feathersjs/authentication-oauth`); + throw new Error('An authentication service must exist before registering @feathersjs/authentication-oauth'); } const { oauth } = service.configuration; if (!oauth) { - debug(`No oauth configuration found at '${authPath}'. Skipping oAuth setup.`); + debug(`No oauth configuration found in authentication configuration. Skipping oAuth setup.`); return; } diff --git a/packages/authentication-oauth/src/utils.ts b/packages/authentication-oauth/src/utils.ts index 7f21a7e5fe..5c5a50e63c 100644 --- a/packages/authentication-oauth/src/utils.ts +++ b/packages/authentication-oauth/src/utils.ts @@ -3,14 +3,13 @@ import session from 'express-session'; import { Application } from '@feathersjs/feathers'; export interface OauthSetupSettings { - authService: string; + authService?: string; linkStrategy: string; expressSession: RequestHandler; } -export const getDefaultSettings = (app: Application, other?: Partial) => { +export const getDefaultSettings = (_app: Application, other?: Partial) => { const defaults: OauthSetupSettings = { - authService: app.get('defaultAuthentication'), linkStrategy: 'jwt', expressSession: session({ secret: Math.random().toString(36).substring(7), diff --git a/packages/authentication-oauth/test/index.test.ts b/packages/authentication-oauth/test/index.test.ts index 834f065666..014a50b7d8 100644 --- a/packages/authentication-oauth/test/index.test.ts +++ b/packages/authentication-oauth/test/index.test.ts @@ -13,7 +13,7 @@ describe('@feathersjs/authentication-oauth', () => { assert.fail('Should never get here'); } catch (error) { assert.equal(error.message, - `'something' authentication service must exist before registering @feathersjs/authentication-oauth` + 'An authentication service must exist before registering @feathersjs/authentication-oauth' ); } }); diff --git a/packages/authentication-oauth/test/utils.test.ts b/packages/authentication-oauth/test/utils.test.ts index 20fd70a5c1..04aee35b22 100644 --- a/packages/authentication-oauth/test/utils.test.ts +++ b/packages/authentication-oauth/test/utils.test.ts @@ -6,7 +6,7 @@ describe('@feathersjs/authentication-oauth/utils', () => { it('getDefaultSettings', () => { const settings = getDefaultSettings(app); - assert.equal(settings.authService, 'authentication'); + assert.equal(settings.authService, undefined); assert.equal(settings.linkStrategy, 'jwt'); }); }); diff --git a/packages/authentication/src/hooks/authenticate.ts b/packages/authentication/src/hooks/authenticate.ts index 21650cbc07..b60cb45275 100644 --- a/packages/authentication/src/hooks/authenticate.ts +++ b/packages/authentication/src/hooks/authenticate.ts @@ -2,7 +2,6 @@ import { flatten, omit, merge } from 'lodash'; import { HookContext } from '@feathersjs/feathers'; import { NotAuthenticated } from '@feathersjs/errors'; import Debug from 'debug'; -import { AuthenticationService } from '../service'; const debug = Debug('@feathersjs/authentication/hooks/authenticate'); @@ -22,12 +21,9 @@ export default (originalSettings: string|AuthenticateHookSettings, ...originalSt return async (context: HookContext) => { const { app, params, type, path, service } = context; - const { - service: authPath = app.get('defaultAuthentication'), - strategies - } = settings; + const { strategies } = settings; const { provider, authentication } = params; - const authService = app.service(authPath) as unknown as AuthenticationService; + const authService = app.defaultAuthentication(settings.service); debug(`Running authenticate hook on '${path}'`); @@ -36,7 +32,7 @@ export default (originalSettings: string|AuthenticateHookSettings, ...originalSt } if (!authService || typeof authService.authenticate !== 'function') { - throw new NotAuthenticated(`Could not find authentication service at '${authPath}'`); + throw new NotAuthenticated('Could not find a valid authentication service'); } // @ts-ignore diff --git a/packages/authentication/src/service.ts b/packages/authentication/src/service.ts index e5bbefcbe6..4d036333e7 100644 --- a/packages/authentication/src/service.ts +++ b/packages/authentication/src/service.ts @@ -3,11 +3,38 @@ import { merge, get } from 'lodash'; import { NotAuthenticated } from '@feathersjs/errors'; import { AuthenticationBase, AuthenticationResult, AuthenticationRequest } from './core'; import { connection, events } from './hooks'; -import { Params, ServiceMethods } from '@feathersjs/feathers'; +import { Application, Params, ServiceMethods } from '@feathersjs/feathers'; const debug = Debug('@feathersjs/authentication/service'); +declare module '@feathersjs/feathers' { + interface Application { + + /** + * Returns the default authentication service or the + * authentication service for a given path. + * + * @param location The service path to use (optional) + */ + defaultAuthentication (location?: string): AuthenticationService; + } +} + export class AuthenticationService extends AuthenticationBase implements Partial> { + constructor (app: Application, configKey: string = 'authentication', options = {}) { + super(app, configKey, options); + + if (typeof app.defaultAuthentication !== 'function') { + app.defaultAuthentication = function (location?: string) { + const configKey = app.get('defaultAuthentication'); + const path = location || Object.keys(this.services).find(current => + this.service(current).configKey === configKey + ); + + return path ? this.service(path) : null; + }; + } + } /** * Return the payload for a JWT based on the authentication result. * Called internally by the `create` method. diff --git a/packages/authentication/test/hooks/authenticate.test.ts b/packages/authentication/test/hooks/authenticate.test.ts index b565255216..907ba8c976 100644 --- a/packages/authentication/test/hooks/authenticate.test.ts +++ b/packages/authentication/test/hooks/authenticate.test.ts @@ -95,7 +95,7 @@ describe('authentication/hooks/authenticate', () => { assert.fail('Should never get here'); } catch (error) { assert.strictEqual(error.name, 'NotAuthenticated'); - assert.strictEqual(error.message, `Could not find authentication service at 'authentication'`); + assert.strictEqual(error.message, `Could not find a valid authentication service`); } }); diff --git a/packages/authentication/test/service.test.ts b/packages/authentication/test/service.test.ts index 5b6a3e9d3a..a521230248 100644 --- a/packages/authentication/test/service.test.ts +++ b/packages/authentication/test/service.test.ts @@ -6,8 +6,7 @@ import feathers, { Application, Service } from '@feathersjs/feathers'; import memory from 'feathers-memory'; import defaultOptions from '../src/options'; -import { AuthenticationService } from '../src/service'; -import { AuthenticationResult } from '../src/core'; +import { AuthenticationService, AuthenticationResult } from '../src'; import { Strategy1 } from './fixtures'; @@ -38,6 +37,11 @@ describe('authentication/service', () => { assert.deepStrictEqual(app.service('authentication').configuration, Object.assign({}, defaultOptions, app.get('authentication'))); }); + it('app.defaultAuthentication()', () => { + assert.strictEqual(app.defaultAuthentication(), app.service('authentication')); + assert.strictEqual(app.defaultAuthentication('dummy'), undefined); + }); + describe('create', () => { it('creates a valid accessToken and includes strategy result', async () => { const service = app.service('authentication'); diff --git a/packages/express/lib/authentication.js b/packages/express/lib/authentication.js index 2728f2bf90..a54d844490 100644 --- a/packages/express/lib/authentication.js +++ b/packages/express/lib/authentication.js @@ -5,20 +5,11 @@ const normalizeStrategy = (_settings = [], ..._strategies) => typeof _settings === 'string' ? { strategies: flatten([ _settings, ..._strategies ]) } : _settings; -const getService = (settings, app) => { - const path = settings.service || app.get('defaultAuthentication'); - - if (typeof path !== 'string') { - return null; - } - - return app.service(path) || null; -}; exports.parseAuthentication = (settings = {}) => { return function (req, res, next) { const { app } = req; - const service = getService(settings, app); + const service = app.defaultAuthentication ? app.defaultAuthentication(settings.service) : null; if (service === null) { return next(); @@ -53,7 +44,7 @@ exports.authenticate = (...strategies) => { return function (req, res, next) { const { app, authentication } = req; - const service = getService(settings, app); + const service = app.defaultAuthentication(settings.service); debug('Authenticating with Express middleware and strategies', settings.strategies);