还有另一个承诺问题-嵌套的Sequelize调用?

问题描述 投票:0回答:1

我已经阅读了许多关于Promises的文章,并且在大多数情况下,我已经获得了它们,并且已经使用了两年了。但是我有一个案例,我一直在挣扎,并且在我的所有阅读中都没有找到完全匹配的项目-除非我没有认出该匹配项目。我的情况是这样的:

我同时拥有客户端和服务器应用程序。服务器应用是客户端的API。用户发出登录请求,并成功调用Active Directory(在该目录中找到该用户)后,将进行Sequelize'Users.findOne'调用,并将用户数据返回给.then中的客户端。任何错误都有一个.catch。

我想在findOne成功后添加支票和另一个Sequelize调用,如果其中Active Directory(办公室,公司,部门)的三个数据点中的任何一个与Users表中存储的数据都不匹配,我用一个Users.update调用。我不需要将此调用的结果返回给客户端,也不需要将任何失败通知给客户端。将两者都记录到服务器就足够了。我使用winston进行日志记录。不带代码和带代码的代码如下。两者都有效,但我不确定较长的方法是否正确。

为了完整起见,我包括对AD的Passport调用,以及通过AD Group的替代登录,但是您可以忽略这些位。我在原始代码中添加了一个星号行,以指示在哪里插入了其他代码,在第二个清单中,我在代码周围加上了星号行,以便您可以轻松找到它。

所以我这样做正确吗?

注意:为简便起见,您可以忽略星号后的return语句之后的所有内容。这样不到一半的代码。如果您认为其他相关信息,我只是希望您看到其余内容。

