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

Merge pull request #1542 from weseek/reactify-admin/Prevent-turning-off-all

Reactify admin/prevent turning off all
Yuki Takei 6 лет назад
Родитель
Сommit
ac79ba3988

+ 24 - 24
src/client/js/components/Admin/Security/GithubSecuritySetting.jsx

@@ -58,34 +58,34 @@ class GithubSecurityManagement extends React.Component {
       <React.Fragment>
 
         <h2 className="alert-anchor border-bottom">
-          { t('security_setting.OAuth.GitHub.name') } { t('security_setting.configuration') }
+          {t('security_setting.OAuth.GitHub.name')} {t('security_setting.configuration')}
         </h2>
 
         {this.state.retrieveError != null && (
-        <div className="alert alert-danger">
-          <p>{t('Error occurred')} : {this.state.err}</p>
-        </div>
+          <div className="alert alert-danger">
+            <p>{t('Error occurred')} : {this.state.err}</p>
+          </div>
         )}
 
         <div className="row mb-5">
-          <strong className="col-xs-3 text-right">{ t('security_setting.OAuth.GitHub.name') }</strong>
+          <strong className="col-xs-3 text-right">{t('security_setting.OAuth.GitHub.name')}</strong>
           <div className="col-xs-6 text-left">
             <div className="checkbox checkbox-success">
               <input
                 id="isGithubEnabled"
                 type="checkbox"
-                checked={adminGeneralSecurityContainer.state.isGithubOAuthEnabled}
+                checked={adminGeneralSecurityContainer.state.isGitHubEnabled}
                 onChange={() => { adminGeneralSecurityContainer.switchIsGithubOAuthEnabled() }}
               />
               <label htmlFor="isGithubEnabled">
-                { t('security_setting.OAuth.GitHub.enable_github') }
+                {t('security_setting.OAuth.GitHub.enable_github')}
               </label>
             </div>
           </div>
         </div>
 
         <div className="row mb-5">
-          <label className="col-xs-3 text-right">{ t('security_setting.callback_URL') }</label>
+          <label className="col-xs-3 text-right">{t('security_setting.callback_URL')}</label>
           <div className="col-xs-6">
             <input
               className="form-control"
@@ -93,21 +93,21 @@ class GithubSecurityManagement extends React.Component {
               value={adminGithubSecurityContainer.state.appSiteUrl}
               readOnly
             />
-            <p className="help-block small">{ t('security_setting.desc_of_callback_URL', { AuthName: 'OAuth' }) }</p>
+            <p className="help-block small">{t('security_setting.desc_of_callback_URL', { AuthName: 'OAuth' })}</p>
             {!adminGeneralSecurityContainer.state.appSiteUrl && (
-            <div className="alert alert-danger">
-              <i
-                className="icon-exclamation"
-                // eslint-disable-next-line max-len
-                dangerouslySetInnerHTML={{ __html: t('security_setting.alert_siteUrl_is_not_set', { link: `<a href="/admin/app">${t('App settings')}<i class="icon-login"></i></a>` }) }}
-              />
-            </div>
+              <div className="alert alert-danger">
+                <i
+                  className="icon-exclamation"
+                  // eslint-disable-next-line max-len
+                  dangerouslySetInnerHTML={{ __html: t('security_setting.alert_siteUrl_is_not_set', { link: `<a href="/admin/app">${t('App settings')}<i class="icon-login"></i></a>` }) }}
+                />
+              </div>
             )}
           </div>
         </div>
 
 
-        {adminGeneralSecurityContainer.state.isGithubOAuthEnabled && (
+        {adminGeneralSecurityContainer.state.isGithubEnabled && (
           <React.Fragment>
 
             {!adminGithubSecurityContainer.state.isGitHubStrategySetup && (
@@ -117,7 +117,7 @@ class GithubSecurityManagement extends React.Component {
             )}
 
             <div className="row mb-5">
-              <label htmlFor="githubClientId" className="col-xs-3 text-right">{ t('security_setting.clientID') }</label>
+              <label htmlFor="githubClientId" className="col-xs-3 text-right">{t('security_setting.clientID')}</label>
               <div className="col-xs-6">
                 <input
                   className="form-control"
@@ -133,7 +133,7 @@ class GithubSecurityManagement extends React.Component {
             </div>
 
             <div className="row mb-5">
-              <label htmlFor="githubClientSecret" className="col-xs-3 text-right">{ t('security_setting.client_secret') }</label>
+              <label htmlFor="githubClientSecret" className="col-xs-3 text-right">{t('security_setting.client_secret')}</label>
               <div className="col-xs-6">
                 <input
                   className="form-control"
@@ -173,7 +173,7 @@ class GithubSecurityManagement extends React.Component {
 
         <div className="row my-3">
           <div className="col-xs-offset-3 col-xs-5">
-            <div className="btn btn-primary" disabled={this.state.retrieveError != null} onClick={this.onClickSubmit}>{ t('Update') }</div>
+            <div className="btn btn-primary" disabled={this.state.retrieveError != null} onClick={this.onClickSubmit}>{t('Update')}</div>
           </div>
         </div>
 
@@ -182,13 +182,13 @@ class GithubSecurityManagement extends React.Component {
         <div style={{ minHeight: '300px' }}>
           <h4>
             <i className="icon-question" aria-hidden="true"></i>
-            <a href="#collapseHelpForGithubOauth" data-toggle="collapse"> { t('security_setting.OAuth.how_to.github') }</a>
+            <a href="#collapseHelpForGithubOauth" data-toggle="collapse"> {t('security_setting.OAuth.how_to.github')}</a>
           </h4>
           <ol id="collapseHelpForGithubOauth" className="collapse">
             {/* eslint-disable-next-line max-len */}
-            <li dangerouslySetInnerHTML={{ __html:  t('security_setting.OAuth.GitHub.register_1', { link: '<a href="https://github.com/settings/developers" target=_blank>GitHub Developer Settings</a>' }) }} />
-            <li dangerouslySetInnerHTML={{ __html:  t('security_setting.OAuth.GitHub.register_2', { url: adminGithubSecurityContainer.state.callbackUrl }) }} />
-            <li dangerouslySetInnerHTML={{ __html:  t('security_setting.OAuth.GitHub.register_3') }} />
+            <li dangerouslySetInnerHTML={{ __html: t('security_setting.OAuth.GitHub.register_1', { link: '<a href="https://github.com/settings/developers" target=_blank>GitHub Developer Settings</a>' }) }} />
+            <li dangerouslySetInnerHTML={{ __html: t('security_setting.OAuth.GitHub.register_2', { url: adminGithubSecurityContainer.state.callbackUrl }) }} />
+            <li dangerouslySetInnerHTML={{ __html: t('security_setting.OAuth.GitHub.register_3') }} />
           </ol>
         </div>
 

+ 2 - 2
src/client/js/components/Admin/Security/GoogleSecuritySetting.jsx

@@ -74,7 +74,7 @@ class GoogleSecurityManagement extends React.Component {
               <input
                 id="isGoogleEnabled"
                 type="checkbox"
-                checked={adminGeneralSecurityContainer.state.isGoogleOAuthEnabled}
+                checked={adminGeneralSecurityContainer.state.isGoogleEnabled}
                 onChange={() => { adminGeneralSecurityContainer.switchIsGoogleOAuthEnabled() }}
               />
               <label htmlFor="isGoogleEnabled">
@@ -107,7 +107,7 @@ class GoogleSecurityManagement extends React.Component {
         </div>
 
 
-        {adminGeneralSecurityContainer.state.isGoogleOAuthEnabled && (
+        {adminGeneralSecurityContainer.state.isGoogleEnabled && (
           <React.Fragment>
 
             {!adminGoogleSecurityContainer.state.isGoogleStrategySetup && (

+ 26 - 26
src/client/js/components/Admin/Security/TwitterSecuritySetting.jsx

@@ -58,34 +58,34 @@ class TwitterSecurityManagement extends React.Component {
       <React.Fragment>
 
         <h2 className="alert-anchor border-bottom">
-          { t('security_setting.OAuth.Twitter.name') } { t('security_setting.configuration') }
+          {t('security_setting.OAuth.Twitter.name')} {t('security_setting.configuration')}
         </h2>
 
         {this.state.retrieveError != null && (
-        <div className="alert alert-danger">
-          <p>{t('Error occurred')} : {this.state.err}</p>
-        </div>
+          <div className="alert alert-danger">
+            <p>{t('Error occurred')} : {this.state.err}</p>
+          </div>
         )}
 
         <div className="row mb-5">
-          <strong className="col-xs-3 text-right">{ t('security_setting.OAuth.Twitter.name') }</strong>
+          <strong className="col-xs-3 text-right">{t('security_setting.OAuth.Twitter.name')}</strong>
           <div className="col-xs-6 text-left">
             <div className="checkbox checkbox-success">
               <input
                 id="isTwitterEnabled"
                 type="checkbox"
-                checked={adminGeneralSecurityContainer.state.isTwitterOAuthEnabled}
+                checked={adminGeneralSecurityContainer.state.isTwitterEnabled}
                 onChange={() => { adminGeneralSecurityContainer.switchIsTwitterOAuthEnabled() }}
               />
               <label htmlFor="isTwitterEnabled">
-                { t('security_setting.OAuth.Twitter.enable_twitter') }
+                {t('security_setting.OAuth.Twitter.enable_twitter')}
               </label>
             </div>
           </div>
         </div>
 
         <div className="row mb-5">
-          <label className="col-xs-3 text-right">{ t('security_setting.callback_URL') }</label>
+          <label className="col-xs-3 text-right">{t('security_setting.callback_URL')}</label>
           <div className="col-xs-6">
             <input
               className="form-control"
@@ -93,21 +93,21 @@ class TwitterSecurityManagement extends React.Component {
               value={adminTwitterSecurityContainer.state.callbackUrl}
               readOnly
             />
-            <p className="help-block small">{ t('security_setting.desc_of_callback_URL', { AuthName: 'OAuth' }) }</p>
+            <p className="help-block small">{t('security_setting.desc_of_callback_URL', { AuthName: 'OAuth' })}</p>
             {!adminGeneralSecurityContainer.state.appSiteUrl && (
-            <div className="alert alert-danger">
-              <i
-                className="icon-exclamation"
-                // eslint-disable-next-line max-len
-                dangerouslySetInnerHTML={{ __html: t('security_setting.alert_siteUrl_is_not_set', { link: `<a href="/admin/app">${t('App settings')}<i class="icon-login"></i></a>` }) }}
-              />
-            </div>
+              <div className="alert alert-danger">
+                <i
+                  className="icon-exclamation"
+                  // eslint-disable-next-line max-len
+                  dangerouslySetInnerHTML={{ __html: t('security_setting.alert_siteUrl_is_not_set', { link: `<a href="/admin/app">${t('App settings')}<i class="icon-login"></i></a>` }) }}
+                />
+              </div>
             )}
           </div>
         </div>
 
 
-        {adminGeneralSecurityContainer.state.isTwitterOAuthEnabled && (
+        {adminGeneralSecurityContainer.state.isTwitterEnabled && (
           <React.Fragment>
 
             {!adminTwitterSecurityContainer.state.isTwitterStrategySetup && (
@@ -117,7 +117,7 @@ class TwitterSecurityManagement extends React.Component {
             )}
 
             <div className="row mb-5">
-              <label htmlFor="TwitterConsumerId" className="col-xs-3 text-right">{ t('security_setting.clientID') }</label>
+              <label htmlFor="TwitterConsumerId" className="col-xs-3 text-right">{t('security_setting.clientID')}</label>
               <div className="col-xs-6">
                 <input
                   className="form-control"
@@ -133,7 +133,7 @@ class TwitterSecurityManagement extends React.Component {
             </div>
 
             <div className="row mb-5">
-              <label htmlFor="TwitterConsumerSecret" className="col-xs-3 text-right">{ t('security_setting.client_secret') }</label>
+              <label htmlFor="TwitterConsumerSecret" className="col-xs-3 text-right">{t('security_setting.client_secret')}</label>
               <div className="col-xs-6">
                 <input
                   className="form-control"
@@ -173,7 +173,7 @@ class TwitterSecurityManagement extends React.Component {
 
         <div className="row my-3">
           <div className="col-xs-offset-3 col-xs-5">
-            <button type="button" className="btn btn-primary" disabled={this.state.retrieveError != null} onClick={this.onClickSubmit}>{ t('Update') }</button>
+            <button type="button" className="btn btn-primary" disabled={this.state.retrieveError != null} onClick={this.onClickSubmit}>{t('Update')}</button>
           </div>
         </div>
 
@@ -182,16 +182,16 @@ class TwitterSecurityManagement extends React.Component {
         <div style={{ minHeight: '300px' }}>
           <h4>
             <i className="icon-question" aria-hidden="true"></i>
-            <a href="#collapseHelpForTwitterOauth" data-toggle="collapse"> { t('security_setting.OAuth.how_to.twitter') }</a>
+            <a href="#collapseHelpForTwitterOauth" data-toggle="collapse"> {t('security_setting.OAuth.how_to.twitter')}</a>
           </h4>
           <ol id="collapseHelpForTwitterOauth" className="collapse">
             {/* eslint-disable-next-line max-len */}
-            <li dangerouslySetInnerHTML={{ __html:  t('security_setting.OAuth.Twitter.register_1', { link: '<a href="https://apps.twitter.com/" target=_blank>Twitter Application Management</a>' }) }} />
-            <li dangerouslySetInnerHTML={{ __html:  t('security_setting.OAuth.Twitter.register_2') }} />
-            <li dangerouslySetInnerHTML={{ __html:  t('security_setting.OAuth.Twitter.register_3') }} />
+            <li dangerouslySetInnerHTML={{ __html: t('security_setting.OAuth.Twitter.register_1', { link: '<a href="https://apps.twitter.com/" target=_blank>Twitter Application Management</a>' }) }} />
+            <li dangerouslySetInnerHTML={{ __html: t('security_setting.OAuth.Twitter.register_2') }} />
+            <li dangerouslySetInnerHTML={{ __html: t('security_setting.OAuth.Twitter.register_3') }} />
             {/* eslint-disable-next-line max-len */}
-            <li dangerouslySetInnerHTML={{ __html:  t('security_setting.OAuth.Twitter.register_4', { url: adminTwitterSecurityContainer.state.callbackUrl }) }} />
-            <li dangerouslySetInnerHTML={{ __html:  t('security_setting.OAuth.Twitter.register_5') }} />
+            <li dangerouslySetInnerHTML={{ __html: t('security_setting.OAuth.Twitter.register_4', { url: adminTwitterSecurityContainer.state.callbackUrl }) }} />
+            <li dangerouslySetInnerHTML={{ __html: t('security_setting.OAuth.Twitter.register_5') }} />
           </ol>
         </div>
 

+ 37 - 20
src/client/js/services/AdminGeneralSecurityContainer.js

@@ -1,6 +1,7 @@
 import { Container } from 'unstated';
 
 import loggerFactory from '@alias/logger';
+import { toastError } from '../util/apiNotification';
 
 // eslint-disable-next-line no-unused-vars
 const logger = loggerFactory('growi:security:AdminGeneralSecurityContainer');
@@ -32,9 +33,9 @@ export default class AdminGeneralSecurityContainer extends Container {
       isSamlEnabled: true,
       isOidcEnabled: true,
       isBasicEnabled: true,
-      isGoogleOAuthEnabled: true,
-      isGithubOAuthEnabled: true,
-      isTwitterOAuthEnabled: true,
+      isGoogleEnabled: true,
+      isGithubEnabled: true,
+      isTwitterEnabled: true,
     };
 
     this.onIsWikiModeForced = this.onIsWikiModeForced.bind(this);
@@ -119,11 +120,28 @@ export default class AdminGeneralSecurityContainer extends Container {
     return securitySettingParams;
   }
 
+  /**
+   * Switch authentication
+   */
+  async switchAuthentication(stateVariableName, authId) {
+    const isEnabled = !this.state[stateVariableName];
+    try {
+      await this.appContainer.apiv3.put('/security-setting/authentication/enabled', {
+        isEnabled,
+        authId,
+      });
+      this.setState({ [stateVariableName]: isEnabled });
+    }
+    catch (err) {
+      toastError(err);
+    }
+  }
+
   /**
    * Switch local enabled
    */
-  switchIsLocalEnabled() {
-    this.setState({ isLocalEnabled: !this.state.isLocalEnabled });
+  async switchIsLocalEnabled() {
+    this.switchAuthentication('isLocalEnabled', 'local');
   }
 
   /**
@@ -158,51 +176,50 @@ export default class AdminGeneralSecurityContainer extends Container {
   /**
    * Switch LDAP enabled
    */
-  switchIsLdapEnabled() {
-    this.setState({ isLdapEnabled: !this.state.isLdapEnabled });
+  async switchIsLdapEnabled() {
+    this.switchAuthentication('isLdapEnabled', 'ldap');
   }
 
   /**
    * Switch SAML enabled
    */
-  switchIsSamlEnabled() {
-    this.setState({ isSamlEnabled: !this.state.isSamlEnabled });
+  async switchIsSamlEnabled() {
+    this.switchAuthentication('isSamlEnabled', 'saml');
   }
 
   /**
    * Switch Oidc enabled
    */
-  switchIsOidcEnabled() {
-    this.setState({ isOidcEnabled: !this.state.isOidcEnabled });
+  async switchIsOidcEnabled() {
+    this.switchAuthentication('isOidcEnabled', 'oidc');
   }
 
   /**
    * Switch Basic enabled
    */
-  switchIsBasicEnabled() {
-    this.setState({ isBasicEnabled: !this.state.isBasicEnabled });
+  async switchIsBasicEnabled() {
+    this.switchAuthentication('isBasicEnabled', 'basic');
   }
 
   /**
    * Switch GoogleOAuth enabled
    */
-  switchIsGoogleOAuthEnabled() {
-    this.setState({ isGoogleOAuthEnabled: !this.state.isGoogleOAuthEnabled });
+  async switchIsGoogleOAuthEnabled() {
+    this.switchAuthentication('isGoogleEnabled', 'google');
   }
 
   /**
    * Switch GithubOAuth enabled
    */
-  switchIsGithubOAuthEnabled() {
-    this.setState({ isGithubOAuthEnabled: !this.state.isGithubOAuthEnabled });
+  async switchIsGithubOAuthEnabled() {
+    this.switchAuthentication('isGitHubEnabled', 'github');
   }
 
   /**
    * Switch TwitterOAuth enabled
    */
-  switchIsTwitterOAuthEnabled() {
-    this.setState({ isTwitterOAuthEnabled: !this.state.isTwitterOAuthEnabled });
+  async switchIsTwitterOAuthEnabled() {
+    this.switchAuthentication('isTwitterEnabled', 'twitter');
   }
 
-
 }

+ 73 - 22
src/server/routes/apiv3/security-setting.js

@@ -20,6 +20,12 @@ const validator = {
     body('hideRestrictedByOwner').isBoolean(),
     body('hideRestrictedByGroup').isBoolean(),
   ],
+  authenticationSetting: [
+    body('isEnabled').isBoolean(),
+    body('authId').isString().isIn([
+      'local', 'ldap', 'saml', 'oidc', 'basic', 'google', 'github', 'twitter',
+    ]),
+  ],
   localSetting: [
     body('isLocalEnabled').isBoolean(),
     body('registrationMode').isString(),
@@ -393,6 +399,65 @@ module.exports = (crowi) => {
     return res.apiv3({ securityParams });
   });
 
+  /**
+   * @swagger
+   *
+   *    /_api/v3/security-setting/authentication/enabled:
+   *      put:
+   *        tags: [SecuritySetting]
+   *        description: Update authentication isEnabled
+   *        requestBody:
+   *          required: true
+   *          content:
+   *            application/json:
+   *              schema:
+   *                type: object
+   *                properties:
+   *                  isEnabled:
+   *                    type: boolean
+   *                  target:
+   *                    type: string
+   *        responses:
+   *          200:
+   *            description: Succeeded to enable authentication
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  type: object
+   *                  description: updated param
+   */
+  router.put('/authentication/enabled', loginRequiredStrictly, adminRequired, csrf, validator.authenticationSetting, ApiV3FormValidator, async(req, res) => {
+    const { isEnabled, authId } = req.body;
+
+    let setupStrategies = await crowi.passportService.getSetupStrategies();
+
+    // Reflect request param
+    setupStrategies = setupStrategies.filter(strategy => strategy !== authId);
+
+    if (setupStrategies.length === 0) {
+      return res.apiv3Err(new ErrorV3('Can not turn everything off'));
+    }
+
+    const enableParams = { [`security:passport-${authId}:isEnabled`]: isEnabled };
+
+    try {
+      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', enableParams);
+
+      await crowi.passportService.setupStrategyById(authId);
+
+      const responseParams = { [`security:passport-${authId}:isEnabled`]: await crowi.configManager.getConfig('crowi', `security:passport-${authId}:isEnabled`) };
+
+      return res.apiv3({ responseParams });
+    }
+    catch (err) {
+      const msg = 'Error occurred in updating enable setting';
+      logger.error('Error', err);
+      return res.apiv3Err(new ErrorV3(msg, 'update-enable-setting failed'));
+    }
+
+
+  });
+
   /**
    * @swagger
    *
@@ -472,6 +537,7 @@ module.exports = (crowi) => {
     };
     try {
       await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      await crowi.passportService.setupStrategyById('local');
       const localSettingParams = {
         isLocalEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-local:isEnabled'),
         registrationMode: await crowi.configManager.getConfig('crowi', 'security:registrationMode'),
@@ -525,6 +591,7 @@ module.exports = (crowi) => {
 
     try {
       await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      await crowi.passportService.setupStrategyById('ldap');
       const securitySettingParams = {
         serverUrl: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:serverUrl'),
         isUserBind: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isUserBind'),
@@ -585,6 +652,7 @@ module.exports = (crowi) => {
 
     try {
       await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      await crowi.passportService.setupStrategyById('saml');
       const securitySettingParams = {
         missingMandatoryConfigKeys: await crowi.passportService.getSamlMissingMandatoryConfigKeys(),
         samlEntryPoint: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:entryPoint'),
@@ -644,6 +712,7 @@ module.exports = (crowi) => {
 
     try {
       await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      await crowi.passportService.setupStrategyById('oidc');
       const securitySettingParams = {
         oidcProviderName: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:providerName'),
         oidcIssuerHost: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:issuerHost'),
@@ -693,6 +762,7 @@ module.exports = (crowi) => {
 
     try {
       await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      await crowi.passportService.setupStrategyById('basic');
       const securitySettingParams = {
         isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-basic:isSameUsernameTreatedAsIdenticalUser'),
       };
@@ -735,23 +805,16 @@ module.exports = (crowi) => {
 
     try {
       await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      await crowi.passportService.setupStrategyById('google');
       const securitySettingParams = {
         isGoogleOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-google:isEnabled'),
         googleClientId: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientId'),
         googleClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientSecret'),
         isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-google:isSameUsernameTreatedAsIdenticalUser'),
       };
-      // reset strategy
-      await crowi.passportService.resetGoogleStrategy();
-      // setup strategy
-      if (crowi.configManager.getConfig('crowi', 'security:passport-google:isEnabled')) {
-        await crowi.passportService.setupGoogleStrategy(true);
-      }
       return res.apiv3({ securitySettingParams });
     }
     catch (err) {
-      // reset strategy
-      await crowi.passportService.resetGoogleStrategy();
       const msg = 'Error occurred in updating googleOAuth';
       logger.error('Error', err);
       return res.apiv3Err(new ErrorV3(msg, 'update-googleOAuth-failed'));
@@ -788,18 +851,13 @@ module.exports = (crowi) => {
 
     try {
       await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      await crowi.passportService.setupStrategyById('github');
       const securitySettingParams = {
         isGitHubStrategySetup: await crowi.passportService.isGitHubStrategySetup,
         githubClientId: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientId'),
         githubClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientSecret'),
         isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-github:isSameUsernameTreatedAsIdenticalUser'),
       };
-      // reset strategy
-      await crowi.passportService.resetGitHubStrategy();
-      // setup strategy
-      if (crowi.configManager.getConfig('crowi', 'security:passport-github:isEnabled')) {
-        await crowi.passportService.setupGitHubStrategy(true);
-      }
       return res.apiv3({ securitySettingParams });
     }
     catch (err) {
@@ -841,23 +899,16 @@ module.exports = (crowi) => {
 
     try {
       await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      await crowi.passportService.setupStrategyById('twitter');
       const securitySettingParams = {
         isTwitterStrategySetup: await crowi.passportService.isTwitterStrategySetup,
         twitterConsumerId: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:consumerKey'),
         twitterConsumerSecret: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:consumerSecret'),
         isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:isSameUsernameTreatedAsIdenticalUser'),
       };
-      // reset strategy
-      await crowi.passportService.resetTwitterStrategy();
-      // setup strategy
-      if (crowi.configManager.getConfig('crowi', 'security:passport-twitter:isEnabled')) {
-        await crowi.passportService.setupTwitterStrategy(true);
-      }
       return res.apiv3({ securitySettingParams });
     }
     catch (err) {
-      // reset strategy
-      await crowi.passportService.resetTwitterStrategy();
       const msg = 'Error occurred in updating twitterOAuth';
       logger.error('Error', err);
       return res.apiv3Err(new ErrorV3(msg, 'update-twitterOAuth-failed'));

+ 98 - 32
src/server/service/passport.js

@@ -81,6 +81,88 @@ class PassportService {
       'security:passport-saml:attrMapUsername',
       'security:passport-saml:attrMapMail',
     ];
+
+    this.setupFunction = {
+      local: {
+        setup: 'setupLocalStrategy',
+        reset: 'resetLocalStrategy',
+      },
+      ldap: {
+        setup: 'setupLdapStrategy',
+        reset: 'resetLdapStrategy',
+      },
+      saml: {
+        setup: 'setupSamlStrategy',
+        reset: 'resetSamlStrategy',
+      },
+      oidc: {
+        setup: 'setupOidcStrategy',
+        reset: 'resetOidcStrategy',
+      },
+      basic: {
+        setup: 'setupBasicStrategy',
+        reset: 'resetBasicStrategy',
+      },
+      google: {
+        setup: 'setupGoogleStrategy',
+        reset: 'resetGoogleStrategy',
+      },
+      github: {
+        setup: 'setupGitHubStrategy',
+        reset: 'resetGitHubStrategy',
+      },
+      twitter: {
+        setup: 'setupTwitterStrategy',
+        reset: 'resetTwitterStrategy',
+      },
+    };
+  }
+
+  /**
+   * get SetupStrategies
+   *
+   * @return {Array}
+   * @memberof PassportService
+   */
+  getSetupStrategies() {
+    const setupStrategies = [];
+
+    if (this.isLocalStrategySetup) { setupStrategies.push('local') }
+    if (this.isLdapStrategySetup) { setupStrategies.push('ldap') }
+    if (this.isSamlStrategySetup) { setupStrategies.push('saml') }
+    if (this.isOidcStrategySetup) { setupStrategies.push('oidc') }
+    if (this.isBasicStrategySetup) { setupStrategies.push('basic') }
+    if (this.isGoogleStrategySetup) { setupStrategies.push('google') }
+    if (this.isGitHubStrategySetup) { setupStrategies.push('github') }
+    if (this.isTwitterStrategySetup) { setupStrategies.push('twitter') }
+
+    return setupStrategies;
+  }
+
+  /**
+   * get SetupFunction
+   *
+   * @return {Object}
+   * @param {string} authId
+   */
+  getSetupFunction(authId) {
+    return this.setupFunction[authId];
+  }
+
+  /**
+   * setup strategy by target name
+   */
+  setupStrategyById(authId) {
+    const func = this.getSetupFunction(authId);
+
+    try {
+      this[func.setup]();
+    }
+    catch (err) {
+      debug(err);
+      this[func.reset]();
+    }
+
   }
 
   /**
@@ -100,10 +182,8 @@ class PassportService {
    * @memberof PassportService
    */
   setupLocalStrategy() {
-    // check whether the strategy has already been set up
-    if (this.isLocalStrategySetup) {
-      throw new Error('LocalStrategy has already been set up');
-    }
+
+    this.resetLocalStrategy();
 
     const { configManager } = this.crowi;
 
@@ -157,10 +237,8 @@ class PassportService {
    * @memberof PassportService
    */
   setupLdapStrategy() {
-    // check whether the strategy has already been set up
-    if (this.isLdapStrategySetup) {
-      throw new Error('LdapStrategy has already been set up');
-    }
+
+    this.resetLdapStrategy();
 
     const config = this.crowi.config;
     const { configManager } = this.crowi;
@@ -323,10 +401,8 @@ class PassportService {
    * @memberof PassportService
    */
   setupGoogleStrategy() {
-    // check whether the strategy has already been set up
-    if (this.isGoogleStrategySetup) {
-      throw new Error('GoogleStrategy has already been set up');
-    }
+
+    this.resetGoogleStrategy();
 
     const { configManager } = this.crowi;
     const isGoogleEnabled = configManager.getConfig('crowi', 'security:passport-google:isEnabled');
@@ -373,10 +449,8 @@ class PassportService {
   }
 
   setupGitHubStrategy() {
-    // check whether the strategy has already been set up
-    if (this.isGitHubStrategySetup) {
-      throw new Error('GitHubStrategy has already been set up');
-    }
+
+    this.resetGitHubStrategy();
 
     const { configManager } = this.crowi;
     const isGitHubEnabled = configManager.getConfig('crowi', 'security:passport-github:isEnabled');
@@ -423,10 +497,8 @@ class PassportService {
   }
 
   setupTwitterStrategy() {
-    // check whether the strategy has already been set up
-    if (this.isTwitterStrategySetup) {
-      throw new Error('TwitterStrategy has already been set up');
-    }
+
+    this.resetTwitterStrategy();
 
     const { configManager } = this.crowi;
     const isTwitterEnabled = configManager.getConfig('crowi', 'security:passport-twitter:isEnabled');
@@ -473,10 +545,8 @@ class PassportService {
   }
 
   async setupOidcStrategy() {
-    // check whether the strategy has already been set up
-    if (this.isOidcStrategySetup) {
-      throw new Error('OidcStrategy has already been set up');
-    }
+
+    this.resetOidcStrategy();
 
     const { configManager } = this.crowi;
     const isOidcEnabled = configManager.getConfig('crowi', 'security:passport-oidc:isEnabled');
@@ -536,10 +606,8 @@ class PassportService {
   }
 
   setupSamlStrategy() {
-    // check whether the strategy has already been set up
-    if (this.isSamlStrategySetup) {
-      throw new Error('SamlStrategy has already been set up');
-    }
+
+    this.resetSamlStrategy();
 
     const { configManager } = this.crowi;
     const isSamlEnabled = configManager.getConfig('crowi', 'security:passport-saml:isEnabled');
@@ -615,10 +683,8 @@ class PassportService {
    * @memberof PassportService
    */
   setupBasicStrategy() {
-    // check whether the strategy has already been set up
-    if (this.isBasicStrategySetup) {
-      throw new Error('BasicStrategy has already been set up');
-    }
+
+    this.resetBasicStrategy();
 
     const configManager = this.crowi.configManager;
     const isBasicEnabled = configManager.getConfig('crowi', 'security:passport-basic:isEnabled');