Skip to content

Commit d4a8021

Browse files
authored
fix: Always require strategy parameter in authentication (#1327)
1 parent fa7f057 commit d4a8021

File tree

10 files changed

+27
-97
lines changed

10 files changed

+27
-97
lines changed

packages/authentication-local/src/strategy.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,9 @@ export class LocalStrategy extends AuthenticationBaseStrategy {
9494
}
9595

9696
async authenticate (data: AuthenticationRequest, params: Params) {
97-
const { passwordField, usernameField, entity, errorMessage } = this.configuration;
97+
const { passwordField, usernameField, entity } = this.configuration;
9898
const username = data[usernameField];
9999
const password = data[passwordField];
100-
101-
if (data.strategy && data.strategy !== this.name) {
102-
throw new NotAuthenticated(errorMessage);
103-
}
104-
105100
const result = await this.findEntity(username, omit(params, 'provider'));
106101

107102
await this.comparePassword(result, password);

packages/authentication-oauth/src/strategy.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
AuthenticationRequest, AuthenticationBaseStrategy
66
} from '@feathersjs/authentication';
77
import { Params } from '@feathersjs/feathers';
8-
import { NotAuthenticated } from '@feathersjs/errors';
98

109
const debug = Debug('@feathersjs/authentication-oauth/strategy');
1110

@@ -97,10 +96,6 @@ export class OAuthStrategy extends AuthenticationBaseStrategy {
9796
}
9897

9998
async authenticate (authentication: AuthenticationRequest, params: Params) {
100-
if (authentication.strategy !== this.name) {
101-
throw new NotAuthenticated('Not authenticated');
102-
}
103-
10499
const entity: string = this.configuration.entity;
105100
const profile = await this.getProfile(authentication, params);
106101
const existingEntity = await this.findEntity(profile, params)

packages/authentication-oauth/test/strategy.test.ts

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,6 @@ describe('@feathersjs/authentication-oauth/strategy', () => {
2020
});
2121

2222
describe('authenticate', () => {
23-
it('errors when strategy is not set', async () => {
24-
try {
25-
await strategy.authenticate({
26-
id: 'newEntity'
27-
}, {});
28-
assert.fail('Should never get here');
29-
} catch (error) {
30-
assert.equal(error.name, 'NotAuthenticated');
31-
assert.equal(error.message, 'Not authenticated');
32-
}
33-
});
34-
3523
it('with new user', async () => {
3624
const authResult = await strategy.authenticate({
3725
strategy: 'test',

packages/authentication/src/core.ts

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -194,41 +194,20 @@ export class AuthenticationBase {
194194
* @param allowed A list of allowed strategy names
195195
*/
196196
async authenticate (authentication: AuthenticationRequest, params: Params, ...allowed: string[]) {
197-
debug('Running authenticate for strategies', allowed);
197+
const { strategy } = authentication || ({} as AuthenticationRequest);
198+
const [ authStrategy ] = this.getStrategies(strategy);
198199

199-
const strategies = this.getStrategies(...allowed)
200-
.filter(current => current && typeof current.authenticate === 'function');
200+
debug('Running authenticate for strategy', strategy, allowed);
201201

202-
if (!authentication || strategies.length === 0) {
202+
if (!authentication || !authStrategy || !allowed.includes(strategy)) {
203203
// If there are no valid strategies or `authentication` is not an object
204-
throw new NotAuthenticated(`No valid authentication strategy available`);
204+
throw new NotAuthenticated(`Invalid authentication information` + (!strategy ? ' (no `strategy` set)' : ''));
205205
}
206206

207-
const { strategy } = authentication;
208-
const authParams = {
207+
return authStrategy.authenticate(authentication, {
209208
...params,
210209
authenticated: true
211-
};
212-
213-
// Throw an error is a `strategy` is indicated but not in the allowed strategies
214-
if (strategy && !allowed.includes(strategy)) {
215-
throw new NotAuthenticated(`Invalid authentication strategy '${strategy}'`);
216-
}
217-
218-
let error: Error|null = null;
219-
220-
for (const authStrategy of strategies) {
221-
try {
222-
const authResult = await authStrategy.authenticate(authentication, authParams);
223-
return authResult;
224-
} catch (currentError) {
225-
error = error || currentError;
226-
}
227-
}
228-
229-
debug('All strategies error. First error is', error);
230-
231-
throw error;
210+
});
232211
}
233212

234213
/**

packages/authentication/src/jwt.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ export class JWTStrategy extends AuthenticationBaseStrategy {
4747
}
4848

4949
async authenticate (authentication: AuthenticationRequest, params: Params) {
50-
const { accessToken, strategy } = authentication;
50+
const { accessToken } = authentication;
5151
const { entity } = this.configuration;
5252

53-
if (!accessToken || (strategy && strategy !== this.name)) {
53+
if (!accessToken) {
5454
throw new NotAuthenticated('Not authenticated');
5555
}
5656

packages/authentication/test/core.test.ts

Lines changed: 13 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import assert from 'assert';
22
import feathers, { Application } from '@feathersjs/feathers';
33
import jwt from 'jsonwebtoken';
44

5-
import { AuthenticationBase } from '../src/core';
5+
import { AuthenticationBase, AuthenticationRequest } from '../src/core';
66
import { Strategy1, Strategy2, MockRequest } from './fixtures';
77
import { ServerResponse } from 'http';
88

@@ -23,6 +23,11 @@ describe('authentication/core', () => {
2323

2424
auth.register('first', new Strategy1());
2525
auth.register('second', new Strategy2());
26+
auth.register('dummy', {
27+
async authenticate (data: AuthenticationRequest) {
28+
return data;
29+
}
30+
});
2631
});
2732

2833
describe('configuration', () => {
@@ -80,7 +85,7 @@ describe('authentication/core', () => {
8085

8186
describe('strategies', () => {
8287
it('strategyNames', () => {
83-
assert.deepStrictEqual(auth.strategyNames, [ 'first', 'second' ]);
88+
assert.deepStrictEqual(auth.strategyNames, [ 'first', 'second', 'dummy' ]);
8489
});
8590

8691
it('getStrategies', () => {
@@ -176,14 +181,6 @@ describe('authentication/core', () => {
176181
}, Strategy2.result));
177182
});
178183

179-
it('returns first success when both strategies succeed', async () => {
180-
const result = await auth.authenticate({
181-
both: true
182-
}, {}, ...auth.strategyNames);
183-
184-
assert.deepStrictEqual(result, Strategy1.result);
185-
});
186-
187184
it('throws error when allowed and passed strategy does not match', async () => {
188185
try {
189186
await auth.authenticate({
@@ -193,43 +190,18 @@ describe('authentication/core', () => {
193190
assert.fail('Should never get here');
194191
} catch (error) {
195192
assert.strictEqual(error.name, 'NotAuthenticated');
196-
assert.strictEqual(error.message, `Invalid authentication strategy 'first'`);
193+
assert.strictEqual(error.message, 'Invalid authentication information');
197194
}
198195
});
199-
});
200196

201-
describe('with a list of strategies and strategy not set in params', () => {
202-
it('returns first success in chain', async () => {
203-
const authentication = {
204-
v2: true,
205-
password: 'supersecret'
206-
};
207-
208-
const result = await auth.authenticate(authentication, {}, 'first', 'second');
209-
210-
assert.deepStrictEqual(result, Object.assign({
211-
authentication,
212-
params: { authenticated: true }
213-
}, Strategy2.result));
214-
});
215-
216-
it('returns first error when all strategies fail', async () => {
217-
try {
218-
await auth.authenticate({}, {}, 'first', 'second');
219-
assert.fail('Should never get here');
220-
} catch (error) {
221-
assert.strictEqual(error.name, 'NotAuthenticated');
222-
assert.strictEqual(error.message, 'Invalid Dave');
223-
}
224-
});
225-
226-
it('errors when there is no valid strategy', async () => {
197+
it('throws error when strategy is not set', async () => {
227198
try {
228-
await auth.authenticate({}, {}, 'bla');
199+
await auth.authenticate({
200+
username: 'Dummy'
201+
}, {}, 'second');
229202
assert.fail('Should never get here');
230203
} catch (error) {
231-
assert.strictEqual(error.name, 'NotAuthenticated');
232-
assert.strictEqual(error.message, 'No valid authentication strategy available');
204+
assert.strictEqual(error.message, 'Invalid authentication information (no `strategy` set)');
233205
}
234206
});
235207
});

packages/authentication/test/hooks/authenticate.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ describe('authentication/hooks/authenticate', () => {
161161
try {
162162
await app.service('users').get(1, {
163163
authentication: {
164+
strategy: 'first',
164165
some: 'thing'
165166
}
166167
});

packages/authentication/test/jwt.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ describe('authentication/jwt', () => {
8585
assert.fail('Should never get here');
8686
} catch (error) {
8787
assert.strictEqual(error.name, 'NotAuthenticated');
88-
assert.strictEqual(error.message, 'Not authenticated');
88+
assert.strictEqual(error.message, 'Invalid authentication information (no `strategy` set)');
8989
}
9090
});
9191

packages/authentication/test/service.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ describe('authentication/service', () => {
211211
await app.service('authentication').remove(null);
212212
assert.fail('Should never get here');
213213
} catch (error) {
214-
assert.strictEqual(error.message, 'No valid authentication strategy available');
214+
assert.strictEqual(error.message, 'Invalid authentication information (no `strategy` set)');
215215
}
216216
});
217217
});

packages/express/test/authentication.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ describe('@feathersjs/express/authentication', () => {
165165
const { data } = error.response;
166166

167167
assert.strictEqual(data.name, 'NotAuthenticated');
168-
assert.strictEqual(data.message, 'No valid authentication strategy available');
168+
assert.strictEqual(data.message, 'Invalid authentication information (no `strategy` set)');
169169
});
170170
});
171171

0 commit comments

Comments
 (0)