api.post('/login', passport.authenticate('ldapauth', {session: true, failureFlash: 'Invalid username or password.', failWithError: true}),
    (req, res, next) => {
      // this is only called if authentication was successful. this is called after the serializer.
      // the authenticated user is found in req.user.
      let adGroups = req.user.memberOf;
      let office = req.user.physicalDeliveryOfficeName;
      let company = req.user.company;
      let department = req.user.department;
      // console.log('Member Of', adGroups);

      if (typeof req.user.sessionID !== 'undefined') {
        winston.info(`\"Login Successful for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
          {username: req.user.sAMAccountName, sessionID: req.user.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
      } else {
        winston.info(`\"Login Successful for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.dataValues.sid} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
          {username: req.user.sAMAccountName, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
      }
      // console.log('Req user: ', req.user);
      // console.log('right here 1')
      let tempAbilities = [];
      let userAbilities = [];
      let allAbilities = displayAbilities();
      let include = [{
        model: Roles,
        where: {
          active: 1
        },
        include: [ RolesPerms ]
      }];
      let options = {
        where: {
          username: req.user.sAMAccountName
        },
        include: include
      };
      let userID = null;
      // TODO check if found user is 'active === 0' and if so, fail the authentication; use where clause "active != 0"
      // console.log('right here 2')

      Users.findOne(options).then(userResult => {
        // console.log('user result', userResult);
        if (userResult === null) {
          if (typeof req.user.sessionID !== 'undefined') {
            winston.info(`\"Login user not found - looking for group for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.sAMAccountName, sessionID: req.user.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
          } else {
            winston.info(`\"Login user not found - looking for group for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.dataValues.sid} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.sAMAccountName, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
          }
          throw new Error('User not in SutterNow DB.')
        }
        userID = userResult.dataValues.id;
        userResult.roles.forEach(rElement => {
          rElement.roles_perms.forEach(rpElement => {
            // console.log('rpElement', rpElement);
            // if (abilities.findIndex(x => x.prop=="propVal")) --> an example of using an object property to find index
            if (tempAbilities.indexOf(rpElement.dataValues.permission_name) === -1) {
              tempAbilities.push(rpElement.dataValues.permission_name);
              userAbilities.push(allAbilities[allAbilities.findIndex(x => x.name === rpElement.dataValues.permission_name)]);
            }
          })
        });
        req.session.rules = userAbilities;
        let location = {
          office: office,
          company: company,
          department: department
        }
        req.session.location = location
/****************************************************************************************************/
        return res.json({id: userID, rules: userAbilities, location: location, "Message": "Login Successful"});
      }).catch(err => {
        // console.log('ah crap')
        if (typeof req.user.sessionID !== 'undefined') {
          winston.info(`\"Looking for group for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
            {username: req.user.sAMAccountName, sessionID: req.user.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
        } else {
          winston.info(`\"Looking for group for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.dataValues.sid} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
            {username: req.user.sAMAccountName, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
        }
        const promA = Groups.findAll({
          where: {
            active: 1
          },
          include: [{
            model: Roles,
            where: {
              active: 1
            },
            include: [ RolesPerms ]
          }],
          order: ['displayName']
        });
        const promB = GroupsRoles.findAll();
        // console.error(err);
        // user not found in our DB, but they're in AD; let's check if they belong to an approved group
        Promise.all([promA, promB]).then(responses => {
          // console.log('Response 1', responses[0]);
          // console.log('Response 2', responses[1]);

          if (typeof req.user.sessionID !== 'undefined') {
            winston.info(`\"Found group results for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.sAMAccountName, sessionID: req.user.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
          } else {
            winston.info(`\"Found group results for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.dataValues.sid} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.sAMAccountName, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
          }

          let foundGroup = ''
          let foundRoles = []
          let foundPerms = []

          responses[0].forEach(el => {
            // console.log('our el', el)
            // console.log('our group', el.dataValues)
            for (let j = 0; j < adGroups.length; j++) {
              // console.log('adGroups j', adGroups[j])
              if (adGroups[j].match(el.dataValues.username)) {
                // console.log('found it', el.dataValues)
                userID = el.id
                foundGroup = el.dataValues.username;
                foundRoles = el.dataValues;
                break // TODO allow for membership in multiple groups, like I do multiple roles, below
              }
            }
          });

          foundRoles.roles.forEach(role => {
            // console.log('roles_perms things', role.roles_perms);
            role.roles_perms.forEach(roleP => {
              if (foundPerms.indexOf(roleP.dataValues.permission_name) === -1) {
                foundPerms.push(roleP.dataValues.permission_name);
                userAbilities.push(allAbilities[allAbilities.findIndex(x => x.name === roleP.dataValues.permission_name)]);
              }
            })
          });
          req.session.rules = userAbilities;
          let location = {
            office: office,
            company: company,
            department: department
          }
          req.session.location = location

          return res.json({id: 0, rules: userAbilities, location: location, "Message": "Login Successful via group membership"});
        }).catch(err => {
          console.error('the error ' + err);
          return res.json({"Message": "Login failed. You neither had a user account in SutterNow, nor did you belong to a valid AD Group."})
        });
      });

      return null;
      // res.json({"Message":"Login successful"});
  },
    (err, req, res, next) => {
      /* failWithErrors: true, above, makes this section get called to handle the error.
         We don't handle the logging nor the json return here; instead, we setup the error object and pass it on
         to the error handler which does those things. */
      console.log('Authentication failed; passing error on to error handler...');
      err.route = 'Authentication';
      err.statusCode = 401;
      err.status = 401;
      err.shouldRedirect = req.headers['user-agent'].indexOf('Postman') > -1;
      if (typeof req.flash === 'function' && typeof req.flash('error') !== 'undefined' && req.flash('error').length !== 0) {
        err.message = req.flash('error').slice(-1)[0];
        console.log('Flash error ' + req.flash('error').slice(-1)[0]);
        res.statusMessage = req.flash('error').slice(-1)[0];
      }
      if (app.get('env') === 'production') {
        console.log('stack redacted');
        err.stack = '';// We want to obscure any data the user shouldn't see.
      }
      next(err);
      // return res.json({"Message": "Login failed. " + err.message});
      // return null;
    }
  );
api.post('/login', passport.authenticate('ldapauth', {session: true, failureFlash: 'Invalid username or password.', failWithError: true}),
    (req, res, next) => {
      // this is only called if authentication was successful. this is called after the serializer.
      // the authenticated user is found in req.user.
      let adGroups = req.user.memberOf;
      let office = req.user.physicalDeliveryOfficeName;
      let company = req.user.company;
      let department = req.user.department;
      // console.log('Member Of', adGroups);

      if (typeof req.user.sessionID !== 'undefined') {
        winston.info(`\"Login Successful for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
          {username: req.user.sAMAccountName, sessionID: req.user.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
      } else {
        winston.info(`\"Login Successful for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.dataValues.sid} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
          {username: req.user.sAMAccountName, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
      }
      // console.log('Req user: ', req.user);
      // console.log('right here 1')
      let tempAbilities = [];
      let userAbilities = [];
      let allAbilities = displayAbilities();
      let include = [{
        model: Roles,
        where: {
          active: 1
        },
        include: [ RolesPerms ]
      }];
      let options = {
        where: {
          username: req.user.sAMAccountName
        },
        include: include
      };
      let userID = null;
      // TODO check if found user is 'active === 0' and if so, fail the authentication; use where clause "active != 0"
      // console.log('right here 2')

      Users.findOne(options).then(userResult => {
        // console.log('user result', userResult);
        if (userResult === null) {
          if (typeof req.user.sessionID !== 'undefined') {
            winston.info(`\"Login user not found - looking for group for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.sAMAccountName, sessionID: req.user.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
          } else {
            winston.info(`\"Login user not found - looking for group for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.dataValues.sid} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.sAMAccountName, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
          }
          throw new Error('User not in SutterNow DB.')
        }
        userID = userResult.dataValues.id;
        userResult.roles.forEach(rElement => {
          rElement.roles_perms.forEach(rpElement => {
            // console.log('rpElement', rpElement);
            // if (abilities.findIndex(x => x.prop=="propVal")) --> an example of using an object property to find index
            if (tempAbilities.indexOf(rpElement.dataValues.permission_name) === -1) {
              tempAbilities.push(rpElement.dataValues.permission_name);
              userAbilities.push(allAbilities[allAbilities.findIndex(x => x.name === rpElement.dataValues.permission_name)]);
            }
          })
        });
        req.session.rules = userAbilities;
        let location = {
          office: office,
          company: company,
          department: department
        }
        req.session.location = location
/****************************************************************************************************/
        // TODO is this supposed to be another .then chained between this one and the catch (or before this one)? if so, combine the catch?
        if (userResult.dataValues.office !== office || userResult.dataValues.department !== department || userResult.dataValues.company !== company) {
          // update the database with the new AD values
          console.log('updating user')
          Users.update({
            // values
            office: office,
            department: department,
            company: company
          }, {
            // options
            where: {
              id: userID
            }
          }).then(numAffected => {
            winston.info(`\"Updated ${numAffected} user for ${req.user.dataValues.username}\" - SessionID: ${req.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.dataValues.username, sessionID: req.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'User Admin'});
            return;
          }).catch((err) => {
            if (err) {
              // Not sure how to get an error here. ensureAuthenticated handles invalid users attempting this PUT.
              // console.log(err);
              err.route = 'User Admin';
              err.statusCode = 'UPDATE_USER_AT_LOGIN_BY_ID_ERROR';
              err.status = 'UPDATE USER AT LOGIN BY ID ERROR';
              err.shouldRedirect = req.headers['user-agent'].indexOf('Postman') > -1;
              if (app.get('env') === 'production') {
                console.log('stack redacted');
                err.stack = '';// We want to obscure any data the user shouldn't see.
              }
              next(err);
            }
          });
        }
/****************************************************************************************************/
        return res.json({id: userID, rules: userAbilities, location: location, "Message": "Login Successful"});
      }).catch(err => {
        // console.log('ah crap')
        if (typeof req.user.sessionID !== 'undefined') {
          winston.info(`\"Looking for group for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
            {username: req.user.sAMAccountName, sessionID: req.user.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
        } else {
          winston.info(`\"Looking for group for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.dataValues.sid} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
            {username: req.user.sAMAccountName, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
        }
        const promA = Groups.findAll({
          where: {
            active: 1
          },
          include: [{
            model: Roles,
            where: {
              active: 1
            },
            include: [ RolesPerms ]
          }],
          order: ['displayName']
        });
        const promB = GroupsRoles.findAll();
        // console.error(err);
        // user not found in our DB, but they're in AD; let's check if they belong to an approved group
        Promise.all([promA, promB]).then(responses => {
          // console.log('Response 1', responses[0]);
          // console.log('Response 2', responses[1]);

          if (typeof req.user.sessionID !== 'undefined') {
            winston.info(`\"Found group results for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.sAMAccountName, sessionID: req.user.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
          } else {
            winston.info(`\"Found group results for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.dataValues.sid} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.sAMAccountName, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
          }

          let foundGroup = ''
          let foundRoles = []
          let foundPerms = []

          responses[0].forEach(el => {
            // console.log('our el', el)
            // console.log('our group', el.dataValues)
            for (let j = 0; j < adGroups.length; j++) {
              // console.log('adGroups j', adGroups[j])
              if (adGroups[j].match(el.dataValues.username)) {
                // console.log('found it', el.dataValues)
                userID = el.id
                foundGroup = el.dataValues.username;
                foundRoles = el.dataValues;
                break // TODO allow for membership in multiple groups, like I do multiple roles, below
              }
            }
          });

          foundRoles.roles.forEach(role => {
            // console.log('roles_perms things', role.roles_perms);
            role.roles_perms.forEach(roleP => {
              if (foundPerms.indexOf(roleP.dataValues.permission_name) === -1) {
                foundPerms.push(roleP.dataValues.permission_name);
                userAbilities.push(allAbilities[allAbilities.findIndex(x => x.name === roleP.dataValues.permission_name)]);
              }
            })
          });
          req.session.rules = userAbilities;
          let location = {
            office: office,
            company: company,
            department: department
          }
          req.session.location = location

          return res.json({id: 0, rules: userAbilities, location: location, "Message": "Login Successful via group membership"});
        }).catch(err => {
          console.error('the error ' + err);
          return res.json({"Message": "Login failed. You neither had a user account in SutterNow, nor did you belong to a valid AD Group."})
        });
      });

      return null;
      // res.json({"Message":"Login successful"});
  },
    (err, req, res, next) => {
      /* failWithErrors: true, above, makes this section get called to handle the error.
         We don't handle the logging nor the json return here; instead, we setup the error object and pass it on
         to the error handler which does those things. */
      console.log('Authentication failed; passing error on to error handler...');
      err.route = 'Authentication';
      err.statusCode = 401;
      err.status = 401;
      err.shouldRedirect = req.headers['user-agent'].indexOf('Postman') > -1;
      if (typeof req.flash === 'function' && typeof req.flash('error') !== 'undefined' && req.flash('error').length !== 0) {
        err.message = req.flash('error').slice(-1)[0];
        console.log('Flash error ' + req.flash('error').slice(-1)[0]);
        res.statusMessage = req.flash('error').slice(-1)[0];
      }
      if (app.get('env') === 'production') {
        console.log('stack redacted');
        err.stack = '';// We want to obscure any data the user shouldn't see.
      }
      next(err);
      // return res.json({"Message": "Login failed. " + err.message});
      // return null;
    }
  );
node.js express promise sequelize.js passport.js
1个回答
0
投票

我想我明白了。我将添加的代码移至单独的.then,并确保返回的代码不使用res.json,而仅返回对象。然后,无论用户表更新成功还是失败,我都会使用res.json在新的.then中返回该对象,因此:

api.post('/login', passport.authenticate('ldapauth', {session: true, failureFlash: 'Invalid username or password.', failWithError: true}),
    (req, res, next) => {
      // this is only called if authentication was successful. this is called after the serializer.
      // the authenticated user is found in req.user.
      let adGroups = req.user.memberOf;
      let office = req.user.physicalDeliveryOfficeName;
      let company = req.user.company;
      let department = req.user.department;
      // console.log('Member Of', adGroups);

      if (typeof req.user.sessionID !== 'undefined') {
        winston.info(`\"Login Successful for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
          {username: req.user.sAMAccountName, sessionID: req.user.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
      } else {
        winston.info(`\"Login Successful for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.dataValues.sid} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
          {username: req.user.sAMAccountName, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
      }
      // console.log('Req user: ', req.user);
      // console.log('right here 1')
      let tempAbilities = [];
      let userAbilities = [];
      let allAbilities = displayAbilities();
      let include = [{
        model: Roles,
        where: {
          active: 1
        },
        include: [ RolesPerms ]
      }];
      let options = {
        where: {
          username: req.user.sAMAccountName
        },
        include: include
      };
      let userID = null;
      // TODO check if found user is 'active === 0' and if so, fail the authentication; use where clause "active != 0"
      // console.log('right here 2')

      Users.findOne(options).then(userResult => {
        // console.log('user result', userResult);
        if (userResult === null) {
          if (typeof req.user.sessionID !== 'undefined') {
            winston.info(`\"Login user not found - looking for group for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.sAMAccountName, sessionID: req.user.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
          } else {
            winston.info(`\"Login user not found - looking for group for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.dataValues.sid} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.sAMAccountName, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
          }
          throw new Error('User not in SutterNow DB.')
        }
        userID = userResult.dataValues.id;
        userResult.roles.forEach(rElement => {
          rElement.roles_perms.forEach(rpElement => {
            // console.log('rpElement', rpElement);
            // if (abilities.findIndex(x => x.prop=="propVal")) --> an example of using an object property to find index
            if (tempAbilities.indexOf(rpElement.dataValues.permission_name) === -1) {
              tempAbilities.push(rpElement.dataValues.permission_name);
              userAbilities.push(allAbilities[allAbilities.findIndex(x => x.name === rpElement.dataValues.permission_name)]);
            }
          })
        });
        req.session.rules = userAbilities;
        let location = {
          office: office,
          company: company,
          department: department
        }
        req.session.location = location
        let adLocation = {
          office: userResult.dataValues.office,
          company: userResult.dataValues.company,
          department: userResult.dataValues.department
        }

        return {id: userID, rules: userAbilities, location: location, adLocation: adLocation, "Message": "Login Successful"};
      }).then(result => {
        if (result.adLocation.office !== result.location.office || result.adLocation.department !== result.location.department || result.adLocation.company !== result.location.company) {
          // update the database with the new AD values
          Users.update({
            // values
            office: office,
            department: department,
            company: company
          }, {
            // options
            where: {
              id: userID
            }
          }).then(numAffected => {
            winston.info(`\"Updated ${numAffected} user for ${req.user.dataValues.username}\" - SessionID: ${req.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.dataValues.username, sessionID: req.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'User Admin'});
            return res.json(result);
          }).catch((err) => {
            if (err) {
              // Not sure how to get an error here. ensureAuthenticated handles invalid users attempting this PUT.
              // console.log(err);
              err.route = 'User Admin';
              err.statusCode = 'UPDATE_USER_AT_LOGIN_BY_ID_ERROR';
              err.status = 'UPDATE USER AT LOGIN BY ID ERROR';
              err.shouldRedirect = req.headers['user-agent'].indexOf('Postman') > -1;
              if (app.get('env') === 'production') {
                console.log('stack redacted');
                err.stack = '';// We want to obscure any data the user shouldn't see.
              }
              next(err);
            }
          });
        } else {
          return res.json(result);
        }
      }).catch(err => {
        // console.log('ah crap')
        if (typeof req.user.sessionID !== 'undefined') {
          winston.info(`\"Looking for group for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
            {username: req.user.sAMAccountName, sessionID: req.user.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
        } else {
          winston.info(`\"Looking for group for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.dataValues.sid} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
            {username: req.user.sAMAccountName, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
        }
        const promA = Groups.findAll({
          where: {
            active: 1
          },
          include: [{
            model: Roles,
            where: {
              active: 1
            },
            include: [ RolesPerms ]
          }],
          order: ['displayName']
        });
        const promB = GroupsRoles.findAll();
        // console.error(err);
        // user not found in our DB, but they're in AD; let's check if they belong to an approved group
        Promise.all([promA, promB]).then(responses => {
          // console.log('Response 1', responses[0]);
          // console.log('Response 2', responses[1]);

          if (typeof req.user.sessionID !== 'undefined') {
            winston.info(`\"Found group results for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.sessionID} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.sAMAccountName, sessionID: req.user.sessionID, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
          } else {
            winston.info(`\"Found group results for \"${req.user.displayName}\" (${req.user.sAMAccountName})\" - SessionID: ${req.user.dataValues.sid} ${req.ip} \"${req.method} ${req.originalUrl} HTTP/${req.httpVersion}\" \"${req.headers['referer']}\" \"${req.headers['user-agent']}\" \"${req.headers['content-length']}\"`,
              {username: req.user.sAMAccountName, sessionID: req.user.dataValues.sid, ip: req.ip, referrer: req.headers['referer'], url: req.originalUrl, query: req.method, route: 'Authentication'});
          }

          let foundGroup = ''
          let foundRoles = []
          let foundPerms = []

          responses[0].forEach(el => {
            // console.log('our el', el)
            // console.log('our group', el.dataValues)
            for (let j = 0; j < adGroups.length; j++) {
              // console.log('adGroups j', adGroups[j])
              if (adGroups[j].match(el.dataValues.username)) {
                // console.log('found it', el.dataValues)
                userID = el.id
                foundGroup = el.dataValues.username;
                foundRoles = el.dataValues;
                break // TODO allow for membership in multiple groups, like I do multiple roles, below
              }
            }
          });

          foundRoles.roles.forEach(role => {
            // console.log('roles_perms things', role.roles_perms);
            role.roles_perms.forEach(roleP => {
              if (foundPerms.indexOf(roleP.dataValues.permission_name) === -1) {
                foundPerms.push(roleP.dataValues.permission_name);
                userAbilities.push(allAbilities[allAbilities.findIndex(x => x.name === roleP.dataValues.permission_name)]);
              }
            })
          });
          req.session.rules = userAbilities;
          let location = {
            office: office,
            company: company,
            department: department
          }
          req.session.location = location

          return res.json({id: 0, rules: userAbilities, location: location, "Message": "Login Successful via group membership"});
        }).catch(err => {
          console.error('the error ' + err);
          return res.json({"Message": "Login failed. You neither had a user account in SutterNow, nor did you belong to a valid AD Group."})
        });
      });

      return null;
      // res.json({"Message":"Login successful"});
  },
    (err, req, res, next) => {
      /* failWithErrors: true, above, makes this section get called to handle the error.
         We don't handle the logging nor the json return here; instead, we setup the error object and pass it on
         to the error handler which does those things. */
      console.log('Authentication failed; passing error on to error handler...');
      err.route = 'Authentication';
      err.statusCode = 401;
      err.status = 401;
      err.shouldRedirect = req.headers['user-agent'].indexOf('Postman') > -1;
      if (typeof req.flash === 'function' && typeof req.flash('error') !== 'undefined' && req.flash('error').length !== 0) {
        err.message = req.flash('error').slice(-1)[0];
        console.log('Flash error ' + req.flash('error').slice(-1)[0]);
        res.statusMessage = req.flash('error').slice(-1)[0];
      }
      if (app.get('env') === 'production') {
        console.log('stack redacted');
        err.stack = '';// We want to obscure any data the user shouldn't see.
      }
      next(err);
      // return res.json({"Message": "Login failed. " + err.message});
      // return null;
    }
  );
© www.soinside.com 2019 - 2024. All rights reserved.