Как войти в систему с помощью Meteor на стороне сервера после получения обратного вызова от IDP [решено] - PullRequest
1 голос
/ 01 апреля 2020

Мне нужно аутентифицировать пользователя с помощью passport-saml v2.0 и войти в систему после того, как аутентификационный обратный вызов успешно отвечает на почтовый запрос IDP.

Я использую React на входе с потоковым маршрутизатором, а Picker - обратно -end.

Я запускаю аутентификацию на стороне клиента, когда нажимаю кнопку, и это создает окно с запросом /auth/saml.

Код работает, и мой пользователь успешно добавлен в mongodb, но теперь, после того, как функция userHandler вернула userId и токен, я хочу использовать Meteor.loginWithToken для входа, но эта функция не работает на стороне сервера.

Основная проблема заключается в использовании информации пользователя, полученной IDP, в функции обратного вызова и входе в систему с использованием Meteor с этой информацией.

Сторона сервера: код для запуска аутентификации с использованием стратегии passport js и passport-saml

import { Picker} from 'meteor/meteorhacks:picker';
import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';
import passport from 'passport';
import saml from 'passport-saml';
import expressSession from 'express-session';

Picker.middleware(bodyParser.json());
Picker.middleware(bodyParser.urlencoded({extended:false}));
Picker.middleware(cookieParser());
Picker.middleware(expressSession({
  secret: 'secret', 
  resave: false, 
  saveUninitialized: true,
}));

var samlStrategy = new saml.Strategy({
    callbackUrl: process.env.ROOT_URL + '/login/callback', //call back in service provider to handle with the IDP response
    entryPoint: 'http://localhost:8080/simplesaml/saml2/idp/SSOService.php', //link for IDP
    issuer: 'saml-poc', //id da entidade provedora
    identifierFormat: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', //formato requisitado pela entidade
    decryptionPvk: process.env.CERTPVK,
    privateCert: process.env.CERTPVK,
    cert: process.env.IDPKEY,
    validateInResponseTo: false,
    disableRequestedAuthnContext: true,
}, function(profile, done) {
    return done(null, profile);
});

passport.use('samlStrategy', samlStrategy);
Picker.middleware(passport.initialize({}));
Picker.middleware(passport.session({}));

//serialize the user
passport.serializeUser(function(user, done) {
  console.log('-----------------------------');
  console.log('serialize user');
  console.log(user);
  console.log('-----------------------------');
  done(null, user);
});

//deserialize
passport.deserializeUser(function(user, done) {
  console.log('-----------------------------');
  console.log('deserialize user');
  console.log(user);
  console.log('-----------------------------');
  done(null, user);
});

Picker.route('/auth/saml', 
  function(params, req, res, next) {
    console.log('Start login handler');
    passport.authenticate('samlStrategy', {
      session: false,
    }, 
    function(err, user, info) {
      if (err) {
        console.log("Error1");
        return next(err);
      }
      if (!user) {
        console.log("Error2");
        return res.json(401, {
            error: 'Auth Error!'
        });
      }
    }
    )(req, res, next);
  }
);

Picker.route('/auth/callback',
  function (params, req, res, next) {
    console.log('-----------------------------');
    console.log('/Start login callback ');
    passport.authenticate('samlStrategy', {
      session: false,
  },
  async function (err, user, info) {
    if (err) {
      return next(err);
    }
    if (!user) {
      return res.json(401, {
          error: 'Auth Error!'
      });
    }

    const {userId, token} = await userHandler(user);

    res.write("<script>window.close();</script>");
    res.flushHeaders();
    res.end('Sucess');

  })(req, res, next);
});

const userHandler = (user) => new Promise((resolve, reject) => {

  let usr = Accounts.findUserByEmail(user.email);
  const company = "company";
  const profile = { name: "Vinicius França" };
  const stampedToken = Accounts._generateStampedLoginToken();

  if(!usr){
    Meteor.call('adminUser_addNewUser', user.email, null, profile, company, "user", undefined, undefined, true, (err,res) => {
      if(!res){
        SweetAlert('OPS...', 'Error', 'error');
      }
      Accounts.findUserByEmail(user.email).then((_usr) => {
        Accounts._insertLoginToken(_usr._id, stampedToken);
        resolve({userId: _usr._id, token: stampedToken});
      })
    });
  } else {
    Accounts._clearAllLoginTokens(usr._id);
    Accounts._insertLoginToken(usr._id, stampedToken);
    resolve({userId: usr._id, token: stampedToken});
  }
});

Клиентская сторона:

logginSAML() {
    this.setState({logginSSO: true});
    let authWindow = window.open(
      window.location.href + "/auth/saml",
      "Window SSO",
      "resizable=no,scrollbars=yes,status=yes",
      "height=1000px",
      "width=100px",
      "_blank"
    );
    const _this = this;

    window.onunload = window.onbeforeunload = (e) => {
      //is not working
      //call login with token here
      _this.setState({logginSSO: false});
      console.log('q loucura man');
      e.returnValue = '';
      delete e['returnValue'];
    };
  }

1 Ответ

0 голосов
/ 02 апреля 2020

Я решил проблему с помощью BroadCastChannel из javascript для отправки информации о пользователях в качестве обходного пути, следовательно, вошел в систему на стороне клиента с помощью методов Meteor.

...