oidc_server.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. Oidc = {};
  2. OAuth.registerService('oidc', 2, null, function (query) {
  3. var debug = process.env.DEBUG || false;
  4. var token = getToken(query);
  5. if (debug) console.log('XXX: register token:', token);
  6. var accessToken = token.access_token || token.id_token;
  7. var expiresAt = (+new Date) + (1000 * parseInt(token.expires_in, 10));
  8. var userinfo = getUserInfo(accessToken);
  9. if (debug) console.log('XXX: userinfo:', userinfo);
  10. var serviceData = {};
  11. serviceData.id = userinfo[process.env.OAUTH2_ID_MAP] || userinfo[id];
  12. serviceData.username = userinfo[process.env.OAUTH2_USERNAME_MAP] || userinfo[uid];
  13. serviceData.fullname = userinfo[process.env.OAUTH2_FULLNAME_MAP] || userinfo[displayName];
  14. serviceData.accessToken = accessToken;
  15. serviceData.expiresAt = expiresAt;
  16. serviceData.email = userinfo[process.env.OAUTH2_EMAIL_MAP] || userinfo[email];
  17. if (accessToken) {
  18. var tokenContent = getTokenContent(accessToken);
  19. var fields = _.pick(tokenContent, getConfiguration().idTokenWhitelistFields);
  20. _.extend(serviceData, fields);
  21. }
  22. if (token.refresh_token)
  23. serviceData.refreshToken = token.refresh_token;
  24. if (debug) console.log('XXX: serviceData:', serviceData);
  25. var profile = {};
  26. profile.name = userinfo[process.env.OAUTH2_FULLNAME_MAP] || userinfo[displayName];
  27. profile.email = userinfo[process.env.OAUTH2_EMAIL_MAP] || userinfo[email];
  28. if (debug) console.log('XXX: profile:', profile);
  29. return {
  30. serviceData: serviceData,
  31. options: { profile: profile }
  32. };
  33. });
  34. var userAgent = "Meteor";
  35. if (Meteor.release) {
  36. userAgent += "/" + Meteor.release;
  37. }
  38. var getToken = function (query) {
  39. var debug = process.env.DEBUG || false;
  40. var config = getConfiguration();
  41. var serverTokenEndpoint = config.serverUrl + config.tokenEndpoint;
  42. var response;
  43. try {
  44. response = HTTP.post(
  45. serverTokenEndpoint,
  46. {
  47. headers: {
  48. Accept: 'application/json',
  49. "User-Agent": userAgent
  50. },
  51. params: {
  52. code: query.code,
  53. client_id: config.clientId,
  54. client_secret: OAuth.openSecret(config.secret),
  55. redirect_uri: OAuth._redirectUri('oidc', config),
  56. grant_type: 'authorization_code',
  57. state: query.state
  58. }
  59. }
  60. );
  61. } catch (err) {
  62. throw _.extend(new Error("Failed to get token from OIDC " + serverTokenEndpoint + ": " + err.message),
  63. { response: err.response });
  64. }
  65. if (response.data.error) {
  66. // if the http response was a json object with an error attribute
  67. throw new Error("Failed to complete handshake with OIDC " + serverTokenEndpoint + ": " + response.data.error);
  68. } else {
  69. if (debug) console.log('XXX: getToken response: ', response.data);
  70. return response.data;
  71. }
  72. };
  73. var getUserInfo = function (accessToken) {
  74. var debug = process.env.DEBUG || false;
  75. var config = getConfiguration();
  76. // Some userinfo endpoints use a different base URL than the authorization or token endpoints.
  77. // This logic allows the end user to override the setting by providing the full URL to userinfo in their config.
  78. if (config.userinfoEndpoint.includes("https://")) {
  79. var serverUserinfoEndpoint = config.userinfoEndpoint;
  80. } else {
  81. var serverUserinfoEndpoint = config.serverUrl + config.userinfoEndpoint;
  82. }
  83. var response;
  84. try {
  85. response = HTTP.get(
  86. serverUserinfoEndpoint,
  87. {
  88. headers: {
  89. "User-Agent": userAgent,
  90. "Authorization": "Bearer " + accessToken
  91. }
  92. }
  93. );
  94. } catch (err) {
  95. throw _.extend(new Error("Failed to fetch userinfo from OIDC " + serverUserinfoEndpoint + ": " + err.message),
  96. {response: err.response});
  97. }
  98. if (debug) console.log('XXX: getUserInfo response: ', response.data);
  99. return response.data;
  100. };
  101. var getConfiguration = function () {
  102. var config = ServiceConfiguration.configurations.findOne({ service: 'oidc' });
  103. if (!config) {
  104. throw new ServiceConfiguration.ConfigError('Service oidc not configured.');
  105. }
  106. return config;
  107. };
  108. var getTokenContent = function (token) {
  109. var content = null;
  110. if (token) {
  111. try {
  112. var parts = token.split('.');
  113. var header = JSON.parse(new Buffer(parts[0], 'base64').toString());
  114. content = JSON.parse(new Buffer(parts[1], 'base64').toString());
  115. var signature = new Buffer(parts[2], 'base64');
  116. var signed = parts[0] + '.' + parts[1];
  117. } catch (err) {
  118. this.content = {
  119. exp: 0
  120. };
  121. }
  122. }
  123. return content;
  124. }
  125. Oidc.retrieveCredential = function (credentialToken, credentialSecret) {
  126. return OAuth.retrieveCredential(credentialToken, credentialSecret);
  127. };