Explorar el Código

Merge pull request #345 from hitochan777/ldap-migration

Migrate from original user when ldap auth succeeds
Yuki Takei hace 8 años
padre
commit
9042a8bed8

+ 2 - 1
lib/form/admin/securityGeneral.js

@@ -11,6 +11,7 @@ module.exports = form(
   field('settingForm[security:basicSecret]'),
   field('settingForm[security:restrictGuestMode]').required(),
   field('settingForm[security:registrationMode]').required(),
-  field('settingForm[security:registrationWhiteList]').custom(normalizeCRLF).custom(stringToArray)
+  field('settingForm[security:registrationWhiteList]').custom(normalizeCRLF).custom(stringToArray),
+  field('settingForm[security:externalAsLocal]').trim().toBooleanStrict(),
 );
 

+ 3 - 1
lib/locales/en-US/translation.json

@@ -275,7 +275,9 @@
     "for_instance":" For instance, if you use growi within a company, you can write ",
     "only_those":" Only those whose e-mail address including the company address can register.",
     "insert_single":"Please insert single e-mail address per line.",
-    "Authentication mechanism settings":"Authentication mechanism settings"
+    "Authentication mechanism settings":"Authentication mechanism settings",
+    "external_as_local": "Bind the external account with the same username as the local one to the local one automatically",
+    "external_as_local_help": "Enabling this option may be helpful if you want to authenticate users with external accounts, that are originally created as local accounts."
   },
 
   "markdown_setting": {

+ 3 - 1
lib/locales/ja/translation.json

@@ -295,7 +295,9 @@
     "for_instance":"例えば、会社で使う場合 などと記載すると、",
     "only_those":"その会社のメールアドレスを持っている人のみ登録可能になります。",
     "insert_single":"1行に1メールアドレス入力してください。",
-    "Authentication mechanism settings":"認証機構設定"
+    "Authentication mechanism settings":"認証機構設定",
+    "external_as_local": "外部アカウントをそれと同じユーザー名を持ったローカルアカウントに自動的にリンクする",
+    "external_as_local_help": "ローカルアカウントとして作成されたユーザーを外部アカウントで認証したい場合に役に立つかもしれません。"
   },
   "markdown_setting": {
     "markdown_rendering": "Markdownレンダリングの設定を変更できます。",

+ 7 - 0
lib/models/config.js

@@ -53,6 +53,7 @@ module.exports = function(crowi) {
       'security:registrationWhiteList' : [],
 
       'security:isEnabledPassport' : false,
+      'security:externalAsLocal': false,
       'security:passport-ldap:isEnabled' : false,
       'security:passport-ldap:serverUrl' : undefined,
       'security:passport-ldap:isUserBind' : undefined,
@@ -277,6 +278,12 @@ module.exports = function(crowi) {
     return getValueForCrowiNS(config, key);
   };
 
+  configSchema.statics.shouldTreatExternalAccountAsLocal = function(config)
+  {
+    const key = 'security:externalAsLocal';
+    return getValueForCrowiNS(config, key);
+  };
+
   configSchema.statics.isUploadable = function(config)
   {
     var method = crowi.env.FILE_UPLOAD || 'aws';

+ 29 - 25
lib/models/external-account.js

@@ -70,35 +70,39 @@ class ExternalAccount {
    */
   static findOrRegister(providerType, accountId, usernameToBeRegistered) {
 
-    return this.findOne({ providerType, accountId })
-      .then((account) => {
-        // found
-        if (account != null) {
-          debug(`ExternalAccount '${accountId}' is found `, account);
-          return account;
+    return this.findOne({ providerType, accountId }).then( account => {
+      // found
+      if (account != null) {
+        debug(`ExternalAccount '${accountId}' is found `, account);
+        return account;
+      }
+
+      const User = ExternalAccount.crowi.model('User');
+      const Config = ExternalAccount.crowi.model('Config');
+
+      const treatExternalUserAsLocalUser = Config.shouldTreatExternalAccountAsLocal(ExternalAccount.crowi.getConfig());
+
+      return User.find({username: usernameToBeRegistered}).then( users => {
+        // throw Exception when count is not zero
+        const maxDuplicateUserCount = treatExternalUserAsLocalUser ? 1 : 0;
+        if (users.length > maxDuplicateUserCount) {
+          throw new DuplicatedUsernameException(`username '${usernameToBeRegistered}' has already been existed`);
         }
-        // not found
-        else {
-          debug(`ExternalAccount '${accountId}' is not found, it is going to be registered.`);
 
-          const User = ExternalAccount.crowi.model('User');
-
-          return User.count({username: usernameToBeRegistered})
-            .then((count) => {
-              // throw Exception when count is not zero
-              if (count > 0) {
-                throw new DuplicatedUsernameException(`username '${usernameToBeRegistered}' has already been existed`);
-              }
-
-              // create user with STATUS_ACTIVE
-              return User.createUser('', usernameToBeRegistered, undefined, undefined, undefined, User.STATUS_ACTIVE);
-            })
-            .then((user) => {
-              return this.create({ providerType: 'ldap', accountId, user: user._id });
-            });
+        if (users.length === 0) {
+          debug(`ExternalAccount '${accountId}' is not found, it is going to be registered.`);
+          // create user with STATUS_ACTIVE
+          return User.createUser('', usernameToBeRegistered, undefined, undefined, undefined, User.STATUS_ACTIVE);
         }
-      });
 
+        debug(`ExternalAccount '${accountId}' will be linked to an exisiting account`);
+        return users[0];
+
+      }).then( newUser => {
+        return this.create({ providerType: 'ldap', accountId, user: newUser._id });
+      })
+
+    });
   }
 
   /**

+ 2 - 3
lib/routes/admin.js

@@ -95,8 +95,7 @@ module.exports = function(crowi, app) {
   // app.get('/admin/security'                  , admin.security.index);
   actions.security = {};
   actions.security.index = function(req, res) {
-    var settingForm;
-    settingForm = Config.setupCofigFormData('crowi', req.config);
+    const settingForm = Config.setupCofigFormData('crowi', req.config);
     return res.render('admin/security', { settingForm });
   };
 
@@ -851,7 +850,7 @@ module.exports = function(crowi, app) {
   };
 
   actions.api.securitySetting = function(req, res) {
-    var form = req.form.settingForm;
+    const form = req.form.settingForm;
 
     if (req.form.isValid) {
       debug('form content', form);

+ 19 - 0
lib/views/admin/security.html

@@ -90,6 +90,25 @@
             </div>
           </div>
 
+          <div class="form-group">
+            <div class="col-xs-offset-3 col-xs-6">
+              <div class="checkbox checkbox-info">
+                <input type="checkbox" id="externalAsLocal" name="settingForm[security:externalAsLocal]" value="1"
+                                                                                                                 {% if settingForm['security:externalAsLocal'] %}
+                checked
+                {% endif %}
+                />
+                <label for="externalAsLocal">
+                  {{ t("security_setting.external_as_local") }}
+                </label>
+              </div>
+  
+              <p class="help-block">
+                {{ t("security_setting.external_as_local_help") }}
+              </p>
+            </div>
+          </div>
+
           <div class="form-group">
             <div class="col-xs-offset-3 col-xs-6">
               <input type="hidden" name="_csrf" value="{{ csrf() }}">