This repository has been archived by the owner on Mar 22, 2022. It is now read-only.
/
authenticate.js
99 lines (78 loc) · 3.68 KB
/
authenticate.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
const errors = require('@feathersjs/errors');
const Debug = require('debug');
const merge = require('lodash.merge');
const { NotAuthenticated } = require('@feathersjs/errors');
const debug = Debug('@feathersjs/authentication:hooks:authenticate');
module.exports = function authenticate (_strategies, options = {}) {
if (!_strategies) {
throw new Error(`The 'authenticate' hook requires one of your registered passport strategies.`);
}
const strategies = Array.isArray(_strategies) ? _strategies : [ _strategies ];
return function (hook) {
const app = hook.app;
// If called internally or we are already authenticated skip
if (!hook.params.provider || hook.params.authenticated) {
return Promise.resolve(hook);
}
if (hook.type !== 'before') {
return Promise.reject(new Error(`The 'authenticate' hook should only be used as a 'before' hook.`));
}
hook.data = hook.data || {};
const strategy = hook.data.strategy || strategies[0];
if (strategies.indexOf(strategy) === -1) {
return Promise.reject(new NotAuthenticated(`Strategy ${strategy} is not permitted`));
}
// Handle the case where authenticate hook was registered without a passport strategy specified
if (!strategy) {
return Promise.reject(new errors.GeneralError(`You must provide an authentication 'strategy'`));
}
// The client must send a `strategy` name.
if (!app.passport._strategy(strategy)) {
return Promise.reject(new errors.BadRequest(`Authentication strategy '${strategy}' is not registered.`));
}
// NOTE (EK): Passport expects an express/connect
// like request object. So we need to create one.
let request = {
query: hook.data,
body: hook.data,
params: hook.params,
headers: hook.params.headers || {},
cookies: hook.params.cookies || {},
session: {}
};
const strategyOptions = merge({}, app.passport.options(strategy), options);
debug(`Attempting to authenticate using ${strategy} strategy with options`, strategyOptions);
return app.authenticate(strategy, strategyOptions)(request).then((result = {}) => {
if (result.fail && options.allowUnauthenticated !== true) {
// TODO (EK): Reject with something...
// You get back result.challenge and result.status
if (strategyOptions.failureRedirect) {
// TODO (EK): Bypass the service?
// hook.result = true
Object.defineProperty(hook.data, '__redirect', { value: { status: 302, url: strategyOptions.failureRedirect } });
}
const { challenge, status = 401 } = result;
let message = challenge && challenge.message ? challenge.message : challenge;
if (strategyOptions.failureMessage) {
message = strategyOptions.failureMessage;
}
return Promise.reject(new errors[status](message, challenge));
}
if (result.success || options.allowUnauthenticated === true) {
hook.params = Object.assign({ authenticated: result.success }, hook.params, result.data);
// Add the user to the original request object so it's available in the socket handler
Object.assign(request.params, hook.params);
if (strategyOptions.successRedirect) {
// TODO (EK): Bypass the service?
// hook.result = true
Object.defineProperty(hook.data, '__redirect', { value: { status: 302, url: strategyOptions.successRedirect } });
}
} else if (result.redirect) {
// TODO (EK): Bypass the service?
// hook.result = true
Object.defineProperty(hook.data, '__redirect', { value: { status: result.status, url: result.url } });
}
return Promise.resolve(hook);
});
};
};