Browse Source

passport saml: passport

mizozobu 7 years ago
parent
commit
19ef7eefd8

+ 1 - 0
src/server/crowi/index.js

@@ -283,6 +283,7 @@ Crowi.prototype.setupPassport = function() {
     this.passportService.setupGoogleStrategy();
     this.passportService.setupGitHubStrategy();
     this.passportService.setupTwitterStrategy();
+    this.passportService.setupSamlStrategy();
   }
   catch (err) {
     logger.error(err);

+ 3 - 1
src/server/routes/index.js

@@ -75,9 +75,11 @@ module.exports = function(crowi, app) {
   app.get('/passport/google'                      , loginPassport.loginWithGoogle);
   app.get('/passport/github'                      , loginPassport.loginWithGitHub);
   app.get('/passport/twitter'                     , loginPassport.loginWithTwitter);
+  app.get('/passport/saml'                        , loginPassport.loginWithSaml);
   app.get('/passport/google/callback'             , loginPassport.loginPassportGoogleCallback);
   app.get('/passport/github/callback'             , loginPassport.loginPassportGitHubCallback);
-  app.get('/passport/twitter/callback'             , loginPassport.loginPassportTwitterCallback);
+  app.get('/passport/twitter/callback'            , loginPassport.loginPassportTwitterCallback);
+  app.post('/passport/saml/callback'               , loginPassport.loginPassportSamlCallback);
 
   // markdown admin
   app.get('/admin/markdown'                   , loginRequired(crowi, app) , middleware.adminRequired() , admin.markdown.index);

+ 35 - 0
src/server/routes/login-passport.js

@@ -311,6 +311,39 @@ module.exports = function(crowi, app) {
     });
   };
 
+  const loginWithSaml = function(req, res, next) {
+    if (!passportService.isSamlStrategySetup) {
+      debug('SamlStrategy has not been set up');
+      req.flash('warningMessage', 'SamlStrategy has not been set up');
+      return next();
+    }
+
+    passport.authenticate('saml')(req, res);
+  };
+
+  const loginPassportSamlCallback = async(req, res, next) => {
+    const providerId = 'saml';
+    const strategyName = 'saml';
+    const response = await promisifiedPassportAuthentication(req, res, next, strategyName);
+    const userInfo = {
+      'id': response.id,
+      'username': response.username,
+      'name': `${response.firstName} ${response.lastName}`,
+    };
+
+    const externalAccount = await getOrCreateUser(req, res, next, userInfo, providerId);
+    if (!externalAccount) {
+      return loginFailure(req, res, next);
+    }
+
+    const user = await externalAccount.getPopulatedUser();
+
+    // login
+    req.logIn(user, err => {
+      if (err) { return next(err) }
+      return loginSuccess(req, res, user);
+    });
+  };
 
   const promisifiedPassportAuthentication = (req, res, next, strategyName) => {
     return new Promise((resolve, reject) => {
@@ -372,8 +405,10 @@ module.exports = function(crowi, app) {
     loginWithGoogle,
     loginWithGitHub,
     loginWithTwitter,
+    loginWithSaml,
     loginPassportGoogleCallback,
     loginPassportGitHubCallback,
     loginPassportTwitterCallback,
+    loginPassportSamlCallback,
   };
 };

+ 64 - 5
src/server/service/passport.js

@@ -5,6 +5,7 @@ const LdapStrategy = require('passport-ldapauth');
 const GoogleStrategy = require('passport-google-auth').Strategy;
 const GitHubStrategy = require('passport-github').Strategy;
 const TwitterStrategy = require('passport-twitter').Strategy;
+const SamlStrategy = require('passport-saml').Strategy;
 
 /**
  * the service class of Passport
@@ -33,6 +34,21 @@ class PassportService {
      */
     this.isGoogleStrategySetup = false;
 
+    /**
+     * the flag whether GitHubStrategy is set up successfully
+     */
+    this.isGitHubStrategySetup = false;
+
+    /**
+     * the flag whether TwitterStrategy is set up successfully
+     */
+    this.isTwitterStrategySetup = false;
+
+    /**
+     * the flag whether SamlStrategy is set up successfully
+     */
+    this.isSamlStrategySetup = false;
+
     /**
      * the flag whether serializer/deserializer are set up successfully
      */
@@ -271,7 +287,6 @@ class PassportService {
 
     const config = this.crowi.config;
     const Config = this.crowi.model('Config');
-    //this
     const isGoogleEnabled = Config.isEnabledPassportGoogle(config);
 
     // when disabled
@@ -317,7 +332,6 @@ class PassportService {
 
     const config = this.crowi.config;
     const Config = this.crowi.model('Config');
-    //this
     const isGitHubEnabled = Config.isEnabledPassportGitHub(config);
 
     // when disabled
@@ -343,8 +357,9 @@ class PassportService {
     this.isGitHubStrategySetup = true;
     debug('GitHubStrategy: setup is done');
   }
+
   /**
-   * reset GoogleStrategy
+   * reset GitHubStrategy
    *
    * @memberof PassportService
    */
@@ -362,7 +377,6 @@ class PassportService {
 
     const config = this.crowi.config;
     const Config = this.crowi.model('Config');
-    //this
     const isTwitterEnabled = Config.isEnabledPassportTwitter(config);
 
     // when disabled
@@ -390,7 +404,7 @@ class PassportService {
   }
 
   /**
-   * reset GoogleStrategy
+   * reset TwitterStrategy
    *
    * @memberof PassportService
    */
@@ -400,6 +414,51 @@ class PassportService {
     this.isTwitterStrategySetup = false;
   }
 
+  setupSamlStrategy() {
+    // check whether the strategy has already been set up
+    if (this.isSamlStrategySetup) {
+      throw new Error('SamlStrategy has already been set up');
+    }
+
+    const config = this.crowi.config;
+    const Config = this.crowi.model('Config');
+    // const isSamlEnabled = Config.isEnabledPassportSaml(config);
+    const isSamlEnabled = true;
+
+    // when disabled
+    if (!isSamlEnabled) {
+      return;
+    }
+
+    debug('SamlStrategy: setting up..');
+    passport.use(new SamlStrategy({
+      path: config.crowi['security:passport-saml:path'] || process.env.SAML_CALLBACK_URI,
+      entryPoint: config.crowi['security:passport-saml:entryPoint'] || process.env.SAML_ENTRY_POINT,
+      issuer: config.crowi['security:passport-saml:issuer'] || process.env.SAML_ISSUER,
+    }, function(profile, done) {
+      if (profile) {
+        return done(null, profile);
+      }
+      else {
+        return done(null, false);
+      }
+    }));
+
+    this.isSamlStrategySetup = true;
+    debug('SamlStrategy: setup is done');
+  }
+
+  /**
+   * reset SamlStrategy
+   *
+   * @memberof PassportService
+   */
+  resetSamlStrategy() {
+    debug('SamlStrategy: reset');
+    passport.unuse('saml');
+    this.isSamlStrategySetup = false;
+  }
+
   /**
    * setup serializer and deserializer
    *