Browse Source

refs 124384: improve error messages

Futa Arai 2 years ago
parent
commit
0c892c3658

+ 5 - 3
apps/app/public/static/locales/en_US/admin.json

@@ -1041,7 +1041,7 @@
     "error_generate_growi_archive": "Failed to generate GROWI archive file",
     "error_generate_growi_archive": "Failed to generate GROWI archive file",
     "error_send_growi_archive": "Failed to send GROWI archive file to the destination GROWI"
     "error_send_growi_archive": "Failed to send GROWI archive file to the destination GROWI"
   },
   },
-  "external_group": {
+  "external_user_group": {
     "management": "External Group Management",
     "management": "External Group Management",
     "execute_sync": "Execute Sync",
     "execute_sync": "Execute Sync",
     "sync": "Sync",
     "sync": "Sync",
@@ -1061,9 +1061,11 @@
       "description_mapper_detail": "Attribute to map as group description. Description can be edited after sync. However, when a mapper is set, the edited value can possibly be overwritten by the next sync.",
       "description_mapper_detail": "Attribute to map as group description. Description can be edited after sync. However, when a mapper is set, the edited value can possibly be overwritten by the next sync.",
       "updated_group_sync_settings": "Updated LDAP group sync settings",
       "updated_group_sync_settings": "Updated LDAP group sync settings",
       "sync_succeeded": "Sync succeeded",
       "sync_succeeded": "Sync succeeded",
-      "sync_failed": "Sync failed. Check LDAP security settings and group sync settings",
       "password": "Password",
       "password": "Password",
-      "password_detail": "Login password is necessary because Bind type is set to User Bind"
+      "password_detail": "Login password is necessary because Bind type is set to User Bind",
+      "circular_reference": "Sync failed because there is a possible circular reference in your LDAP group tree structure",
+      "group_search_failed": "LDAP group search failed. Please check your LDAP security settings and group sync settings.",
+      "user_search_failed": "LDAP user search failed. Please check your LDAP security settings and group sync settings."
     }
     }
   },
   },
   "toaster": {
   "toaster": {

+ 5 - 3
apps/app/public/static/locales/ja_JP/admin.json

@@ -1049,7 +1049,7 @@
     "error_generate_growi_archive": "GROWI アーカイブファイルの作成に失敗しました",
     "error_generate_growi_archive": "GROWI アーカイブファイルの作成に失敗しました",
     "error_send_growi_archive": "GROWI アーカイブファイルの送信に失敗しました"
     "error_send_growi_archive": "GROWI アーカイブファイルの送信に失敗しました"
   },
   },
-  "external_group": {
+  "external_user_group": {
     "management": "外部グループ管理",
     "management": "外部グループ管理",
     "execute_sync": "同期実行",
     "execute_sync": "同期実行",
     "sync": "同期",
     "sync": "同期",
@@ -1069,9 +1069,11 @@
       "description_mapper_detail": "グループの「説明」として読み込む属性。「説明」は同期後に編集可能です。ただし、mapper が設定されている場合、編集内容は再同期によって上書きされます。",
       "description_mapper_detail": "グループの「説明」として読み込む属性。「説明」は同期後に編集可能です。ただし、mapper が設定されている場合、編集内容は再同期によって上書きされます。",
       "updated_group_sync_settings": "LDAP グループ同期設定を更新しました",
       "updated_group_sync_settings": "LDAP グループ同期設定を更新しました",
       "sync_succeeded": "同期に成功しました",
       "sync_succeeded": "同期に成功しました",
-      "sync_failed": "同期に失敗しました。LDAP セキュリティ設定や、グループ同期設定が正しいことを確認してください。",
       "password": "パスワード",
       "password": "パスワード",
-      "password_detail": "認証設定がユーザ Bind のため、ログイン時のパスワードの入力が必要となります"
+      "password_detail": "認証設定がユーザ Bind のため、ログイン時のパスワードの入力が必要となります",
+      "circular_reference": "LDAP グループの木構造に循環参照が行われている可能性があるため、同期に失敗しました",
+      "group_search_failed": "LDAP グループ検索に失敗しました。LDAP セキュリティ設定、グループ同期設定が正しいことを確認してください。",
+      "user_search_failed": "LDAP ユーザ検索に失敗しました。LDAP セキュリティ設定、グループ同期設定が正しいことを確認してください。"
     }
     }
   },
   },
   "toaster": {
   "toaster": {

+ 5 - 2
apps/app/public/static/locales/zh_CN/admin.json

@@ -1049,7 +1049,7 @@
     "error_generate_growi_archive": "Failed to generate GROWI archive file",
     "error_generate_growi_archive": "Failed to generate GROWI archive file",
     "error_send_growi_archive": "Failed to send GROWI archive file to the destination GROWI"
     "error_send_growi_archive": "Failed to send GROWI archive file to the destination GROWI"
   },
   },
