@tiledesk/tiledesk-server 2.14.17 → 2.14.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/app.js +2 -0
- package/middleware/file-type.js +50 -0
- package/middleware/passport.js +531 -589
- package/models/analyticResult.js +2 -1
- package/package.json +3 -2
- package/routes/files.js +75 -18
- package/routes/filesp.js +545 -0
- package/routes/llm.js +1 -1
- package/services/fileGridFsService.js +195 -6
- package/test/fileFilter.test.js +194 -0
- package/test/filepRoute.js +561 -0
- package/test/fixtures/avatar.jpg +0 -0
- package/test/fixtures/fake.pdf +8 -0
- package/test/fixtures/sample.xyz +0 -0
package/middleware/passport.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var passportJWT = require("passport-jwt");
|
|
1
|
+
var passportJWT = require("passport-jwt");
|
|
2
2
|
var JwtStrategy = passportJWT.Strategy;
|
|
3
3
|
var ExtractJwt = passportJWT.ExtractJwt;
|
|
4
4
|
|
|
5
|
-
var passportHttp = require("passport-http");
|
|
5
|
+
var passportHttp = require("passport-http");
|
|
6
6
|
var BasicStrategy = passportHttp.BasicStrategy;
|
|
7
7
|
var GoogleStrategy = require('passport-google-oidc');
|
|
8
8
|
|
|
@@ -31,15 +31,15 @@ var uniqid = require('uniqid');
|
|
|
31
31
|
const MaskData = require("maskdata");
|
|
32
32
|
|
|
33
33
|
const maskOptions = {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
// Character to mask the data. default value is '*'
|
|
35
|
+
maskWith: "*",
|
|
36
|
+
// If the starting 'n' digits needs to be unmasked
|
|
37
|
+
// Default value is 4
|
|
38
|
+
unmaskedStartDigits: 3, //Should be positive Integer
|
|
39
|
+
//If the ending 'n' digits needs to be unmasked
|
|
40
|
+
// Default value is 1
|
|
41
|
+
unmaskedEndDigits: 3 // Should be positive Integer
|
|
42
|
+
};
|
|
43
43
|
|
|
44
44
|
var alg = process.env.GLOBAL_SECRET_ALGORITHM;
|
|
45
45
|
winston.info('Authentication Global Algorithm : ' + alg);
|
|
@@ -52,7 +52,7 @@ var pKey = process.env.GLOBAL_SECRET_OR_PUB_KEY;
|
|
|
52
52
|
// console.log("pKey",pKey);
|
|
53
53
|
|
|
54
54
|
if (pKey) {
|
|
55
|
-
|
|
55
|
+
configSecret = pKey.replace(/\\n/g, '\n');
|
|
56
56
|
}
|
|
57
57
|
// console.log("configSecret",configSecret);
|
|
58
58
|
// if (process.env.GLOBAL_SECRET_OR_PUB_KEY) {
|
|
@@ -66,663 +66,619 @@ var maskedconfigSecret = MaskData.maskPhone(configSecret, maskOptions);
|
|
|
66
66
|
winston.info('Authentication Global Secret : ' + maskedconfigSecret);
|
|
67
67
|
|
|
68
68
|
var enableGoogleSignin = false;
|
|
69
|
-
if (process.env.GOOGLE_SIGNIN_ENABLED=="true" || process.env.GOOGLE_SIGNIN_ENABLED == true) {
|
|
70
|
-
|
|
69
|
+
if (process.env.GOOGLE_SIGNIN_ENABLED == "true" || process.env.GOOGLE_SIGNIN_ENABLED == true) {
|
|
70
|
+
enableGoogleSignin = true;
|
|
71
71
|
}
|
|
72
72
|
winston.info('Authentication Google Signin enabled : ' + enableGoogleSignin);
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
|
|
76
75
|
var enableOauth2Signin = false;
|
|
77
|
-
if (process.env.OAUTH2_SIGNIN_ENABLED=="true" || process.env.OAUTH2_SIGNIN_ENABLED == true) {
|
|
78
|
-
|
|
76
|
+
if (process.env.OAUTH2_SIGNIN_ENABLED == "true" || process.env.OAUTH2_SIGNIN_ENABLED == true) {
|
|
77
|
+
enableOauth2Signin = true;
|
|
79
78
|
}
|
|
80
79
|
winston.info('Authentication Oauth2 Signin enabled : ' + enableOauth2Signin);
|
|
81
80
|
|
|
82
81
|
|
|
83
82
|
var jwthistory = undefined;
|
|
84
83
|
try {
|
|
85
|
-
|
|
86
|
-
} catch(err) {
|
|
87
|
-
|
|
84
|
+
jwthistory = require('@tiledesk-ent/tiledesk-server-jwthistory');
|
|
85
|
+
} catch (err) {
|
|
86
|
+
winston.debug("jwthistory not present");
|
|
88
87
|
}
|
|
89
88
|
|
|
90
|
-
module.exports = function(passport) {
|
|
91
|
-
|
|
89
|
+
module.exports = function (passport) {
|
|
90
|
+
|
|
92
91
|
// passport.serializeUser(function(user, done) {
|
|
93
92
|
// console.log("serializeUser");
|
|
94
93
|
|
|
95
94
|
// done(null, user);
|
|
96
95
|
// });
|
|
97
|
-
|
|
96
|
+
|
|
98
97
|
// passport.deserializeUser(function(user, done) {
|
|
99
98
|
// done(null, user);
|
|
100
99
|
// });
|
|
101
100
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
101
|
+
var opts = {
|
|
102
|
+
// jwtFromRequest: ExtractJwt.fromAuthHeader(),
|
|
103
|
+
jwtFromRequest: ExtractJwt.fromExtractors([ExtractJwt.fromAuthHeaderWithScheme("jwt"), ExtractJwt.fromUrlQueryParameter('secret_token')]),
|
|
104
|
+
//this will help you to pass request body to passport
|
|
105
|
+
passReqToCallback: true, //https://stackoverflow.com/questions/55163015/how-to-bind-or-pass-req-parameter-to-passport-js-jwt-strategy
|
|
106
|
+
// secretOrKey: configSecret,
|
|
107
|
+
secretOrKeyProvider: function (request, rawJwtToken, done) {
|
|
108
|
+
// winston.info("secretOrKeyProvider ", request );
|
|
109
|
+
|
|
110
|
+
// if (request.project) {
|
|
111
|
+
// winston.info("secretOrKeyProvider.request.project.jwtSecret: "+request.project.jwtSecret );
|
|
112
|
+
// }
|
|
113
|
+
|
|
114
|
+
// winston.info("secretOrKeyProvider: "+request.project.name );
|
|
115
|
+
// winston.info("secretOrKeyProvider: "+rawJwtToken );
|
|
116
|
+
|
|
117
|
+
var decoded = request.preDecodedJwt
|
|
118
|
+
winston.debug("decoded: ", decoded);
|
|
119
|
+
if (!decoded) { //fallback
|
|
121
120
|
winston.debug("load decoded after: ");
|
|
122
121
|
decoded = jwt.decode(rawJwtToken);
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
winston.debug("decoded after: ", decoded);
|
|
125
|
+
|
|
126
|
+
// qui arriva questo
|
|
127
|
+
// decoded: {"_id":"5ce3ee855c520200176c189e","updatedAt":"2019-05-31T09:50:22.949Z","createdAt":"2019-05-21T12:26:45.192Z","name":"botext","url":"https://tiledesk-v2-simple--andrealeo83.repl.co","id_project":"5ce3d1ceb25ad30017274bc5","trashed":false,"createdBy":"5ce3d1c7b25ad30017274bc2","__v":0,"external":true,"iat":1559297130,"aud":"https://tiledesk.com","iss":"https://tiledesk.com","sub":"5ce3ee855c520200176c189e@tiledesk.com/bot"}
|
|
126
128
|
|
|
127
|
-
// qui arriva questo
|
|
128
|
-
// decoded: {"_id":"5ce3ee855c520200176c189e","updatedAt":"2019-05-31T09:50:22.949Z","createdAt":"2019-05-21T12:26:45.192Z","name":"botext","url":"https://tiledesk-v2-simple--andrealeo83.repl.co","id_project":"5ce3d1ceb25ad30017274bc5","trashed":false,"createdBy":"5ce3d1c7b25ad30017274bc2","__v":0,"external":true,"iat":1559297130,"aud":"https://tiledesk.com","iss":"https://tiledesk.com","sub":"5ce3ee855c520200176c189e@tiledesk.com/bot"}
|
|
129
129
|
|
|
130
|
+
if (decoded && decoded.aud) {
|
|
130
131
|
|
|
131
|
-
|
|
132
|
+
winston.debug("decoded.aud: " + decoded.aud);
|
|
132
133
|
|
|
133
|
-
winston.debug("decoded.aud: "+ decoded.aud );
|
|
134
134
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
winston.debug("audUrl: "+ audUrl );
|
|
135
|
+
const audUrl = new URL(decoded.aud);
|
|
136
|
+
winston.debug("audUrl: " + audUrl);
|
|
138
137
|
const path = audUrl.pathname;
|
|
139
|
-
winston.debug("audUrl path: " + path
|
|
140
|
-
|
|
138
|
+
winston.debug("audUrl path: " + path);
|
|
139
|
+
|
|
141
140
|
const AudienceType = path.split("/")[1];
|
|
142
|
-
winston.debug("audUrl AudienceType: " + AudienceType
|
|
141
|
+
winston.debug("audUrl AudienceType: " + AudienceType);
|
|
143
142
|
|
|
144
143
|
const AudienceId = path.split("/")[2];
|
|
145
|
-
winston.debug("audUrl AudienceId: " + AudienceId
|
|
144
|
+
winston.debug("audUrl AudienceId: " + AudienceId);
|
|
146
145
|
|
|
147
|
-
|
|
146
|
+
if (AudienceType == "bots") {
|
|
148
147
|
|
|
149
|
-
|
|
148
|
+
if (!AudienceId) {
|
|
150
149
|
winston.error("AudienceId for bots is required: ", decoded);
|
|
151
150
|
return done(null, null);
|
|
152
|
-
|
|
151
|
+
}
|
|
153
152
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
153
|
+
winston.debug("bot id AudienceId: " + AudienceId);
|
|
154
|
+
let qbot = Faq_kb.findById(AudienceId).select('+secret');
|
|
155
|
+
|
|
156
|
+
if (cacheEnabler.faq_kb) {
|
|
158
157
|
let id_project = decoded.id_project;
|
|
159
|
-
winston.debug("decoded.id_project:"+decoded.id_project);
|
|
160
|
-
qbot.cache(cacheUtil.defaultTTL, id_project+":faq_kbs:id:"+AudienceId+":secret")
|
|
158
|
+
winston.debug("decoded.id_project:" + decoded.id_project);
|
|
159
|
+
qbot.cache(cacheUtil.defaultTTL, id_project + ":faq_kbs:id:" + AudienceId + ":secret")
|
|
161
160
|
winston.debug('faq_kb AudienceId cache enabled');
|
|
162
|
-
|
|
161
|
+
}
|
|
163
162
|
|
|
164
163
|
|
|
165
|
-
|
|
164
|
+
qbot.exec(function (err, faq_kb) { //TODO add cache_bot_here
|
|
166
165
|
if (err) {
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
winston.error("auth Faq_kb err: ", {error: err, decoded: decoded});
|
|
167
|
+
return done(null, null);
|
|
169
168
|
}
|
|
170
169
|
if (!faq_kb) {
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
winston.warn("faq_kb not found with id: " + AudienceId, decoded);
|
|
171
|
+
return done(null, null);
|
|
173
172
|
}
|
|
174
173
|
|
|
175
|
-
winston.debug("faq_kb: ", faq_kb
|
|
174
|
+
winston.debug("faq_kb: ", faq_kb);
|
|
176
175
|
// winston.debug("faq_kb.secret: "+ faq_kb.secret );
|
|
177
176
|
done(null, faq_kb.secret);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
else if (AudienceType == "projects") {
|
|
182
|
-
if (!AudienceId) {
|
|
177
|
+
});
|
|
178
|
+
} else if (AudienceType == "projects") {
|
|
179
|
+
if (!AudienceId) {
|
|
183
180
|
winston.error("AudienceId for projects is required: ", decoded);
|
|
184
181
|
return done(null, null);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
winston.debug("project id: "+ AudienceId );
|
|
188
|
-
Project.findOne({_id: AudienceId, status: 100}).select('+jwtSecret')
|
|
189
|
-
//@DISABLED_CACHE .cache(cacheUtil.queryTTL, "projects:query:id:status:100:"+AudienceId+":select:+jwtSecret") //project_cache
|
|
190
|
-
.exec(function (err, project){
|
|
191
|
-
if (err) {
|
|
192
|
-
winston.error("auth Project err: ", {error:err, decoded: decoded} );
|
|
193
|
-
return done(null, null);
|
|
194
|
-
}
|
|
195
|
-
if (!project) {
|
|
196
|
-
winston.warn("Project not found with id: " + AudienceId, decoded);
|
|
197
|
-
return done(null, null);
|
|
198
|
-
}
|
|
199
|
-
winston.debug("project: ", project );
|
|
200
|
-
winston.debug("project.jwtSecret: "+ project.jwtSecret );
|
|
201
|
-
done(null, project.jwtSecret);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
182
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
183
|
+
|
|
184
|
+
winston.debug("project id: " + AudienceId);
|
|
185
|
+
Project.findOne({_id: AudienceId, status: 100}).select('+jwtSecret')
|
|
186
|
+
//@DISABLED_CACHE .cache(cacheUtil.queryTTL, "projects:query:id:status:100:"+AudienceId+":select:+jwtSecret") //project_cache
|
|
187
|
+
.exec(function (err, project) {
|
|
188
|
+
if (err) {
|
|
189
|
+
winston.error("auth Project err: ", {error: err, decoded: decoded});
|
|
190
|
+
return done(null, null);
|
|
191
|
+
}
|
|
192
|
+
if (!project) {
|
|
193
|
+
winston.warn("Project not found with id: " + AudienceId, decoded);
|
|
194
|
+
return done(null, null);
|
|
195
|
+
}
|
|
196
|
+
winston.debug("project: ", project);
|
|
197
|
+
winston.debug("project.jwtSecret: " + project.jwtSecret);
|
|
198
|
+
done(null, project.jwtSecret);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
} else if (AudienceType == "subscriptions") {
|
|
202
|
+
|
|
203
|
+
if (!AudienceId) {
|
|
208
204
|
winston.error("AudienceId for subscriptions is required: ", decoded);
|
|
209
205
|
return done(null, null);
|
|
210
|
-
|
|
206
|
+
}
|
|
211
207
|
|
|
212
|
-
|
|
213
|
-
|
|
208
|
+
winston.debug("Subscription id: " + AudienceId);
|
|
209
|
+
Subscription.findById(AudienceId).select('+secret').exec(function (err, subscription) {
|
|
214
210
|
if (err) {
|
|
215
|
-
|
|
216
|
-
|
|
211
|
+
winston.error("auth Subscription err: ", {error: err, decoded: decoded});
|
|
212
|
+
return done(null, null);
|
|
217
213
|
}
|
|
218
214
|
if (!subscription) {
|
|
219
|
-
|
|
220
|
-
|
|
215
|
+
winston.warn("subscription not found with id: " + AudienceId, decoded);
|
|
216
|
+
return done(null, null);
|
|
221
217
|
}
|
|
222
|
-
winston.debug("subscription: ", subscription
|
|
223
|
-
winston.debug("subscription.secret: "+ subscription.secret
|
|
218
|
+
winston.debug("subscription: ", subscription);
|
|
219
|
+
winston.debug("subscription.secret: " + subscription.secret);
|
|
224
220
|
done(null, subscription.secret);
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
done(null, configSecret); //pub_jwt pp_jwt
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
winston.debug("configSecret: "+ maskedconfigSecret );
|
|
221
|
+
});
|
|
222
|
+
} else if (decoded.aud == "https://tiledesk.com") {
|
|
223
|
+
winston.debug("configSecret: " + maskedconfigSecret);
|
|
224
|
+
done(null, configSecret); //pub_jwt pp_jwt
|
|
225
|
+
} else {
|
|
226
|
+
winston.debug("configSecret: " + maskedconfigSecret);
|
|
227
|
+
done(null, configSecret); //pub_jwt pp_jwt
|
|
228
|
+
}
|
|
229
|
+
} else {
|
|
230
|
+
winston.debug("configSecret: " + maskedconfigSecret);
|
|
240
231
|
done(null, configSecret); //pub_jwt pp_jwt
|
|
241
|
-
}
|
|
242
232
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
winston.debug("passport opts: ", opts);
|
|
247
|
-
|
|
248
|
-
passport.use(new JwtStrategy(opts, async(req, jwt_payload, done) => {
|
|
249
|
-
// passport.use(new JwtStrategy(opts, function(req, jwt_payload, done) {
|
|
250
|
-
winston.debug("jwt_payload",jwt_payload);
|
|
251
|
-
// console.log("req",req);
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
// console.log("jwt_payload._doc._id",jwt_payload._doc._id);
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
if (jwt_payload._id == undefined && (jwt_payload._doc == undefined || (jwt_payload._doc && jwt_payload._doc._id==undefined))) {
|
|
258
|
-
var err = "jwt_payload._id or jwt_payload._doc._id can t be undefined" ;
|
|
259
|
-
winston.error(err);
|
|
260
|
-
return done(null, false);
|
|
233
|
+
}
|
|
261
234
|
}
|
|
262
|
-
//JWT OLD format
|
|
263
|
-
const identifier = jwt_payload._id || jwt_payload._doc._id;
|
|
264
|
-
|
|
265
|
-
// const subject = jwt_payload.sub || jwt_payload._id || jwt_payload._doc._id;
|
|
266
|
-
winston.debug("passport identifier: " + identifier);
|
|
267
235
|
|
|
268
|
-
const subject = jwt_payload.sub;
|
|
269
|
-
winston.debug("passport subject: " + subject);
|
|
270
236
|
|
|
271
|
-
winston.debug("passport
|
|
237
|
+
winston.debug("passport opts: ", opts);
|
|
272
238
|
|
|
273
|
-
|
|
274
|
-
|
|
239
|
+
passport.use(new JwtStrategy(opts, async (req, jwt_payload, done) => {
|
|
240
|
+
// passport.use(new JwtStrategy(opts, function(req, jwt_payload, done) {
|
|
241
|
+
winston.debug("jwt_payload", jwt_payload);
|
|
242
|
+
// console.log("req",req);
|
|
275
243
|
|
|
276
|
-
winston.debug("req.disablePassportEntityCheck:"+req.disablePassportEntityCheck);
|
|
277
|
-
|
|
278
|
-
if (req && req.disablePassportEntityCheck) { //req can be null
|
|
279
|
-
// jwt_payload.id = jwt_payload._id; //often req.user.id is used inside code. req.user.id is a mongoose getter of _id
|
|
280
|
-
// is better to rename req.user.id to req.user._id in all files
|
|
281
|
-
winston.debug("req.disablePassportEntityCheck enabled");
|
|
282
|
-
return done(null, jwt_payload);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
//TODO check into DB if JWT is revoked
|
|
286
|
-
if (jwthistory) {
|
|
287
|
-
var jwtRevoked = await jwthistory.isJWTRevoked(jwt_payload.jti);
|
|
288
|
-
winston.debug("passport jwt jwtRevoked: "+ jwtRevoked);
|
|
289
|
-
if (jwtRevoked) {
|
|
290
|
-
winston.warn("passport jwt is revoked with jti: "+ jwt_payload.jti);
|
|
291
|
-
return done(null, false);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
244
|
|
|
295
|
-
|
|
296
|
-
winston.debug("Passport JWT bot");
|
|
245
|
+
// console.log("jwt_payload._doc._id",jwt_payload._doc._id);
|
|
297
246
|
|
|
298
|
-
let qbot = Faq_kb.findOne({_id: identifier}); //TODO add cache_bot_here
|
|
299
247
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
winston.
|
|
303
|
-
qbot.cache(cacheUtil.defaultTTL, id_project+":faq_kbs:id:"+identifier)
|
|
304
|
-
winston.debug('faq_kb cache enabled');
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
qbot.exec(function(err, faq_kb) {
|
|
308
|
-
|
|
309
|
-
if (err) {
|
|
310
|
-
winston.error("Passport JWT bot err", err);
|
|
311
|
-
return done(err, false);
|
|
312
|
-
}
|
|
313
|
-
if (faq_kb) {
|
|
314
|
-
winston.debug("Passport JWT bot user", faq_kb);
|
|
315
|
-
return done(null, faq_kb);
|
|
316
|
-
} else {
|
|
317
|
-
winston.warn("Passport JWT bot not user");
|
|
248
|
+
if (jwt_payload._id == undefined && (jwt_payload._doc == undefined || (jwt_payload._doc && jwt_payload._doc._id == undefined))) {
|
|
249
|
+
var err = "jwt_payload._id or jwt_payload._doc._id can t be undefined";
|
|
250
|
+
winston.error(err);
|
|
318
251
|
return done(null, false);
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
// } else if (subject=="projects") {
|
|
322
|
-
|
|
323
|
-
} else if (subject=="subscription") {
|
|
324
|
-
|
|
325
|
-
Subscription.findOne({_id: identifier}, function(err, subscription) {
|
|
326
|
-
if (err) {
|
|
327
|
-
winston.error("Passport JWT subscription err", err);
|
|
328
|
-
return done(err, false);
|
|
329
|
-
}
|
|
330
|
-
if (subscription) {
|
|
331
|
-
winston.debug("Passport JWT subscription user", subscription);
|
|
332
|
-
return done(null, subscription);
|
|
333
|
-
} else {
|
|
334
|
-
winston.warn("Passport JWT subscription not user", subscription);
|
|
335
|
-
return done(null, false);
|
|
336
252
|
}
|
|
337
|
-
|
|
253
|
+
//JWT OLD format
|
|
254
|
+
const identifier = jwt_payload._id || jwt_payload._doc._id;
|
|
338
255
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
if (jwt_payload) {
|
|
343
|
-
|
|
344
|
-
// const audUrl = new URL(jwt_payload.aud);
|
|
345
|
-
// winston.info("audUrl: "+ audUrl );
|
|
346
|
-
|
|
347
|
-
// const path = audUrl.pathname;
|
|
348
|
-
// winston.info("audUrl path: " + path );
|
|
349
|
-
|
|
350
|
-
// const AudienceType = path.split("/")[1];
|
|
351
|
-
// winston.info("audUrl AudienceType: " + AudienceType );
|
|
256
|
+
// const subject = jwt_payload.sub || jwt_payload._id || jwt_payload._doc._id;
|
|
257
|
+
winston.debug("passport identifier: " + identifier);
|
|
352
258
|
|
|
353
|
-
|
|
354
|
-
|
|
259
|
+
const subject = jwt_payload.sub;
|
|
260
|
+
winston.debug("passport subject: " + subject);
|
|
355
261
|
|
|
356
|
-
|
|
357
|
-
|
|
262
|
+
winston.debug("passport identifier: " + identifier + " subject " + subject);
|
|
358
263
|
|
|
264
|
+
var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
|
|
265
|
+
winston.debug("fullUrl:" + fullUrl);
|
|
359
266
|
|
|
360
|
-
|
|
361
|
-
var userM = UserUtil.decorateUser(jwt_payload);
|
|
362
|
-
winston.debug("Passport JWT userexternal userM", userM);
|
|
267
|
+
winston.debug("req.disablePassportEntityCheck:" + req.disablePassportEntityCheck);
|
|
363
268
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
} else if (subject=="guest") {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
if (jwt_payload) {
|
|
375
|
-
winston.debug("Passport JWT guest", jwt_payload);
|
|
376
|
-
var userM = UserUtil.decorateUser(jwt_payload);
|
|
377
|
-
winston.debug("Passport JWT guest userM", userM);
|
|
378
|
-
return done(null, userM );
|
|
379
|
-
} else {
|
|
380
|
-
var err = {msg: "No jwt_payload passed. Its required"};
|
|
381
|
-
winston.error("Passport JWT guest err", err);
|
|
382
|
-
return done(err, false);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
} else {
|
|
386
|
-
winston.debug("Passport JWT generic user");
|
|
387
|
-
let quser = User.findOne({_id: identifier, status: 100}) //TODO user_cache_here
|
|
388
|
-
//@DISABLED_CACHE .cache(cacheUtil.defaultTTL, "users:id:"+identifier)
|
|
389
|
-
|
|
390
|
-
if (cacheEnabler.user) {
|
|
391
|
-
quser.cache(cacheUtil.defaultTTL, "users:id:"+identifier)
|
|
392
|
-
winston.debug('user cache enabled');
|
|
269
|
+
if (req && req.disablePassportEntityCheck) { //req can be null
|
|
270
|
+
// jwt_payload.id = jwt_payload._id; //often req.user.id is used inside code. req.user.id is a mongoose getter of _id
|
|
271
|
+
// is better to rename req.user.id to req.user._id in all files
|
|
272
|
+
winston.debug("req.disablePassportEntityCheck enabled");
|
|
273
|
+
return done(null, jwt_payload);
|
|
393
274
|
}
|
|
394
275
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
winston.debug("Passport JWT generic not user");
|
|
405
|
-
return done(null, false);
|
|
406
|
-
}
|
|
407
|
-
});
|
|
276
|
+
//TODO check into DB if JWT is revoked
|
|
277
|
+
if (jwthistory) {
|
|
278
|
+
var jwtRevoked = await jwthistory.isJWTRevoked(jwt_payload.jti);
|
|
279
|
+
winston.debug("passport jwt jwtRevoked: " + jwtRevoked);
|
|
280
|
+
if (jwtRevoked) {
|
|
281
|
+
winston.warn("passport jwt is revoked with jti: " + jwt_payload.jti);
|
|
282
|
+
return done(null, false);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
408
285
|
|
|
409
|
-
|
|
410
|
-
|
|
286
|
+
if (subject == "bot") {
|
|
287
|
+
winston.debug("Passport JWT bot");
|
|
411
288
|
|
|
289
|
+
let qbot = Faq_kb.findOne({_id: identifier}); //TODO add cache_bot_here
|
|
412
290
|
|
|
413
|
-
|
|
291
|
+
if (cacheEnabler.faq_kb) {
|
|
292
|
+
let id_project = jwt_payload.id_project;
|
|
293
|
+
winston.debug("jwt_payload.id_project:" + jwt_payload.id_project);
|
|
294
|
+
qbot.cache(cacheUtil.defaultTTL, id_project + ":faq_kbs:id:" + identifier)
|
|
295
|
+
winston.debug('faq_kb cache enabled');
|
|
296
|
+
}
|
|
414
297
|
|
|
298
|
+
qbot.exec(function (err, faq_kb) {
|
|
415
299
|
|
|
300
|
+
if (err) {
|
|
301
|
+
winston.error("Passport JWT bot err", err);
|
|
302
|
+
return done(err, false);
|
|
303
|
+
}
|
|
304
|
+
if (faq_kb) {
|
|
305
|
+
winston.debug("Passport JWT bot user", faq_kb);
|
|
306
|
+
return done(null, faq_kb);
|
|
307
|
+
} else {
|
|
308
|
+
winston.warn("Passport JWT bot not user");
|
|
309
|
+
return done(null, false);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
// } else if (subject=="projects") {
|
|
416
313
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
winston.debug("BasicStrategy: " + userid);
|
|
420
|
-
|
|
314
|
+
} else if (subject == "subscription") {
|
|
421
315
|
|
|
422
|
-
|
|
423
|
-
|
|
316
|
+
Subscription.findOne({_id: identifier}, function (err, subscription) {
|
|
317
|
+
if (err) {
|
|
318
|
+
winston.error("Passport JWT subscription err", err);
|
|
319
|
+
return done(err, false);
|
|
320
|
+
}
|
|
321
|
+
if (subscription) {
|
|
322
|
+
winston.debug("Passport JWT subscription user", subscription);
|
|
323
|
+
return done(null, subscription);
|
|
324
|
+
} else {
|
|
325
|
+
winston.warn("Passport JWT subscription not user", subscription);
|
|
326
|
+
return done(null, false);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
424
329
|
|
|
425
|
-
|
|
426
|
-
//@DISABLED_CACHE .cache(cacheUtil.defaultTTL, "users:email:"+email)
|
|
427
|
-
.exec(function (err, user) {
|
|
428
|
-
|
|
429
|
-
if (err) {
|
|
430
|
-
// console.log("BasicStrategy err.stop");
|
|
431
|
-
return done(err);
|
|
432
|
-
}
|
|
433
|
-
if (!user) { return done(null, false); }
|
|
434
|
-
|
|
435
|
-
user.comparePassword(password, function (err, isMatch) {
|
|
436
|
-
if (isMatch && !err) {
|
|
330
|
+
} else if (subject == "userexternal") {
|
|
437
331
|
|
|
438
|
-
// if user is found and password is right create a token
|
|
439
|
-
// console.log("BasicStrategy ok");
|
|
440
|
-
return done(null, user);
|
|
441
332
|
|
|
442
|
-
|
|
443
|
-
return done(err);
|
|
444
|
-
}
|
|
445
|
-
});
|
|
333
|
+
if (jwt_payload) {
|
|
446
334
|
|
|
447
|
-
|
|
335
|
+
// const audUrl = new URL(jwt_payload.aud);
|
|
336
|
+
// winston.info("audUrl: "+ audUrl );
|
|
448
337
|
|
|
338
|
+
// const path = audUrl.pathname;
|
|
339
|
+
// winston.info("audUrl path: " + path );
|
|
449
340
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
// if (!user.verifyPassword(password)) { return done(null, false); }
|
|
453
|
-
});
|
|
454
|
-
}));
|
|
341
|
+
// const AudienceType = path.split("/")[1];
|
|
342
|
+
// winston.info("audUrl AudienceType: " + AudienceType );
|
|
455
343
|
|
|
344
|
+
// const AudienceId = path.split("/")[2];
|
|
345
|
+
// winston.info("audUrl AudienceId: " + AudienceId );
|
|
456
346
|
|
|
347
|
+
// jwt_payload._id = AudienceId + "-" + jwt_payload._id;
|
|
457
348
|
|
|
458
349
|
|
|
350
|
+
winston.debug("Passport JWT userexternal", jwt_payload);
|
|
351
|
+
var userM = UserUtil.decorateUser(jwt_payload);
|
|
352
|
+
winston.debug("Passport JWT userexternal userM", userM);
|
|
459
353
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
passport.use(new GoogleStrategy({
|
|
468
|
-
clientID: googleClientId,
|
|
469
|
-
clientSecret: googleClientSecret,
|
|
470
|
-
callbackURL: googleCallbackURL, // 'https://www.example.com/oauth2/redirect/google'
|
|
471
|
-
// stateless: true ????
|
|
472
|
-
},
|
|
473
|
-
function(issuer, profile, cb) {
|
|
474
|
-
|
|
475
|
-
winston.debug("issuer: "+issuer)
|
|
476
|
-
winston.debug("profile", profile)
|
|
477
|
-
// winston.info("cb", cb)
|
|
478
|
-
|
|
479
|
-
var email = profile.emails[0].value;
|
|
480
|
-
winston.debug("email: "+email)
|
|
354
|
+
return done(null, userM);
|
|
355
|
+
} else {
|
|
356
|
+
var err = {msg: "No jwt_payload passed. Its required"};
|
|
357
|
+
winston.error("Passport JWT userexternal err", err);
|
|
358
|
+
return done(err, false);
|
|
359
|
+
}
|
|
481
360
|
|
|
482
|
-
|
|
483
|
-
winston.debug("query", query)
|
|
361
|
+
} else if (subject == "guest") {
|
|
484
362
|
|
|
485
|
-
Auth.findOne(query, function(err, cred){
|
|
486
|
-
winston.debug("cred", cred, err)
|
|
487
363
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
364
|
+
if (jwt_payload) {
|
|
365
|
+
winston.debug("Passport JWT guest", jwt_payload);
|
|
366
|
+
var userM = UserUtil.decorateUser(jwt_payload);
|
|
367
|
+
winston.debug("Passport JWT guest userM", userM);
|
|
368
|
+
return done(null, userM);
|
|
369
|
+
} else {
|
|
370
|
+
var err = {msg: "No jwt_payload passed. Its required"};
|
|
371
|
+
winston.error("Passport JWT guest err", err);
|
|
372
|
+
return done(err, false);
|
|
373
|
+
}
|
|
492
374
|
|
|
493
|
-
|
|
375
|
+
} else {
|
|
376
|
+
winston.debug("Passport JWT generic user");
|
|
377
|
+
let quser = User.findOne({_id: identifier, status: 100}) //TODO user_cache_here
|
|
378
|
+
//@DISABLED_CACHE .cache(cacheUtil.defaultTTL, "users:id:"+identifier)
|
|
494
379
|
|
|
380
|
+
if (cacheEnabler.user) {
|
|
381
|
+
quser.cache(cacheUtil.defaultTTL, "users:id:" + identifier)
|
|
382
|
+
winston.debug('user cache enabled');
|
|
383
|
+
}
|
|
495
384
|
|
|
496
|
-
|
|
385
|
+
quser.exec(function (err, user) {
|
|
386
|
+
if (err) {
|
|
387
|
+
winston.error("Passport JWT generic err ", err);
|
|
388
|
+
return done(err, false);
|
|
389
|
+
}
|
|
390
|
+
if (user) {
|
|
391
|
+
winston.debug("Passport JWT generic user ", user);
|
|
392
|
+
return done(null, user);
|
|
393
|
+
} else {
|
|
394
|
+
winston.debug("Passport JWT generic not user");
|
|
395
|
+
return done(null, false);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
497
398
|
|
|
498
|
-
|
|
399
|
+
}
|
|
499
400
|
|
|
500
|
-
if (!cred) {
|
|
501
|
-
winston.debug("13")
|
|
502
|
-
// The Google account has not logged in to this app before. Create a
|
|
503
|
-
// new user record and link it to the Google account.
|
|
504
401
|
|
|
505
|
-
|
|
506
|
-
// profile.displayName
|
|
507
|
-
// ], function(err) {
|
|
402
|
+
}));
|
|
508
403
|
|
|
509
|
-
var password = uniqid()
|
|
510
404
|
|
|
511
|
-
|
|
512
|
-
// signup ( email, password, firstname, lastname, emailverified) {
|
|
513
|
-
userService.signup(email, password, profile.displayName, "", true)
|
|
514
|
-
.then(function (savedUser) {
|
|
405
|
+
passport.use(new BasicStrategy(function (userid, password, done) {
|
|
515
406
|
|
|
407
|
+
winston.debug("BasicStrategy: " + userid);
|
|
516
408
|
|
|
517
|
-
// if (err) { return cb(err); }
|
|
518
409
|
|
|
519
|
-
|
|
410
|
+
var email = userid.toLowerCase();
|
|
411
|
+
winston.debug("email lowercase: " + email);
|
|
520
412
|
|
|
521
|
-
|
|
522
|
-
providerId: issuer,
|
|
413
|
+
User.findOne({
|
|
523
414
|
email: email,
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
});
|
|
549
|
-
}).catch(function(err) {
|
|
550
|
-
// if (err.code == 11000) {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
// } else {
|
|
555
|
-
winston.error("Error signup google ", err);
|
|
556
|
-
return cb(err);
|
|
557
|
-
// }
|
|
558
|
-
|
|
559
|
-
});
|
|
560
|
-
} else {
|
|
561
|
-
|
|
562
|
-
winston.debug("else")
|
|
563
|
-
// The Google account has previously logged in to the app. Get the
|
|
564
|
-
// user record linked to the Google account and log the user in.
|
|
415
|
+
status: 100
|
|
416
|
+
}, 'email firstname lastname password emailverified id') //TODO user_cache_here. NOT used frequently. ma attento select. ATTENTO QUI NN USEREI LA SELECT altrimenti con JWT ho tuttto USER mentre con basich auth solo aluni campi
|
|
417
|
+
//@DISABLED_CACHE .cache(cacheUtil.defaultTTL, "users:email:"+email)
|
|
418
|
+
.exec(function (err, user) {
|
|
419
|
+
|
|
420
|
+
if (err) {
|
|
421
|
+
// console.log("BasicStrategy err.stop");
|
|
422
|
+
return done(err);
|
|
423
|
+
}
|
|
424
|
+
if (!user) {
|
|
425
|
+
return done(null, false);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
user.comparePassword(password, function (err, isMatch) {
|
|
429
|
+
if (isMatch && !err) {
|
|
430
|
+
|
|
431
|
+
// if user is found and password is right create a token
|
|
432
|
+
// console.log("BasicStrategy ok");
|
|
433
|
+
return done(null, user);
|
|
434
|
+
|
|
435
|
+
} else {
|
|
436
|
+
return done(err);
|
|
437
|
+
}
|
|
438
|
+
});
|
|
565
439
|
|
|
566
|
-
User.findOne({
|
|
567
|
-
email: email, status: 100
|
|
568
|
-
}, 'email firstname lastname password emailverified id', function (err, user) {
|
|
569
|
-
|
|
570
|
-
winston.debug("user",user, err);
|
|
571
|
-
// db.get('SELECT * FROM users WHERE id = ?', [ cred.user_id ], function(err, user) {
|
|
572
|
-
if (err) { return cb(err); }
|
|
573
|
-
if (!user) { return cb(null, false); }
|
|
574
|
-
return cb(null, user);
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
));
|
|
580
440
|
|
|
581
|
-
}
|
|
441
|
+
// if (user) { return done(null, user); }
|
|
442
|
+
// if (!user) { return done(null, false); }
|
|
443
|
+
// if (!user.verifyPassword(password)) { return done(null, false); }
|
|
444
|
+
});
|
|
445
|
+
}));
|
|
582
446
|
|
|
583
447
|
|
|
584
|
-
if (
|
|
448
|
+
if (enableGoogleSignin == true) {
|
|
449
|
+
let googleClientId = process.env.GOOGLE_CLIENT_ID;
|
|
450
|
+
let googleClientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
|
451
|
+
let googleCallbackURL = process.env.GOOGLE_CALLBACK_URL || "http://localhost:3000/auth/google/callback";
|
|
585
452
|
|
|
586
|
-
|
|
587
|
-
OAuth2Strategy.prototype.userProfile = function(accessToken, done) {
|
|
453
|
+
winston.info("Enabling Google Signin strategy with ClientId: " + googleClientId + " callbackURL: " + googleCallbackURL + " clientSecret: " + googleClientSecret);
|
|
588
454
|
|
|
589
|
-
|
|
455
|
+
passport.use(new GoogleStrategy({
|
|
456
|
+
clientID: googleClientId,
|
|
457
|
+
clientSecret: googleClientSecret,
|
|
458
|
+
callbackURL: googleCallbackURL,
|
|
459
|
+
},
|
|
460
|
+
async function (issuer, profile, cb) {
|
|
461
|
+
try {
|
|
462
|
+
winston.debug("issuer: " + issuer);
|
|
463
|
+
winston.debug("profile", profile);
|
|
590
464
|
|
|
465
|
+
const rawEmail = profile?.emails?.[0]?.value;
|
|
466
|
+
if (!rawEmail) {
|
|
467
|
+
winston.warn("Google profile has no email", {issuer: issuer, profileId: profile?.id});
|
|
468
|
+
return cb(null, false, {message: "Missing email from Google profile."});
|
|
469
|
+
}
|
|
591
470
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
The service account associated with your client needs to be allowed to view the realm users.
|
|
595
|
-
Go to http://localhost:8080/auth/admin/{realm_name}/console/#/realms/{realm_name}/clients
|
|
596
|
-
Select your client (which must be a confidential client)
|
|
597
|
-
In the settings tab, switch Service Account Enabled to ON
|
|
598
|
-
Click on save, the Service Account Roles tab will appear
|
|
599
|
-
In Client Roles, select realm_management
|
|
600
|
-
Scroll through available roles until you can select view_users
|
|
601
|
-
Click on Add selected
|
|
602
|
-
You should have something like this :
|
|
603
|
-
*/
|
|
471
|
+
const email = rawEmail.toLowerCase().trim();
|
|
472
|
+
winston.debug("email: " + email);
|
|
604
473
|
|
|
474
|
+
const query = {providerId: issuer, subject: profile.id};
|
|
475
|
+
winston.debug("query", query);
|
|
605
476
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
// console.log("this._oauth2", this._oauth2)
|
|
609
|
-
this._oauth2._useAuthorizationHeaderForGET = true;
|
|
610
|
-
this._oauth2.get( process.env.OAUTH2_USER_INFO_URL, accessToken, (err, body) => {
|
|
611
|
-
if (err) {
|
|
612
|
-
return done(err);
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
try {
|
|
616
|
-
winston.debug("body", body);
|
|
617
|
-
|
|
618
|
-
const json = JSON.parse(body);
|
|
619
|
-
const userInfo = {
|
|
620
|
-
keycloakId: json.sub,
|
|
621
|
-
fullName: json.name,
|
|
622
|
-
firstName: json.given_name,
|
|
623
|
-
lastName: json.family_name,
|
|
624
|
-
username: json.preferred_username,
|
|
625
|
-
email: json.email,
|
|
626
|
-
// avatar: json.avatar,
|
|
627
|
-
// realm: this.options.realm,
|
|
628
|
-
};
|
|
629
|
-
winston.debug("userInfo", userInfo);
|
|
477
|
+
const cred = await Auth.findOne(query).exec();
|
|
478
|
+
winston.debug("cred", cred);
|
|
630
479
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
};
|
|
480
|
+
if (cred) {
|
|
481
|
+
// Already linked: return the corresponding user
|
|
482
|
+
const user = await User.findOne({email: email, status: 100})
|
|
483
|
+
.select('email firstname lastname password emailverified id')
|
|
484
|
+
.exec();
|
|
637
485
|
|
|
486
|
+
if (!user) {
|
|
487
|
+
winston.warn("Auth link exists but user not found/active", {email: email, query: query});
|
|
488
|
+
return cb(null, false, {message: "User not found."});
|
|
489
|
+
}
|
|
638
490
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
tokenURL: process.env.OAUTH2_TOKEN_URL,
|
|
642
|
-
clientID: process.env.OAUTH2_CLIENT_ID,
|
|
643
|
-
clientSecret: process.env.OAUTH2_CLIENT_SECRET,
|
|
644
|
-
callbackURL: process.env.OAUTH2_CALLBACK_URL || "http://localhost:3000/auth/oauth2/callback",
|
|
645
|
-
scope: ['openid'],
|
|
646
|
-
},
|
|
647
|
-
function(accessToken, refreshToken, params, profile, cb) {
|
|
648
|
-
winston.debug("params", params);
|
|
491
|
+
return cb(null, user);
|
|
492
|
+
}
|
|
649
493
|
|
|
494
|
+
// Not linked yet: try to reuse existing account by email
|
|
495
|
+
let user = await User.findOne({email: email, status: 100})
|
|
496
|
+
.select('email firstname lastname password emailverified id')
|
|
497
|
+
.exec();
|
|
498
|
+
|
|
499
|
+
if (!user) {
|
|
500
|
+
// No existing user -> create one
|
|
501
|
+
const password = uniqid();
|
|
502
|
+
try {
|
|
503
|
+
user = await userService.signup(email, password, profile.displayName, "", true);
|
|
504
|
+
} catch (err) {
|
|
505
|
+
// Race/duplicate: fall back to existing user
|
|
506
|
+
if (err && (err.code === 11000 || err.code === "E11000")) {
|
|
507
|
+
user = await User.findOne({email: email, status: 100}).exec();
|
|
508
|
+
} else {
|
|
509
|
+
winston.error("Error signup google", err);
|
|
510
|
+
return cb(err);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
}
|
|
650
514
|
|
|
651
|
-
|
|
652
|
-
|
|
515
|
+
if (!user) {
|
|
516
|
+
return cb(null, false, {message: "User not found."});
|
|
517
|
+
}
|
|
653
518
|
|
|
654
|
-
|
|
655
|
-
|
|
519
|
+
// Ensure Auth link is created (idempotent)
|
|
520
|
+
await Auth.findOneAndUpdate(
|
|
521
|
+
query,
|
|
522
|
+
{$setOnInsert: {providerId: issuer, email: email, subject: profile.id}},
|
|
523
|
+
{upsert: true, new: true}
|
|
524
|
+
).exec();
|
|
525
|
+
|
|
526
|
+
return cb(null, user);
|
|
527
|
+
} catch (err) {
|
|
528
|
+
winston.error("Google strategy verify error", err);
|
|
529
|
+
return cb(err);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
));
|
|
656
533
|
|
|
657
|
-
|
|
534
|
+
}
|
|
658
535
|
|
|
659
|
-
winston.debug("accessToken", accessToken);
|
|
660
536
|
|
|
661
|
-
|
|
537
|
+
if (enableOauth2Signin == true) {
|
|
538
|
+
|
|
539
|
+
const OAuth2Strategy = require('passport-oauth2');
|
|
540
|
+
OAuth2Strategy.prototype.userProfile = function (accessToken, done) {
|
|
541
|
+
|
|
542
|
+
winston.debug("accessToken " + accessToken)
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
/*
|
|
546
|
+
https://stackoverflow.com/questions/66452108/keycloak-get-users-returns-403-forbidden
|
|
547
|
+
The service account associated with your client needs to be allowed to view the realm users.
|
|
548
|
+
Go to http://localhost:8080/auth/admin/{realm_name}/console/#/realms/{realm_name}/clients
|
|
549
|
+
Select your client (which must be a confidential client)
|
|
550
|
+
In the settings tab, switch Service Account Enabled to ON
|
|
551
|
+
Click on save, the Service Account Roles tab will appear
|
|
552
|
+
In Client Roles, select realm_management
|
|
553
|
+
Scroll through available roles until you can select view_users
|
|
554
|
+
Click on Add selected
|
|
555
|
+
You should have something like this :
|
|
556
|
+
*/
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
// ATTENTION You have to add a client scope after as described here: https://keycloak.discourse.group/t/issue-on-userinfo-endpoint-at-keycloak-20/18461/4
|
|
560
|
+
|
|
561
|
+
// console.log("this._oauth2", this._oauth2)
|
|
562
|
+
this._oauth2._useAuthorizationHeaderForGET = true;
|
|
563
|
+
this._oauth2.get(process.env.OAUTH2_USER_INFO_URL, accessToken, (err, body) => {
|
|
564
|
+
if (err) {
|
|
565
|
+
return done(err);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
try {
|
|
569
|
+
winston.debug("body", body);
|
|
570
|
+
|
|
571
|
+
const json = JSON.parse(body);
|
|
572
|
+
const userInfo = {
|
|
573
|
+
keycloakId: json.sub,
|
|
574
|
+
fullName: json.name,
|
|
575
|
+
firstName: json.given_name,
|
|
576
|
+
lastName: json.family_name,
|
|
577
|
+
username: json.preferred_username,
|
|
578
|
+
email: json.email,
|
|
579
|
+
// avatar: json.avatar,
|
|
580
|
+
// realm: this.options.realm,
|
|
581
|
+
};
|
|
582
|
+
winston.debug("userInfo", userInfo);
|
|
583
|
+
|
|
584
|
+
done(null, userInfo);
|
|
585
|
+
} catch (e) {
|
|
586
|
+
done(e);
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
};
|
|
662
590
|
|
|
663
|
-
var issuer = token.iss;
|
|
664
|
-
var email = profile.email;
|
|
665
591
|
|
|
666
|
-
|
|
667
|
-
|
|
592
|
+
passport.use(new OAuth2Strategy({
|
|
593
|
+
authorizationURL: process.env.OAUTH2_AUTH_URL,
|
|
594
|
+
tokenURL: process.env.OAUTH2_TOKEN_URL,
|
|
595
|
+
clientID: process.env.OAUTH2_CLIENT_ID,
|
|
596
|
+
clientSecret: process.env.OAUTH2_CLIENT_SECRET,
|
|
597
|
+
callbackURL: process.env.OAUTH2_CALLBACK_URL || "http://localhost:3000/auth/oauth2/callback",
|
|
598
|
+
scope: ['openid'],
|
|
599
|
+
},
|
|
600
|
+
function (accessToken, refreshToken, params, profile, cb) {
|
|
601
|
+
winston.debug("params", params);
|
|
668
602
|
|
|
669
|
-
Auth.findOne(query, function(err, cred){
|
|
670
|
-
winston.debug("cred", cred, err);
|
|
671
|
-
if (err) { return cb(err); }
|
|
672
|
-
if (!cred) {
|
|
673
|
-
// The oauth account has not logged in to this app before. Create a
|
|
674
|
-
// new user record and link it to the oauth account.
|
|
675
|
-
var password = uniqid()
|
|
676
|
-
// signup ( email, password, firstname, lastname, emailverified) {
|
|
677
|
-
userService.signup(email, password, profileInfo.name || profileInfo.preferred_username, "", true)
|
|
678
|
-
.then(function (savedUser) {
|
|
679
603
|
|
|
680
|
-
|
|
604
|
+
const token = jwt.decode(accessToken); // user id lives in here
|
|
605
|
+
winston.debug("token", token);
|
|
681
606
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
email: email,
|
|
685
|
-
subject: profile.keycloakId,
|
|
686
|
-
});
|
|
687
|
-
auth.save(function (err, authSaved) {
|
|
688
|
-
if (err) { return cb(err); }
|
|
689
|
-
winston.debug("authSaved", authSaved);
|
|
690
|
-
|
|
691
|
-
return cb(null, savedUser);
|
|
692
|
-
});
|
|
693
|
-
}).catch(function(err) {
|
|
694
|
-
winston.error("Error signup oauth ", err);
|
|
695
|
-
return cb(err);
|
|
696
|
-
});
|
|
697
|
-
} else {
|
|
698
|
-
// The Oauth account has previously logged in to the app. Get the
|
|
699
|
-
// user record linked to the Oauth account and log the user in.
|
|
607
|
+
const profileInfo = jwt.decode(params.access_token); // user email lives in here
|
|
608
|
+
winston.debug("profileInfo", profileInfo);
|
|
700
609
|
|
|
701
|
-
|
|
702
|
-
email: email, status: 100
|
|
703
|
-
}, 'email firstname lastname emailverified id', function (err, user) {
|
|
610
|
+
winston.debug("profile", profile);
|
|
704
611
|
|
|
705
|
-
|
|
706
|
-
// winston.debug("usertoJSON()",user.toJSON());
|
|
612
|
+
winston.debug("accessToken", accessToken);
|
|
707
613
|
|
|
708
|
-
|
|
709
|
-
winston.error("Error getting user",user, err);
|
|
710
|
-
return cb(err);
|
|
711
|
-
}
|
|
614
|
+
winston.debug("refreshToken", refreshToken);
|
|
712
615
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
return cb(null, false);
|
|
716
|
-
}
|
|
616
|
+
var issuer = token.iss;
|
|
617
|
+
var email = profile.email;
|
|
717
618
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
}
|
|
721
|
-
});
|
|
722
|
-
}
|
|
723
|
-
));
|
|
724
|
-
}
|
|
619
|
+
var query = {providerId: issuer, subject: profile.keycloakId};
|
|
620
|
+
winston.debug("query", query)
|
|
725
621
|
|
|
622
|
+
Auth.findOne(query, function (err, cred) {
|
|
623
|
+
winston.debug("cred", cred, err);
|
|
624
|
+
if (err) {
|
|
625
|
+
return cb(err);
|
|
626
|
+
}
|
|
627
|
+
if (!cred) {
|
|
628
|
+
// The oauth account has not logged in to this app before. Create a
|
|
629
|
+
// new user record and link it to the oauth account.
|
|
630
|
+
var password = uniqid()
|
|
631
|
+
// signup ( email, password, firstname, lastname, emailverified) {
|
|
632
|
+
userService.signup(email, password, profileInfo.name || profileInfo.preferred_username, "", true)
|
|
633
|
+
.then(function (savedUser) {
|
|
634
|
+
|
|
635
|
+
winston.debug("savedUser", savedUser)
|
|
636
|
+
|
|
637
|
+
var auth = new Auth({
|
|
638
|
+
providerId: issuer,
|
|
639
|
+
email: email,
|
|
640
|
+
subject: profile.keycloakId,
|
|
641
|
+
});
|
|
642
|
+
auth.save(function (err, authSaved) {
|
|
643
|
+
if (err) {
|
|
644
|
+
return cb(err);
|
|
645
|
+
}
|
|
646
|
+
winston.debug("authSaved", authSaved);
|
|
647
|
+
|
|
648
|
+
return cb(null, savedUser);
|
|
649
|
+
});
|
|
650
|
+
}).catch(function (err) {
|
|
651
|
+
winston.error("Error signup oauth ", err);
|
|
652
|
+
return cb(err);
|
|
653
|
+
});
|
|
654
|
+
} else {
|
|
655
|
+
// The Oauth account has previously logged in to the app. Get the
|
|
656
|
+
// user record linked to the Oauth account and log the user in.
|
|
657
|
+
|
|
658
|
+
User.findOne({
|
|
659
|
+
email: email, status: 100
|
|
660
|
+
}, 'email firstname lastname emailverified id', function (err, user) {
|
|
661
|
+
|
|
662
|
+
winston.debug("user", user, err);
|
|
663
|
+
// winston.debug("usertoJSON()",user.toJSON());
|
|
664
|
+
|
|
665
|
+
if (err) {
|
|
666
|
+
winston.error("Error getting user", user, err);
|
|
667
|
+
return cb(err);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
if (!user) {
|
|
671
|
+
winston.info("User not found", user, err);
|
|
672
|
+
return cb(null, false);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
return cb(null, user);
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
));
|
|
681
|
+
}
|
|
726
682
|
|
|
727
683
|
|
|
728
684
|
// const KeycloakStrategy = require('@exlinc/keycloak-passport')
|
|
@@ -750,19 +706,19 @@ if (enableOauth2Signin==true) {
|
|
|
750
706
|
|
|
751
707
|
// const token = jwt.decode(accessToken); // user id lives in here
|
|
752
708
|
// console.log("token", token);
|
|
753
|
-
|
|
709
|
+
|
|
754
710
|
// console.log("profile", profile);
|
|
755
|
-
|
|
711
|
+
|
|
756
712
|
// console.log("accessToken", accessToken);
|
|
757
|
-
|
|
713
|
+
|
|
758
714
|
// console.log("refreshToken", refreshToken);
|
|
759
|
-
|
|
715
|
+
|
|
760
716
|
// var issuer = token.iss;
|
|
761
717
|
// var email = profile.email;
|
|
762
|
-
|
|
718
|
+
|
|
763
719
|
// var query = {providerId : issuer, subject: profile.keycloakId};
|
|
764
720
|
// winston.info("query", query)
|
|
765
|
-
|
|
721
|
+
|
|
766
722
|
// Auth.findOne(query, function(err, cred){
|
|
767
723
|
// winston.info("cred", cred, err);
|
|
768
724
|
// if (err) { return cb(err); }
|
|
@@ -773,9 +729,9 @@ if (enableOauth2Signin==true) {
|
|
|
773
729
|
// // signup ( email, password, firstname, lastname, emailverified) {
|
|
774
730
|
// userService.signup(email, password, profile.displayName, "", true)
|
|
775
731
|
// .then(function (savedUser) {
|
|
776
|
-
|
|
732
|
+
|
|
777
733
|
// winston.info("savedUser", savedUser)
|
|
778
|
-
|
|
734
|
+
|
|
779
735
|
// var auth = new Auth({
|
|
780
736
|
// providerId: issuer,
|
|
781
737
|
// email: email,
|
|
@@ -784,7 +740,7 @@ if (enableOauth2Signin==true) {
|
|
|
784
740
|
// auth.save(function (err, authSaved) {
|
|
785
741
|
// if (err) { return cb(err); }
|
|
786
742
|
// winston.info("authSaved", authSaved);
|
|
787
|
-
|
|
743
|
+
|
|
788
744
|
// return cb(null, savedUser);
|
|
789
745
|
// });
|
|
790
746
|
// }).catch(function(err) {
|
|
@@ -794,24 +750,24 @@ if (enableOauth2Signin==true) {
|
|
|
794
750
|
// } else {
|
|
795
751
|
// // The Oauth account has previously logged in to the app. Get the
|
|
796
752
|
// // user record linked to the Oauth account and log the user in.
|
|
797
|
-
|
|
753
|
+
|
|
798
754
|
// User.findOne({
|
|
799
755
|
// email: email, status: 100
|
|
800
756
|
// }, 'email firstname lastname emailverified id', function (err, user) {
|
|
801
|
-
|
|
757
|
+
|
|
802
758
|
// winston.info("user",user, err);
|
|
803
759
|
// winston.info("usertoJSON()",user.toJSON());
|
|
804
|
-
|
|
760
|
+
|
|
805
761
|
// if (err) {
|
|
806
762
|
// winston.error("Error getting user",user, err);
|
|
807
763
|
// return cb(err);
|
|
808
764
|
// }
|
|
809
|
-
|
|
765
|
+
|
|
810
766
|
// if (!user) {
|
|
811
767
|
// winston.info("User not found",user, err);
|
|
812
768
|
// return cb(null, false);
|
|
813
769
|
// }
|
|
814
|
-
|
|
770
|
+
|
|
815
771
|
// return done(null, user);
|
|
816
772
|
// });
|
|
817
773
|
// }
|
|
@@ -820,69 +776,55 @@ if (enableOauth2Signin==true) {
|
|
|
820
776
|
// ));
|
|
821
777
|
|
|
822
778
|
|
|
779
|
+
// var OidcStrategy = require('passport-openidconnect').Strategy;
|
|
823
780
|
|
|
824
781
|
|
|
782
|
+
// https://github.com/jaredhanson/passport-anonymous
|
|
825
783
|
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
// var OidcStrategy = require('passport-openidconnect').Strategy;
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
// https://github.com/jaredhanson/passport-anonymous
|
|
833
|
-
|
|
834
|
-
// passport.use(new AnonymousStrategy());
|
|
835
|
-
|
|
784
|
+
// passport.use(new AnonymousStrategy());
|
|
836
785
|
|
|
837
786
|
|
|
838
787
|
// link utili
|
|
839
788
|
// https://codeburst.io/how-to-implement-openid-authentication-with-openid-client-and-passport-in-node-js-43d020121e87?gi=4bb439e255a7
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
789
|
+
// https://developer.wordpress.com/docs/oauth2/
|
|
843
790
|
|
|
844
|
-
// openidconnect
|
|
845
|
-
// https://docs.simplelogin.io/docs/passport/
|
|
846
791
|
|
|
792
|
+
// openidconnect
|
|
793
|
+
// https://docs.simplelogin.io/docs/passport/
|
|
847
794
|
|
|
848
795
|
|
|
796
|
+
// oauth2
|
|
797
|
+
/**
|
|
798
|
+
* BasicStrategy & ClientPasswordStrategy
|
|
799
|
+
*
|
|
800
|
+
* These strategies are used to authenticate registered OAuth clients. They are
|
|
801
|
+
* employed to protect the `token` endpoint, which consumers use to obtain
|
|
802
|
+
* access tokens. The OAuth 2.0 specification suggests that clients use the
|
|
803
|
+
* HTTP Basic scheme to authenticate. Use of the client password strategy
|
|
804
|
+
* allows clients to send the same credentials in the request body (as opposed
|
|
805
|
+
* to the `Authorization` header). While this approach is not recommended by
|
|
806
|
+
* the specification, in practice it is quite common.
|
|
807
|
+
*/
|
|
849
808
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
/**
|
|
853
|
-
* BasicStrategy & ClientPasswordStrategy
|
|
854
|
-
*
|
|
855
|
-
* These strategies are used to authenticate registered OAuth clients. They are
|
|
856
|
-
* employed to protect the `token` endpoint, which consumers use to obtain
|
|
857
|
-
* access tokens. The OAuth 2.0 specification suggests that clients use the
|
|
858
|
-
* HTTP Basic scheme to authenticate. Use of the client password strategy
|
|
859
|
-
* allows clients to send the same credentials in the request body (as opposed
|
|
860
|
-
* to the `Authorization` header). While this approach is not recommended by
|
|
861
|
-
* the specification, in practice it is quite common.
|
|
862
|
-
*/
|
|
863
|
-
|
|
864
|
-
/*
|
|
865
|
-
const ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy;
|
|
866
|
-
|
|
867
|
-
function verifyClient(clientId, clientSecret, done) {
|
|
809
|
+
/*
|
|
810
|
+
const ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy;
|
|
868
811
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
passport.use(new
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
812
|
+
function verifyClient(clientId, clientSecret, done) {
|
|
813
|
+
|
|
814
|
+
db.clients.findByClientId(clientId, (error, client) => {
|
|
815
|
+
if (error) return done(error);
|
|
816
|
+
if (!client) return done(null, false);
|
|
817
|
+
if (client.clientSecret !== clientSecret) return done(null, false);
|
|
818
|
+
return done(null, client);
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
//passport.use(new BasicStrategy(verifyClient));
|
|
823
|
+
|
|
824
|
+
passport.use(new ClientPasswordStrategy(verifyClient));
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
*/
|
|
886
828
|
|
|
887
829
|
|
|
888
830
|
};
|