2019-04-20 15:18:33 +03:00
|
|
|
Oidc = {};
|
|
|
|
|
|
|
|
OAuth.registerService('oidc', 2, null, function (query) {
|
|
|
|
|
|
|
|
var debug = process.env.DEBUG || false;
|
|
|
|
var token = getToken(query);
|
|
|
|
if (debug) console.log('XXX: register token:', token);
|
|
|
|
|
|
|
|
var accessToken = token.access_token || token.id_token;
|
|
|
|
var expiresAt = (+new Date) + (1000 * parseInt(token.expires_in, 10));
|
|
|
|
|
|
|
|
var userinfo = getUserInfo(accessToken);
|
|
|
|
if (debug) console.log('XXX: userinfo:', userinfo);
|
|
|
|
|
|
|
|
var serviceData = {};
|
fix(oidc): can not log in
Trying to configure wekan authenticating against LemonLDAP-NG, I used to read about errors like the following:
```
XXX: getUserInfo response: { sub: 'demoone' }
XXX: userinfo: { sub: 'demoone' }
{"line":"431","file":"oauth.js","message":"Error in OAuth Server: id is not defined","time":{"$date":1556286530412},"level":"warn"}
Exception while invoking method 'login' { stack: 'ReferenceError: id is not defined\n at Object.handleOauthRequest (packages/wekan-oidc.js:39:68)\n at OAuth._requestHandlers.(anonymous function) (packages/oauth2.js:27:31)\n at middleware (packages/oauth.js:203:5)\n at packages/oauth.js:176:5',
source: 'method' }
```
Looking at the sources, that error message seems to be right: we have several references to `id`, `uid`, `displayName` or `email`, which are not defined. Probably a typo, assuming we meant these to be strings.
Applying that patch, I confirm I can finally log in:
```
XXX: getUserInfo response: { sub: 'demoone' }
XXX: userinfo: { sub: 'demoone' }
XXX: serviceData: { id: undefined,
username: undefined,
fullname: undefined,
accessToken: 'e57dc4e9e81cc98c279db3ed08b1c72f',
expiresAt: 1556298699213,
email: undefined }
XXX: profile: { name: undefined, email: undefined }
```
All the credit goes to @pcurie .
2019-04-26 18:21:42 +02:00
|
|
|
serviceData.id = userinfo[process.env.OAUTH2_ID_MAP] || userinfo["id"];
|
|
|
|
serviceData.username = userinfo[process.env.OAUTH2_USERNAME_MAP] || userinfo["uid"];
|
|
|
|
serviceData.fullname = userinfo[process.env.OAUTH2_FULLNAME_MAP] || userinfo["displayName"];
|
2019-04-20 15:18:33 +03:00
|
|
|
serviceData.accessToken = accessToken;
|
|
|
|
serviceData.expiresAt = expiresAt;
|
fix(oidc): can not log in
Trying to configure wekan authenticating against LemonLDAP-NG, I used to read about errors like the following:
```
XXX: getUserInfo response: { sub: 'demoone' }
XXX: userinfo: { sub: 'demoone' }
{"line":"431","file":"oauth.js","message":"Error in OAuth Server: id is not defined","time":{"$date":1556286530412},"level":"warn"}
Exception while invoking method 'login' { stack: 'ReferenceError: id is not defined\n at Object.handleOauthRequest (packages/wekan-oidc.js:39:68)\n at OAuth._requestHandlers.(anonymous function) (packages/oauth2.js:27:31)\n at middleware (packages/oauth.js:203:5)\n at packages/oauth.js:176:5',
source: 'method' }
```
Looking at the sources, that error message seems to be right: we have several references to `id`, `uid`, `displayName` or `email`, which are not defined. Probably a typo, assuming we meant these to be strings.
Applying that patch, I confirm I can finally log in:
```
XXX: getUserInfo response: { sub: 'demoone' }
XXX: userinfo: { sub: 'demoone' }
XXX: serviceData: { id: undefined,
username: undefined,
fullname: undefined,
accessToken: 'e57dc4e9e81cc98c279db3ed08b1c72f',
expiresAt: 1556298699213,
email: undefined }
XXX: profile: { name: undefined, email: undefined }
```
All the credit goes to @pcurie .
2019-04-26 18:21:42 +02:00
|
|
|
serviceData.email = userinfo[process.env.OAUTH2_EMAIL_MAP] || userinfo["email"];
|
2019-04-20 15:18:33 +03:00
|
|
|
|
|
|
|
if (accessToken) {
|
|
|
|
var tokenContent = getTokenContent(accessToken);
|
|
|
|
var fields = _.pick(tokenContent, getConfiguration().idTokenWhitelistFields);
|
|
|
|
_.extend(serviceData, fields);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (token.refresh_token)
|
|
|
|
serviceData.refreshToken = token.refresh_token;
|
|
|
|
if (debug) console.log('XXX: serviceData:', serviceData);
|
|
|
|
|
|
|
|
var profile = {};
|
fix(oidc): can not log in
Trying to configure wekan authenticating against LemonLDAP-NG, I used to read about errors like the following:
```
XXX: getUserInfo response: { sub: 'demoone' }
XXX: userinfo: { sub: 'demoone' }
{"line":"431","file":"oauth.js","message":"Error in OAuth Server: id is not defined","time":{"$date":1556286530412},"level":"warn"}
Exception while invoking method 'login' { stack: 'ReferenceError: id is not defined\n at Object.handleOauthRequest (packages/wekan-oidc.js:39:68)\n at OAuth._requestHandlers.(anonymous function) (packages/oauth2.js:27:31)\n at middleware (packages/oauth.js:203:5)\n at packages/oauth.js:176:5',
source: 'method' }
```
Looking at the sources, that error message seems to be right: we have several references to `id`, `uid`, `displayName` or `email`, which are not defined. Probably a typo, assuming we meant these to be strings.
Applying that patch, I confirm I can finally log in:
```
XXX: getUserInfo response: { sub: 'demoone' }
XXX: userinfo: { sub: 'demoone' }
XXX: serviceData: { id: undefined,
username: undefined,
fullname: undefined,
accessToken: 'e57dc4e9e81cc98c279db3ed08b1c72f',
expiresAt: 1556298699213,
email: undefined }
XXX: profile: { name: undefined, email: undefined }
```
All the credit goes to @pcurie .
2019-04-26 18:21:42 +02:00
|
|
|
profile.name = userinfo[process.env.OAUTH2_FULLNAME_MAP] || userinfo["displayName"];
|
|
|
|
profile.email = userinfo[process.env.OAUTH2_EMAIL_MAP] || userinfo["email"];
|
2019-04-20 15:18:33 +03:00
|
|
|
if (debug) console.log('XXX: profile:', profile);
|
|
|
|
|
|
|
|
return {
|
|
|
|
serviceData: serviceData,
|
|
|
|
options: { profile: profile }
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
var userAgent = "Meteor";
|
|
|
|
if (Meteor.release) {
|
|
|
|
userAgent += "/" + Meteor.release;
|
|
|
|
}
|
|
|
|
|
|
|
|
var getToken = function (query) {
|
|
|
|
var debug = process.env.DEBUG || false;
|
|
|
|
var config = getConfiguration();
|
2019-06-06 11:08:27 +02:00
|
|
|
if(config.tokenEndpoint.includes('https://')){
|
|
|
|
var serverTokenEndpoint = config.tokenEndpoint;
|
|
|
|
}else{
|
|
|
|
var serverTokenEndpoint = config.serverUrl + config.tokenEndpoint;
|
|
|
|
}
|
|
|
|
var requestPermissions = config.requestPermissions;
|
2019-04-20 15:18:33 +03:00
|
|
|
var response;
|
|
|
|
|
|
|
|
try {
|
|
|
|
response = HTTP.post(
|
|
|
|
serverTokenEndpoint,
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
Accept: 'application/json',
|
|
|
|
"User-Agent": userAgent
|
|
|
|
},
|
|
|
|
params: {
|
|
|
|
code: query.code,
|
|
|
|
client_id: config.clientId,
|
|
|
|
client_secret: OAuth.openSecret(config.secret),
|
|
|
|
redirect_uri: OAuth._redirectUri('oidc', config),
|
|
|
|
grant_type: 'authorization_code',
|
2019-06-06 11:08:27 +02:00
|
|
|
scope: requestPermissions,
|
2019-04-20 15:18:33 +03:00
|
|
|
state: query.state
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
} catch (err) {
|
|
|
|
throw _.extend(new Error("Failed to get token from OIDC " + serverTokenEndpoint + ": " + err.message),
|
|
|
|
{ response: err.response });
|
|
|
|
}
|
|
|
|
if (response.data.error) {
|
|
|
|
// if the http response was a json object with an error attribute
|
|
|
|
throw new Error("Failed to complete handshake with OIDC " + serverTokenEndpoint + ": " + response.data.error);
|
|
|
|
} else {
|
|
|
|
if (debug) console.log('XXX: getToken response: ', response.data);
|
|
|
|
return response.data;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
var getUserInfo = function (accessToken) {
|
|
|
|
var debug = process.env.DEBUG || false;
|
|
|
|
var config = getConfiguration();
|
|
|
|
// Some userinfo endpoints use a different base URL than the authorization or token endpoints.
|
|
|
|
// This logic allows the end user to override the setting by providing the full URL to userinfo in their config.
|
|
|
|
if (config.userinfoEndpoint.includes("https://")) {
|
|
|
|
var serverUserinfoEndpoint = config.userinfoEndpoint;
|
|
|
|
} else {
|
|
|
|
var serverUserinfoEndpoint = config.serverUrl + config.userinfoEndpoint;
|
|
|
|
}
|
|
|
|
var response;
|
|
|
|
try {
|
|
|
|
response = HTTP.get(
|
|
|
|
serverUserinfoEndpoint,
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
"User-Agent": userAgent,
|
|
|
|
"Authorization": "Bearer " + accessToken
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
} catch (err) {
|
|
|
|
throw _.extend(new Error("Failed to fetch userinfo from OIDC " + serverUserinfoEndpoint + ": " + err.message),
|
|
|
|
{response: err.response});
|
|
|
|
}
|
|
|
|
if (debug) console.log('XXX: getUserInfo response: ', response.data);
|
|
|
|
return response.data;
|
|
|
|
};
|
|
|
|
|
|
|
|
var getConfiguration = function () {
|
|
|
|
var config = ServiceConfiguration.configurations.findOne({ service: 'oidc' });
|
|
|
|
if (!config) {
|
|
|
|
throw new ServiceConfiguration.ConfigError('Service oidc not configured.');
|
|
|
|
}
|
|
|
|
return config;
|
|
|
|
};
|
|
|
|
|
|
|
|
var getTokenContent = function (token) {
|
|
|
|
var content = null;
|
|
|
|
if (token) {
|
|
|
|
try {
|
|
|
|
var parts = token.split('.');
|
|
|
|
var header = JSON.parse(new Buffer(parts[0], 'base64').toString());
|
|
|
|
content = JSON.parse(new Buffer(parts[1], 'base64').toString());
|
|
|
|
var signature = new Buffer(parts[2], 'base64');
|
|
|
|
var signed = parts[0] + '.' + parts[1];
|
|
|
|
} catch (err) {
|
|
|
|
this.content = {
|
|
|
|
exp: 0
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return content;
|
|
|
|
}
|
|
|
|
|
|
|
|
Oidc.retrieveCredential = function (credentialToken, credentialSecret) {
|
|
|
|
return OAuth.retrieveCredential(credentialToken, credentialSecret);
|
|
|
|
};
|