Просмотр исходного кода

ensure that PassportService extends ConfigPubsubMessageHandlable

Yuki Takei 5 лет назад
Родитель
Сommit
8f0d2ba60d
3 измененных файлов с 90 добавлено и 29 удалено
  1. 12 8
      src/server/crowi/index.js
  2. 27 19
      src/server/routes/apiv3/security-setting.js
  3. 51 2
      src/server/service/passport.js

+ 12 - 8
src/server/crowi/index.js

@@ -317,18 +317,22 @@ Crowi.prototype.setupPassport = async function() {
   this.passportService.setupSerializer();
   this.passportService.setupSerializer();
   // setup strategies
   // setup strategies
   try {
   try {
-    this.passportService.setupLocalStrategy();
-    this.passportService.setupLdapStrategy();
-    this.passportService.setupGoogleStrategy();
-    this.passportService.setupGitHubStrategy();
-    this.passportService.setupTwitterStrategy();
-    this.passportService.setupOidcStrategy();
-    this.passportService.setupSamlStrategy();
-    this.passportService.setupBasicStrategy();
+    this.passportService.setupStrategyById('local');
+    this.passportService.setupStrategyById('ldap');
+    this.passportService.setupStrategyById('saml');
+    this.passportService.setupStrategyById('oidc');
+    this.passportService.setupStrategyById('basic');
+    this.passportService.setupStrategyById('google');
+    this.passportService.setupStrategyById('github');
+    this.passportService.setupStrategyById('twitter');
   }
   }
   catch (err) {
   catch (err) {
     logger.error(err);
     logger.error(err);
   }
   }
+
+  // add as a message handler
+  this.configPubsub.addMessageHandler(this.passportService);
+
   return Promise.resolve();
   return Promise.resolve();
 };
 };
 
 

+ 27 - 19
src/server/routes/apiv3/security-setting.js

