login-passport.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. module.exports = function(crowi, app) {
  2. 'use strict';
  3. var debug = require('debug')('crowi:routes:login-passport')
  4. , passport = require('passport')
  5. , config = crowi.getConfig()
  6. , Config = crowi.model('Config')
  7. , ExternalAccount = crowi.model('ExternalAccount')
  8. , passportService = crowi.passportService
  9. ;
  10. /**
  11. * success handler
  12. * @param {*} req
  13. * @param {*} res
  14. */
  15. const loginSuccess = (req, res, user) => {
  16. // update lastLoginAt
  17. user.updateLastLoginAt(new Date(), (err, userData) => {
  18. if (err) {
  19. console.log(`updateLastLoginAt dumps error: ${err}`);
  20. debug(`updateLastLoginAt dumps error: ${err}`);
  21. }
  22. });
  23. var jumpTo = req.session.jumpTo;
  24. if (jumpTo) {
  25. req.session.jumpTo = null;
  26. return res.redirect(jumpTo);
  27. } else {
  28. return res.redirect('/');
  29. }
  30. };
  31. /**
  32. * failure handler
  33. * @param {*} req
  34. * @param {*} res
  35. */
  36. const loginFailure = (req, res, next) => {
  37. req.flash('errorMessage', 'Sign in failure.');
  38. return res.redirect('/login');
  39. };
  40. /**
  41. * return true(valid) or false(invalid)
  42. *
  43. * true ... group filter is not defined or the user has one or more groups
  44. * false ... group filter is defined and the user has any group
  45. *
  46. */
  47. function isValidLdapUserByGroupFilter(user) {
  48. let bool = true;
  49. if (user._groups != null) {
  50. if (user._groups.length == 0) {
  51. bool = false;
  52. }
  53. }
  54. return bool;
  55. }
  56. /**
  57. * middleware that login with LdapStrategy
  58. * @param {*} req
  59. * @param {*} res
  60. * @param {*} next
  61. */
  62. const loginWithLdap = (req, res, next) => {
  63. if (!passportService.isLdapStrategySetup) {
  64. debug('LdapStrategy has not been set up');
  65. return next();
  66. }
  67. const loginForm = req.body.loginForm;
  68. if (!req.form.isValid) {
  69. debug("invalid form");
  70. return res.render('login', {
  71. });
  72. }
  73. passport.authenticate('ldapauth', (err, ldapAccountInfo, info) => {
  74. if (res.headersSent) { // dirty hack -- 2017.09.25
  75. return; // cz: somehow passport.authenticate called twice when ECONNREFUSED error occurred
  76. }
  77. debug('--- authenticate with LdapStrategy ---');
  78. debug('ldapAccountInfo', ldapAccountInfo);
  79. debug('info', info);
  80. if (err) { // DB Error
  81. console.log('LDAP Server Error: ', err);
  82. req.flash('warningMessage', 'LDAP Server Error occured.');
  83. return next(); // pass and the flash message is displayed when all of authentications are failed.
  84. }
  85. // authentication failure
  86. if (!ldapAccountInfo) { return next(); }
  87. // check groups
  88. if (!isValidLdapUserByGroupFilter(ldapAccountInfo)) {
  89. return loginFailure(req, res, next);
  90. }
  91. /*
  92. * authentication success
  93. */
  94. // it is guaranteed that username that is input from form can be acquired
  95. // because this processes after authentication
  96. const ldapAccountId = passportService.getLdapAccountIdFromReq(req);
  97. const attrMapUsername = passportService.getLdapAttrNameMappedToUsername();
  98. const usernameToBeRegistered = ldapAccountInfo[attrMapUsername];
  99. // find or register(create) user
  100. ExternalAccount.findOrRegister('ldap', ldapAccountId, usernameToBeRegistered)
  101. .catch((err) => {
  102. if (err.name === 'DuplicatedUsernameException') {
  103. // get option
  104. const isSameUsernameTreatedAsIdenticalUser = Config.isSameUsernameTreatedAsIdenticalUser(config, 'ldap');
  105. if (isSameUsernameTreatedAsIdenticalUser) {
  106. // associate to existing user
  107. debug(`ExternalAccount '${ldapAccountId}' will be created and bound to the exisiting User account`);
  108. return ExternalAccount.associate('ldap', ldapAccountId, err.user);
  109. }
  110. }
  111. throw err; // throw again
  112. })
  113. .then((externalAccount) => {
  114. return externalAccount.getPopulatedUser();
  115. })
  116. .then((user) => {
  117. // login
  118. req.logIn(user, (err) => {
  119. if (err) { return next(); }
  120. else {
  121. return loginSuccess(req, res, user);
  122. }
  123. });
  124. })
  125. .catch((err) => {
  126. if (err.name === 'DuplicatedUsernameException') {
  127. req.flash('isDuplicatedUsernameExceptionOccured', true);
  128. return next();
  129. }
  130. else {
  131. return next(err);
  132. }
  133. });
  134. })(req, res, next);
  135. }
  136. /**
  137. * middleware that test credentials with LdapStrategy
  138. *
  139. * @param {*} req
  140. * @param {*} res
  141. */
  142. const testLdapCredentials = (req, res) => {
  143. if (!passportService.isLdapStrategySetup) {
  144. debug('LdapStrategy has not been set up');
  145. return res.json({
  146. status: 'warning',
  147. message: 'LdapStrategy has not been set up',
  148. });
  149. }
  150. const loginForm = req.body.loginForm;
  151. passport.authenticate('ldapauth', (err, user, info) => {
  152. if (res.headersSent) { // dirty hack -- 2017.09.25
  153. return; // cz: somehow passport.authenticate called twice when ECONNREFUSED error occurred
  154. }
  155. if (err) { // DB Error
  156. console.log('LDAP Server Error: ', err);
  157. return res.json({
  158. status: 'warning',
  159. message: 'LDAP Server Error occured.',
  160. });
  161. }
  162. if (info && info.message) {
  163. return res.json({
  164. status: 'warning',
  165. message: info.message,
  166. });
  167. }
  168. if (user) {
  169. // check groups
  170. if (!isValidLdapUserByGroupFilter(user)) {
  171. return res.json({
  172. status: 'warning',
  173. message: 'The user is found, but that has no groups.',
  174. });
  175. }
  176. return res.json({
  177. status: 'success',
  178. message: 'Successfully authenticated.',
  179. });
  180. }
  181. })(req, res, () => {});
  182. }
  183. /**
  184. * middleware that login with LocalStrategy
  185. * @param {*} req
  186. * @param {*} res
  187. * @param {*} next
  188. */
  189. const loginWithLocal = (req, res, next) => {
  190. const loginForm = req.body.loginForm;
  191. if (!req.form.isValid) {
  192. return res.render('login', {
  193. });
  194. }
  195. passport.authenticate('local', (err, user, info) => {
  196. debug('--- authenticate with LocalStrategy ---');
  197. debug('user', user);
  198. debug('info', info);
  199. if (err) { // DB Error
  200. console.log('Database Server Error: ', err);
  201. req.flash('warningMessage', 'Database Server Error occured.');
  202. return next(); // pass and the flash message is displayed when all of authentications are failed.
  203. }
  204. if (!user) { return next(); }
  205. req.logIn(user, (err) => {
  206. if (err) { return next(); }
  207. else {
  208. return loginSuccess(req, res, user);
  209. }
  210. });
  211. })(req, res, next);
  212. }
  213. return {
  214. loginFailure,
  215. loginWithLdap,
  216. testLdapCredentials,
  217. loginWithLocal,
  218. };
  219. };