You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
4.1 KiB

  1. 'use strict'
  2. /* global wiki */
  3. const Promise = require('bluebird')
  4. const express = require('express')
  5. const router = express.Router()
  6. const passport = require('passport')
  7. const ExpressBrute = require('express-brute')
  8. const ExpressBruteRedisStore = require('express-brute-redis')
  9. const moment = require('moment')
  10. /**
  11. * Setup Express-Brute
  12. */
  13. const EBstore = new ExpressBruteRedisStore({
  14. client: wiki.redis
  15. })
  16. const bruteforce = new ExpressBrute(EBstore, {
  17. freeRetries: 5,
  18. minWait: 60 * 1000,
  19. maxWait: 5 * 60 * 1000,
  20. refreshTimeoutOnRequest: false,
  21. failCallback (req, res, next, nextValidRequestDate) {
  22. req.flash('alert', {
  23. class: 'error',
  24. title: wiki.lang.t('auth:errors.toomanyattempts'),
  25. message: wiki.lang.t('auth:errors.toomanyattemptsmsg', { time: moment(nextValidRequestDate).fromNow() }),
  26. iconClass: 'fa-times'
  27. })
  28. res.redirect('/login')
  29. }
  30. })
  31. /**
  32. * Login form
  33. */
  34. router.get('/login', function (req, res, next) {
  35. res.render('auth/login', {
  36. authStrategies: wiki.auth.strategies,
  37. hasMultipleStrategies: Object.keys(wiki.config.auth.strategies).length > 0
  38. })
  39. })
  40. router.post('/login', bruteforce.prevent, function (req, res, next) {
  41. new Promise((resolve, reject) => {
  42. // [1] LOCAL AUTHENTICATION
  43. passport.authenticate('local', function (err, user, info) {
  44. if (err) { return reject(err) }
  45. if (!user) { return reject(new Error('INVALID_LOGIN')) }
  46. resolve(user)
  47. })(req, res, next)
  48. }).catch({ message: 'INVALID_LOGIN' }, err => {
  49. if (appconfig.auth.ldap && appconfig.auth.ldap.enabled) {
  50. // [2] LDAP AUTHENTICATION
  51. return new Promise((resolve, reject) => {
  52. passport.authenticate('ldapauth', function (err, user, info) {
  53. if (err) { return reject(err) }
  54. if (info && info.message) { return reject(new Error(info.message)) }
  55. if (!user) { return reject(new Error('INVALID_LOGIN')) }
  56. resolve(user)
  57. })(req, res, next)
  58. })
  59. } else {
  60. throw err
  61. }
  62. }).then((user) => {
  63. // LOGIN SUCCESS
  64. return req.logIn(user, function (err) {
  65. if (err) { return next(err) }
  66. req.brute.reset(function () {
  67. return res.redirect('/')
  68. })
  69. }) || true
  70. }).catch(err => {
  71. // LOGIN FAIL
  72. if (err.message === 'INVALID_LOGIN') {
  73. req.flash('alert', {
  74. title: wiki.lang.t('auth:errors.invalidlogin'),
  75. message: wiki.lang.t('auth:errors.invalidloginmsg')
  76. })
  77. return res.redirect('/login')
  78. } else {
  79. req.flash('alert', {
  80. title: wiki.lang.t('auth:errors.loginerror'),
  81. message: err.message
  82. })
  83. return res.redirect('/login')
  84. }
  85. })
  86. })
  87. /**
  88. * Social Login
  89. */
  90. router.get('/login/ms', passport.authenticate('windowslive', { scope: ['wl.signin', 'wl.basic', 'wl.emails'] }))
  91. router.get('/login/google', passport.authenticate('google', { scope: ['profile', 'email'] }))
  92. router.get('/login/facebook', passport.authenticate('facebook', { scope: ['public_profile', 'email'] }))
  93. router.get('/login/github', passport.authenticate('github', { scope: ['user:email'] }))
  94. router.get('/login/slack', passport.authenticate('slack', { scope: ['identity.basic', 'identity.email'] }))
  95. router.get('/login/azure', passport.authenticate('azure_ad_oauth2'))
  96. router.get('/login/ms/callback', passport.authenticate('windowslive', { failureRedirect: '/login', successRedirect: '/' }))
  97. router.get('/login/google/callback', passport.authenticate('google', { failureRedirect: '/login', successRedirect: '/' }))
  98. router.get('/login/facebook/callback', passport.authenticate('facebook', { failureRedirect: '/login', successRedirect: '/' }))
  99. router.get('/login/github/callback', passport.authenticate('github', { failureRedirect: '/login', successRedirect: '/' }))
  100. router.get('/login/slack/callback', passport.authenticate('slack', { failureRedirect: '/login', successRedirect: '/' }))
  101. router.get('/login/azure/callback', passport.authenticate('azure_ad_oauth2', { failureRedirect: '/login', successRedirect: '/' }))
  102. /**
  103. * Logout
  104. */
  105. router.get('/logout', function (req, res) {
  106. req.logout()
  107. res.redirect('/')
  108. })
  109. module.exports = router