@@ -324,6 +324,16 @@ module.exports = (crowi) => {
   const csrf = require('../../middlewares/csrf')(crowi);
   const csrf = require('../../middlewares/csrf')(crowi);
   const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
   const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
 
 
+  async function updateAndReloadStrategySettings(authId, params) {
+    const { configManager, passportService } = crowi;
+
+    // update config without publishing ConfigPubsubMessage
+    await configManager.updateConfigsInTheSameNamespace('crowi', params, true);
+
+    await passportService.setupStrategyById(authId);
+    await passportService.publishUpdatedMessage(authId);
+  }
+
   /**
   /**
    * @swagger
    * @swagger
    *
    *
@@ -489,9 +499,7 @@ module.exports = (crowi) => {
     const enableParams = { [`security:passport-${authId}:isEnabled`]: isEnabled };
     const enableParams = { [`security:passport-${authId}:isEnabled`]: isEnabled };
 
 
     try {
     try {
-      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', enableParams);
-
-      await crowi.passportService.setupStrategyById(authId);
+      await updateAndReloadStrategySettings(authId, enableParams);
 
 
       const responseParams = {
       const responseParams = {
         [`security:passport-${authId}:isEnabled`]: await crowi.configManager.getConfig('crowi', `security:passport-${authId}:isEnabled`),
         [`security:passport-${authId}:isEnabled`]: await crowi.configManager.getConfig('crowi', `security:passport-${authId}:isEnabled`),
@@ -613,8 +621,8 @@ module.exports = (crowi) => {
       'security:registrationWhiteList': req.body.registrationWhiteList,
       'security:registrationWhiteList': req.body.registrationWhiteList,
     };
     };
     try {
     try {
-      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
-      await crowi.passportService.setupStrategyById('local');
+      await updateAndReloadStrategySettings('local', requestParams);
+
       const localSettingParams = {
       const localSettingParams = {
         registrationMode: await crowi.configManager.getConfig('crowi', 'security:registrationMode'),
         registrationMode: await crowi.configManager.getConfig('crowi', 'security:registrationMode'),
         registrationWhiteList: await crowi.configManager.getConfig('crowi', 'security:registrationWhiteList'),
         registrationWhiteList: await crowi.configManager.getConfig('crowi', 'security:registrationWhiteList'),
@@ -666,8 +674,8 @@ module.exports = (crowi) => {
     };
     };
 
 
     try {
     try {
-      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
-      await crowi.passportService.setupStrategyById('ldap');
+      await updateAndReloadStrategySettings('ldap', requestParams);
+
       const securitySettingParams = {
       const securitySettingParams = {
         serverUrl: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:serverUrl'),
         serverUrl: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:serverUrl'),
         isUserBind: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isUserBind'),
         isUserBind: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isUserBind'),
@@ -757,8 +765,8 @@ module.exports = (crowi) => {
     };
     };
 
 
     try {
     try {
-      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
-      await crowi.passportService.setupStrategyById('saml');
+      await updateAndReloadStrategySettings('saml', requestParams);
+
       const securitySettingParams = {
       const securitySettingParams = {
         missingMandatoryConfigKeys: await crowi.passportService.getSamlMissingMandatoryConfigKeys(),
         missingMandatoryConfigKeys: await crowi.passportService.getSamlMissingMandatoryConfigKeys(),
         samlEntryPoint: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:entryPoint'),
         samlEntryPoint: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:entryPoint'),
@@ -826,8 +834,8 @@ module.exports = (crowi) => {
     };
     };
 
 
     try {
     try {
-      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
-      await crowi.passportService.setupStrategyById('oidc');
+      await updateAndReloadStrategySettings('oidc', requestParams);
+
       const securitySettingParams = {
       const securitySettingParams = {
         oidcProviderName: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:providerName'),
         oidcProviderName: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:providerName'),
         oidcIssuerHost: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:issuerHost'),
         oidcIssuerHost: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:issuerHost'),
@@ -884,8 +892,8 @@ module.exports = (crowi) => {
     };
     };
 
 
     try {
     try {
-      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
-      await crowi.passportService.setupStrategyById('basic');
+      await updateAndReloadStrategySettings('basic', requestParams);
+
       const securitySettingParams = {
       const securitySettingParams = {
         isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-basic:isSameUsernameTreatedAsIdenticalUser'),
         isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-basic:isSameUsernameTreatedAsIdenticalUser'),
       };
       };
@@ -927,8 +935,8 @@ module.exports = (crowi) => {
     };
     };
 
 
     try {
     try {
-      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
-      await crowi.passportService.setupStrategyById('google');
+      await updateAndReloadStrategySettings('google', requestParams);
+
       const securitySettingParams = {
       const securitySettingParams = {
         googleClientId: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientId'),
         googleClientId: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientId'),
         googleClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientSecret'),
         googleClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientSecret'),
@@ -972,8 +980,8 @@ module.exports = (crowi) => {
     };
     };
 
 
     try {
     try {
-      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
-      await crowi.passportService.setupStrategyById('github');
+      await updateAndReloadStrategySettings('github', requestParams);
+
       const securitySettingParams = {
       const securitySettingParams = {
         githubClientId: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientId'),
         githubClientId: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientId'),
         githubClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientSecret'),
         githubClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientSecret'),
@@ -1022,8 +1030,8 @@ module.exports = (crowi) => {
     requestParams = removeNullPropertyFromObject(requestParams);
     requestParams = removeNullPropertyFromObject(requestParams);
 
 
     try {
     try {
-      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
-      await crowi.passportService.setupStrategyById('twitter');
+      await updateAndReloadStrategySettings('twitter', requestParams);
+
       const securitySettingParams = {
       const securitySettingParams = {
         twitterConsumerId: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:consumerKey'),
         twitterConsumerId: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:consumerKey'),
         twitterConsumerSecret: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:consumerSecret'),
         twitterConsumerSecret: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:consumerSecret'),

+ 51 - 2
src/server/service/passport.js

@@ -1,6 +1,7 @@
 const logger = require('@alias/logger')('growi:service:PassportService');
 const logger = require('@alias/logger')('growi:service:PassportService');
 const urljoin = require('url-join');
 const urljoin = require('url-join');
 const luceneQueryParser = require('lucene-query-parser');
 const luceneQueryParser = require('lucene-query-parser');
+
 const passport = require('passport');
 const passport = require('passport');
 const LocalStrategy = require('passport-local').Strategy;
 const LocalStrategy = require('passport-local').Strategy;
 const LdapStrategy = require('passport-ldapauth');
 const LdapStrategy = require('passport-ldapauth');
@@ -12,10 +13,13 @@ const SamlStrategy = require('passport-saml').Strategy;
 const OIDCIssuer = require('openid-client').Issuer;
 const OIDCIssuer = require('openid-client').Issuer;
 const BasicStrategy = require('passport-http').BasicStrategy;
 const BasicStrategy = require('passport-http').BasicStrategy;
 
 
+const ConfigPubsubMessage = require('../models/vo/config-pubsub-message');
+const ConfigPubsubMessageHandlable = require('./config-pubsub/handlable');
+
 /**
 /**
  * the service class of Passport
  * the service class of Passport
  */
  */
-class PassportService {
+class PassportService extends ConfigPubsubMessageHandlable {
 
 
   // see '/lib/form/login.js'
   // see '/lib/form/login.js'
   static get USERNAME_FIELD() { return 'loginForm[username]' }
   static get USERNAME_FIELD() { return 'loginForm[username]' }
@@ -23,7 +27,10 @@ class PassportService {
   static get PASSWORD_FIELD() { return 'loginForm[password]' }
   static get PASSWORD_FIELD() { return 'loginForm[password]' }
 
 
   constructor(crowi) {
   constructor(crowi) {
+    super();
+
     this.crowi = crowi;
     this.crowi = crowi;
+    this.lastLoadedAt = null;
 
 
     /**
     /**
      * the flag whether LocalStrategy is set up successfully
      * the flag whether LocalStrategy is set up successfully
@@ -118,6 +125,47 @@ class PassportService {
     };
     };
   }
   }
 
 
+
+  /**
+   * @inheritdoc
+   */
+  shouldHandleConfigPubsubMessage(configPubsubMessage) {
+    const { eventName, reloadedAt, strategyId } = configPubsubMessage;
+    if (eventName !== 'passportServiceUpdated' || reloadedAt == null || strategyId == null) {
+      return false;
+    }
+
+    return this.lastLoadedAt != null && this.lastLoadedAt < new Date(configPubsubMessage.reloadedAt);
+  }
+
+  /**
+   * @inheritdoc
+   */
+  async handleConfigPubsubMessage(configPubsubMessage) {
+    const { configManager } = this.crowi;
+    const { strategyId } = configPubsubMessage;
+
+    logger.info('Reset strategy by pubsub notification');
+    await configManager.loadConfigs();
+    return this.setupStrategyById(strategyId);
+  }
+
+  async publishUpdatedMessage(strategyId) {
+    if (this.crowi.configPubsub != null) {
+      const configPubsubMessage = new ConfigPubsubMessage('passportStrategyReloaded', {
+        reloadedAt: new Date(),
+        strategyId,
+      });
+
+      try {
+        await this.crowi.configPubsub.publish(configPubsubMessage);
+      }
+      catch (e) {
+        logger.error('Failed to publish update message with configPubsub: ', e.message);
+      }
+    }
+  }
+
   /**
   /**
    * get SetupStrategies
    * get SetupStrategies
    *
    *
@@ -152,7 +200,7 @@ class PassportService {
   /**
   /**
    * setup strategy by target name
    * setup strategy by target name
    */
    */
-  setupStrategyById(authId) {
+  async setupStrategyById(authId) {
     const func = this.getSetupFunction(authId);
     const func = this.getSetupFunction(authId);
 
 
     try {
     try {
@@ -163,6 +211,7 @@ class PassportService {
       this[func.reset]();
       this[func.reset]();
     }
     }
 
 
+    this.lastLoadedAt = new Date();
   }
   }
 
 
   /**
   /**