-  "external_group": {
+  "external_user_group": {
     "management": "External Group Management",
     "management": "External Group Management",
     "execute_sync": "Execute Sync",
     "execute_sync": "Execute Sync",
     "sync": "Sync",
     "sync": "Sync",
@@ -1071,7 +1071,10 @@
       "sync_succeeded": "Group sync succeeded",
       "sync_succeeded": "Group sync succeeded",
       "sync_failed": "Sync failed. Check LDAP security settings and group sync settings",
       "sync_failed": "Sync failed. Check LDAP security settings and group sync settings",
       "password": "Password",
       "password": "Password",
-      "password_detail": "Login password is necessary because Bind type is set to User Bind"
+      "password_detail": "Login password is necessary because Bind type is set to User Bind",
+      "circular_reference": "Sync failed because there is a possible circular reference in your LDAP group tree structure",
+      "group_search_failed": "LDAP group search failed. Please check your LDAP security settings and group sync settings.",
+      "user_search_failed": "LDAP user search failed. Please check your LDAP security settings and group sync settings."
     }
     }
   },
   },
   "toaster": {
   "toaster": {

+ 1 - 1
apps/app/src/components/Admin/UserGroup/ExternalGroup/ExternalGroupManagement.tsx

@@ -27,7 +27,7 @@ export const ExternalGroupManagement: FC = () => {
   }, []);
   }, []);
 
 
   return <>
   return <>
-    <h2 className="border-bottom">{t('external_group.management')}</h2>
+    <h2 className="border-bottom">{t('external_user_group.management')}</h2>
     <CustomNav
     <CustomNav
       activeTab={activeTab}
       activeTab={activeTab}
       navTabMapping={navTabMapping}
       navTabMapping={navTabMapping}

+ 7 - 7
apps/app/src/components/Admin/UserGroup/ExternalGroup/LdapGroupManagement.tsx

@@ -37,19 +37,19 @@ export const LdapGroupManagement: FC = () => {
       else {
       else {
         await apiv3Put('/external-user-groups/ldap/sync');
         await apiv3Put('/external-user-groups/ldap/sync');
       }
       }
-      toastSuccess(t('external_group.ldap.sync_succeeded'));
+      toastSuccess(t('external_user_group.ldap.sync_succeeded'));
     }
     }
-    catch (e) {
-      toastError(t('external_group.ldap.sync_failed'));
+    catch (errs) {
+      toastError(t(errs[0]?.message));
     }
     }
   }, [t, isUserBind]);
   }, [t, isUserBind]);
 
 
   return <>
   return <>
     <LdapGroupSyncSettingsForm />
     <LdapGroupSyncSettingsForm />
-    <h3 className="border-bottom mb-3">{t('external_group.execute_sync')}</h3>
+    <h3 className="border-bottom mb-3">{t('external_user_group.execute_sync')}</h3>
     <form onSubmit={onSyncBtnClick}>
     <form onSubmit={onSyncBtnClick}>
       {isUserBind && <div className="row form-group">
       {isUserBind && <div className="row form-group">
-        <label htmlFor="ldapGroupSyncPassword" className="text-left text-md-right col-md-3 col-form-label">{t('external_group.ldap.password')}</label>
+        <label htmlFor="ldapGroupSyncPassword" className="text-left text-md-right col-md-3 col-form-label">{t('external_user_group.ldap.password')}</label>
         <div className="col-md-6">
         <div className="col-md-6">
           <input
           <input
             className="form-control"
             className="form-control"
@@ -58,13 +58,13 @@ export const LdapGroupManagement: FC = () => {
             id="ldapGroupSyncPassword"
             id="ldapGroupSyncPassword"
           />
           />
           <p className="form-text text-muted">
           <p className="form-text text-muted">
-            <small>{t('external_group.ldap.password_detail')}</small>
+            <small>{t('external_user_group.ldap.password_detail')}</small>
           </p>
           </p>
         </div>
         </div>
       </div>}
       </div>}
       <div className="row">
       <div className="row">
         <div className="col-md-3"></div>
         <div className="col-md-3"></div>
-        <div className="col-md-6"><button className="btn btn-primary" type="submit">{t('external_group.sync')}</button></div>
+        <div className="col-md-6"><button className="btn btn-primary" type="submit">{t('external_user_group.sync')}</button></div>
       </div>
       </div>
     </form>
     </form>
   </>;
   </>;

+ 21 - 17
apps/app/src/components/Admin/UserGroup/ExternalGroup/LdapGroupSyncSettingsForm.tsx

@@ -35,7 +35,7 @@ export const LdapGroupSyncSettingsForm: FC = () => {
     e.preventDefault();
     e.preventDefault();
     try {
     try {
       await apiv3Put('/external-user-groups/ldap/sync-settings', formValues);
       await apiv3Put('/external-user-groups/ldap/sync-settings', formValues);
-      toastSuccess(t('external_group.ldap.updated_group_sync_settings'));
+      toastSuccess(t('external_user_group.ldap.updated_group_sync_settings'));
     }
     }
     catch (err) {
     catch (err) {
       toastError(err);
       toastError(err);
@@ -43,10 +43,14 @@ export const LdapGroupSyncSettingsForm: FC = () => {
   }, [formValues, t]);
   }, [formValues, t]);
 
 
   return <>
   return <>
-    <h3 className="border-bottom mb-3">{t('external_group.ldap.group_sync_settings')}</h3>
+    <h3 className="border-bottom mb-3">{t('external_user_group.ldap.group_sync_settings')}</h3>
     <form onSubmit={submitHandler}>
     <form onSubmit={submitHandler}>
       <div className="row form-group">
       <div className="row form-group">
-        <label htmlFor="ldapGroupSearchBase" className="text-left text-md-right col-md-3 col-form-label">{t('external_group.ldap.group_search_base_DN')}</label>
+        <label
+          htmlFor="ldapGroupSearchBase"
+          className="text-left text-md-right col-md-3 col-form-label">
+          {t('external_user_group.ldap.group_search_base_DN')}
+        </label>
         <div className="col-md-6">
         <div className="col-md-6">
           <input
           <input
             className="form-control"
             className="form-control"
@@ -57,13 +61,13 @@ export const LdapGroupSyncSettingsForm: FC = () => {
             onChange={e => setFormValues({ ...formValues, ldapGroupSearchBase: e.target.value })}
             onChange={e => setFormValues({ ...formValues, ldapGroupSearchBase: e.target.value })}
           />
           />
           <p className="form-text text-muted">
           <p className="form-text text-muted">
-            <small>{t('external_group.ldap.group_search_base_dn_detail')}</small>
+            <small>{t('external_user_group.ldap.group_search_base_dn_detail')}</small>
           </p>
           </p>
         </div>
         </div>
       </div>
       </div>
       <div className="row form-group">
       <div className="row form-group">
         <label htmlFor="ldapGroupMembershipAttribute" className="text-left text-md-right col-md-3 col-form-label">
         <label htmlFor="ldapGroupMembershipAttribute" className="text-left text-md-right col-md-3 col-form-label">
-          {t('external_group.ldap.membership_attribute')}
+          {t('external_user_group.ldap.membership_attribute')}
         </label>
         </label>
         <div className="col-md-6">
         <div className="col-md-6">
           <input
           <input
@@ -77,15 +81,15 @@ export const LdapGroupSyncSettingsForm: FC = () => {
           />
           />
           <p className="form-text text-muted">
           <p className="form-text text-muted">
             <small>
             <small>
-              {t('external_group.ldap.membership_attribute_detail')} <br />
-            e.g.) <code>member</code>, <code>memberUid</code>
+              {t('external_user_group.ldap.membership_attribute_detail')} <br />
+              e.g.) <code>member</code>, <code>memberUid</code>
             </small>
             </small>
           </p>
           </p>
         </div>
         </div>
       </div>
       </div>
       <div className="row form-group">
       <div className="row form-group">
         <label htmlFor="ldapGroupMembershipAttributeType" className="text-left text-md-right col-md-3 col-form-label">
         <label htmlFor="ldapGroupMembershipAttributeType" className="text-left text-md-right col-md-3 col-form-label">
-          {t('external_group.ldap.membership_attribute_type')}
+          {t('external_user_group.ldap.membership_attribute_type')}
         </label>
         </label>
         <div className="col-md-6">
         <div className="col-md-6">
           <select
           <select
@@ -104,14 +108,14 @@ export const LdapGroupSyncSettingsForm: FC = () => {
           </select>
           </select>
           <p className="form-text text-muted">
           <p className="form-text text-muted">
             <small>
             <small>
-              {t('external_group.ldap.membership_attribute_type_detail')}
+              {t('external_user_group.ldap.membership_attribute_type_detail')}
             </small>
             </small>
           </p>
           </p>
         </div>
         </div>
       </div>
       </div>
       <div className="row form-group">
       <div className="row form-group">
         <label htmlFor="ldapGroupChildGroupAttribute" className="text-left text-md-right col-md-3 col-form-label">
         <label htmlFor="ldapGroupChildGroupAttribute" className="text-left text-md-right col-md-3 col-form-label">
-          {t('external_group.ldap.child_group_attribute')}
+          {t('external_user_group.ldap.child_group_attribute')}
         </label>
         </label>
         <div className="col-md-6">
         <div className="col-md-6">
           <input
           <input
@@ -124,7 +128,7 @@ export const LdapGroupSyncSettingsForm: FC = () => {
             onChange={e => setFormValues({ ...formValues, ldapGroupChildGroupAttribute: e.target.value })}/>
             onChange={e => setFormValues({ ...formValues, ldapGroupChildGroupAttribute: e.target.value })}/>
           <p className="form-text text-muted">
           <p className="form-text text-muted">
             <small>
             <small>
-              {t('external_group.ldap.child_group_attribute_detail')}<br />
+              {t('external_user_group.ldap.child_group_attribute_detail')}<br />
             e.g.) <code>member</code>
             e.g.) <code>member</code>
             </small>
             </small>
           </p>
           </p>
@@ -134,7 +138,7 @@ export const LdapGroupSyncSettingsForm: FC = () => {
         <label
         <label
           className="text-left text-md-right col-md-3 col-form-label"
           className="text-left text-md-right col-md-3 col-form-label"
         >
         >
-          {/* {t('external_group.ldap.auto_generate_user_on_sync')} */}
+          {/* {t('external_user_group.ldap.auto_generate_user_on_sync')} */}
         </label>
         </label>
         <div className="col-md-6">
         <div className="col-md-6">
           <div className="custom-control custom-checkbox custom-checkbox-info">
           <div className="custom-control custom-checkbox custom-checkbox-info">
@@ -150,7 +154,7 @@ export const LdapGroupSyncSettingsForm: FC = () => {
               className="custom-control-label"
               className="custom-control-label"
               htmlFor="autoGenerateUserOnLdapGroupSync"
               htmlFor="autoGenerateUserOnLdapGroupSync"
             >
             >
-              {t('external_group.ldap.auto_generate_user_on_sync')}
+              {t('external_user_group.ldap.auto_generate_user_on_sync')}
             </label>
             </label>
           </div>
           </div>
         </div>
         </div>
@@ -159,7 +163,7 @@ export const LdapGroupSyncSettingsForm: FC = () => {
         <label
         <label
           className="text-left text-md-right col-md-3 col-form-label"
           className="text-left text-md-right col-md-3 col-form-label"
         >
         >
-          {/* {t('external_group.ldap.preserve_deleted_ldap_groups')} */}
+          {/* {t('external_user_group.ldap.preserve_deleted_ldap_groups')} */}
         </label>
         </label>
         <div className="col-md-6">
         <div className="col-md-6">
           <div className="custom-control custom-checkbox custom-checkbox-info">
           <div className="custom-control custom-checkbox custom-checkbox-info">
@@ -175,7 +179,7 @@ export const LdapGroupSyncSettingsForm: FC = () => {
               className="custom-control-label"
               className="custom-control-label"
               htmlFor="preserveDeletedLdapGroups"
               htmlFor="preserveDeletedLdapGroups"
             >
             >
-              {t('external_group.ldap.preserve_deleted_ldap_groups')}
+              {t('external_user_group.ldap.preserve_deleted_ldap_groups')}
             </label>
             </label>
           </div>
           </div>
         </div>
         </div>
@@ -197,7 +201,7 @@ export const LdapGroupSyncSettingsForm: FC = () => {
           />
           />
           <p className="form-text text-muted">
           <p className="form-text text-muted">
             <small>
             <small>
-              {t('external_group.ldap.name_mapper_detail')}
+              {t('external_user_group.ldap.name_mapper_detail')}
             </small>
             </small>
           </p>
           </p>
         </div>
         </div>
@@ -217,7 +221,7 @@ export const LdapGroupSyncSettingsForm: FC = () => {
           />
           />
           <p className="form-text text-muted">
           <p className="form-text text-muted">
             <small>
             <small>
-              {t('external_group.ldap.description_mapper_detail')}
+              {t('external_user_group.ldap.description_mapper_detail')}
             </small>
             </small>
           </p>
           </p>
         </div>
         </div>

+ 1 - 1
apps/app/src/server/routes/apiv3/external-user-group.ts

@@ -86,7 +86,7 @@ module.exports = (crowi: Crowi): Router => {
     }
     }
     catch (err) {
     catch (err) {
       logger.error(err);
       logger.error(err);
-      return res.apiv3Err(err, 500);
+      return res.apiv3Err(err.message, 500);
     }
     }
 
 
     return res.apiv3({}, 204);
     return res.apiv3({}, 204);

+ 15 - 3
apps/app/src/server/service/external-group/ldap-user-group-sync-service.ts

@@ -35,7 +35,13 @@ class LdapUserGroupSyncService extends ExternalUserGroupSyncService {
       }
       }
     };
     };
 
 
-    const userEntryArr = await getUser();
+    let userEntryArr: SearchResultEntry[] | undefined;
+    try {
+      userEntryArr = await getUser();
+    }
+    catch (e) {
+      throw Error('external_user_group.ldap.user_search_failed');
+    }
 
 
     if (userEntryArr != null && userEntryArr.length > 0) {
     if (userEntryArr != null && userEntryArr.length > 0) {
       const userEntry = userEntryArr[0];
       const userEntry = userEntryArr[0];
@@ -58,7 +64,13 @@ class LdapUserGroupSyncService extends ExternalUserGroupSyncService {
     const groupDescriptionAttribute: string = configManager.getConfig('crowi', 'external-user-group:ldap:groupDescriptionAttribute');
     const groupDescriptionAttribute: string = configManager.getConfig('crowi', 'external-user-group:ldap:groupDescriptionAttribute');
     const groupBase: string = this.ldapService.getGroupSearchBase();
     const groupBase: string = this.ldapService.getGroupSearchBase();
 
 
-    const groupEntries = await this.ldapService.searchGroupDir();
+    let groupEntries: SearchResultEntry[];
+    try {
+      groupEntries = await this.ldapService.searchGroupDir();
+    }
+    catch (e) {
+      throw Error('external_user_group.ldap.group_search_failed');
+    }
 
 
     const getChildGroupDnsFromGroupEntry = (groupEntry: SearchResultEntry) => {
     const getChildGroupDnsFromGroupEntry = (groupEntry: SearchResultEntry) => {
       // groupChildGroupAttribute and groupMembershipAttribute may be the same,
       // groupChildGroupAttribute and groupMembershipAttribute may be the same,
@@ -73,7 +85,7 @@ class LdapUserGroupSyncService extends ExternalUserGroupSyncService {
 
 
     const convert = (entry: SearchResultEntry, converted: string[]): ExternalUserGroupTreeNode | null => {
     const convert = (entry: SearchResultEntry, converted: string[]): ExternalUserGroupTreeNode | null => {
       if (converted.includes(entry.objectName)) {
       if (converted.includes(entry.objectName)) {
-        throw Error('There is a possible circular reference in your LDAP group tree structure');
+        throw Error('external_user_group.ldap.circular_reference');
       }
       }
       converted.push(entry.objectName);
       converted.push(entry.objectName);
 
 

+ 6 - 6
apps/app/src/server/service/ldap.ts

@@ -1,5 +1,3 @@
-import assert from 'assert';
-
 import ldap, { NoSuchObjectError } from 'ldapjs';
 import ldap, { NoSuchObjectError } from 'ldapjs';
 
 
 import loggerFactory from '~/utils/logger';
 import loggerFactory from '~/utils/logger';
@@ -76,13 +74,15 @@ class LdapService {
       url,
       url,
     });
     });
 
 
-    client.bind(fixedBindDN, fixedBindCredentials, (err) => {
-      assert.ifError(err);
-    });
-
     const searchResults: SearchResultEntry[] = [];
     const searchResults: SearchResultEntry[] = [];
 
 
     return new Promise((resolve, reject) => {
     return new Promise((resolve, reject) => {
+      client.bind(fixedBindDN, fixedBindCredentials, (err) => {
+        if (err != null) {
+          reject(err);
+        }
+      });
+
       client.search(base || searchBase, { scope, filter }, (err, res) => {
       client.search(base || searchBase, { scope, filter }, (err, res) => {
         if (err != null) {
         if (err != null) {
           reject(err);
           reject(err);