Quellcode durchsuchen

Merge pull request #1473 from weseek/reactify-admin/create-apiV3-update-ldap-setting

Reactify admin/create api v3 update ldap setting
itizawa vor 6 Jahren
Ursprung
Commit
7eb8c344b3

+ 2 - 1
resource/locales/en-US/translation.json

@@ -528,7 +528,8 @@
       "group_search_filter_detail4": "<code>(&(cn=group1)(memberUid=&#123;&#123;dn&#125;&#125;))</code> hits the groups which has <code>cn=group1</code> and <code>memberUid</code> includes the user's <code>uid</code>(when <code>Group DN Property</code> is not changed from the default value.)",
       "group_search_filter_detail4": "<code>(&(cn=group1)(memberUid=&#123;&#123;dn&#125;&#125;))</code> hits the groups which has <code>cn=group1</code> and <code>memberUid</code> includes the user's <code>uid</code>(when <code>Group DN Property</code> is not changed from the default value.)",
       "group_search_user_DN_property": "User DN Property",
       "group_search_user_DN_property": "User DN Property",
       "group_search_user_DN_property_detail": "The property of user object to use in <code>&#123;&#123;dn&#125;&#125;</code> interpolation of <code>Group Search Filter</code>.",
       "group_search_user_DN_property_detail": "The property of user object to use in <code>&#123;&#123;dn&#125;&#125;</code> interpolation of <code>Group Search Filter</code>.",
-      "test_config": "Test Saved Configuration"
+      "test_config": "Test Saved Configuration",
+      "updated_ldap": "Succeeded to update LDAP setting"
     },
     },
     "SAML": {
     "SAML": {
       "name": "SAML",
       "name": "SAML",

+ 2 - 1
resource/locales/ja/translation.json

@@ -523,7 +523,8 @@
       "group_search_filter_detail4": "<code>(&(cn=group1)(memberUid=&#123;&#123;dn&#125;&#125;))</code> は <code>cn=group1</code> と、ユーザーの <code>uid</code> を含む <code>memberUid</code> を持つグループにヒットします(<code>ユーザーの DN プロパティー</code> がデフォルトから変更されていない場合)",
       "group_search_filter_detail4": "<code>(&(cn=group1)(memberUid=&#123;&#123;dn&#125;&#125;))</code> は <code>cn=group1</code> と、ユーザーの <code>uid</code> を含む <code>memberUid</code> を持つグループにヒットします(<code>ユーザーの DN プロパティー</code> がデフォルトから変更されていない場合)",
       "group_search_user_DN_property": "ユーザーの DN プロパティー",
       "group_search_user_DN_property": "ユーザーの DN プロパティー",
       "group_search_user_DN_property_detail": "<code>グループ検索フィルター</code> 内の <code>&#123;&#123;dn&#125;&#125;</code> で置換される、ユーザーオブジェクトのプロパティー",
       "group_search_user_DN_property_detail": "<code>グループ検索フィルター</code> 内の <code>&#123;&#123;dn&#125;&#125;</code> で置換される、ユーザーオブジェクトのプロパティー",
-      "test_config": "ログインテスト"
+      "test_config": "ログインテスト",
+      "updated_ldap": "LDAP設定 を更新しました"
     },
     },
     "SAML": {
     "SAML": {
       "name": "SAML",
       "name": "SAML",

+ 112 - 62
src/client/js/components/Admin/Security/LdapSecuritySetting.jsx

@@ -1,15 +1,55 @@
 import React from 'react';
 import React from 'react';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import { withTranslation } from 'react-i18next';
+import loggerFactory from '@alias/logger';
 
 
 import { createSubscribedElement } from '../../UnstatedUtils';
 import { createSubscribedElement } from '../../UnstatedUtils';
+import { toastSuccess, toastError } from '../../../util/apiNotification';
 
 
 import AppContainer from '../../../services/AppContainer';
 import AppContainer from '../../../services/AppContainer';
 import AdminGeneralSecurityContainer from '../../../services/AdminGeneralSecurityContainer';
 import AdminGeneralSecurityContainer from '../../../services/AdminGeneralSecurityContainer';
 import AdminLdapSecurityContainer from '../../../services/AdminLdapSecurityContainer';
 import AdminLdapSecurityContainer from '../../../services/AdminLdapSecurityContainer';
 
 
+const logger = loggerFactory('growi:security:AdminLdapSecurityContainer');
+
 class LdapSecuritySetting extends React.Component {
 class LdapSecuritySetting extends React.Component {
 
 
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      retrieveError: null,
+    };
+
+    this.onClickSubmit = this.onClickSubmit.bind(this);
+  }
+
+  async componentDidMount() {
+    const { adminLdapSecurityContainer } = this.props;
+
+    try {
+      await adminLdapSecurityContainer.retrieveSecurityData();
+    }
+    catch (err) {
+      toastError(err);
+      this.setState({ retrieveError: err });
+      logger.error(err);
+    }
+  }
+
+  async onClickSubmit() {
+    const { t, adminLdapSecurityContainer } = this.props;
+
+    try {
+      await adminLdapSecurityContainer.updateLdapSetting();
+      toastSuccess(t('security_setting.ldap.updated_ldap'));
+    }
+    catch (err) {
+      toastError(err);
+      logger.error(err);
+    }
+  }
+
   render() {
   render() {
     const { t, adminGeneralSecurityContainer, adminLdapSecurityContainer } = this.props;
     const { t, adminGeneralSecurityContainer, adminLdapSecurityContainer } = this.props;
     const { isLdapEnabled } = adminGeneralSecurityContainer.state;
     const { isLdapEnabled } = adminGeneralSecurityContainer.state;
@@ -18,7 +58,7 @@ class LdapSecuritySetting extends React.Component {
       <React.Fragment>
       <React.Fragment>
 
 
         <h2 className="alert-anchor border-bottom">
         <h2 className="alert-anchor border-bottom">
-          LDAP { t('security_setting.configuration') }
+          LDAP {t('security_setting.configuration')}
         </h2>
         </h2>
 
 
         <div className="row mb-5">
         <div className="row mb-5">
@@ -32,7 +72,7 @@ class LdapSecuritySetting extends React.Component {
                 onChange={() => { adminGeneralSecurityContainer.switchIsLdapEnabled() }}
                 onChange={() => { adminGeneralSecurityContainer.switchIsLdapEnabled() }}
               />
               />
               <label htmlFor="isLdapEnabled">
               <label htmlFor="isLdapEnabled">
-                { t('security_setting.ldap.enable_ldap') }
+                {t('security_setting.ldap.enable_ldap')}
               </label>
               </label>
             </div>
             </div>
           </div>
           </div>
@@ -48,7 +88,7 @@ class LdapSecuritySetting extends React.Component {
                   className="form-control"
                   className="form-control"
                   type="text"
                   type="text"
                   name="serverUrl"
                   name="serverUrl"
-                  value={adminLdapSecurityContainer.state.serverUrl}
+                  defaultValue={adminLdapSecurityContainer.state.serverUrl}
                   onChange={e => adminLdapSecurityContainer.changeServerUrl(e.target.value)}
                   onChange={e => adminLdapSecurityContainer.changeServerUrl(e.target.value)}
                 />
                 />
                 <small>
                 <small>
@@ -57,29 +97,31 @@ class LdapSecuritySetting extends React.Component {
                     // eslint-disable-next-line react/no-danger
                     // eslint-disable-next-line react/no-danger
                     dangerouslySetInnerHTML={{ __html: t('security_setting.ldap.server_url_detail') }}
                     dangerouslySetInnerHTML={{ __html: t('security_setting.ldap.server_url_detail') }}
                   />
                   />
-                  { t('security_setting.example') }: <code>ldaps://ldap.company.com/ou=people,dc=company,dc=com</code>
+                  {t('security_setting.example')}: <code>ldaps://ldap.company.com/ou=people,dc=company,dc=com</code>
                 </small>
                 </small>
               </div>
               </div>
             </div>
             </div>
 
 
             <div className="row mb-5">
             <div className="row mb-5">
-              <strong className="col-xs-3 text-right">{ t('security_setting.ldap.bind_mode') }</strong>
+              <strong className="col-xs-3 text-right">{t('security_setting.ldap.bind_mode')}</strong>
               <div className="col-xs-6 text-left">
               <div className="col-xs-6 text-left">
                 <div className="my-0 btn-group">
                 <div className="my-0 btn-group">
                   <div className="dropdown">
                   <div className="dropdown">
                     <button className="btn btn-default dropdown-toggle w-100" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                     <button className="btn btn-default dropdown-toggle w-100" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                      <span className="pull-left">{t(`security_setting.ldap.bind_${adminLdapSecurityContainer.state.bindMode}`)}</span>
+                      {adminLdapSecurityContainer.state.isUserBind
+                        ? <span className="pull-left">{t('security_setting.ldap.bind_user')}</span>
+                        : <span className="pull-left">{t('security_setting.ldap.bind_manager')}</span>}
                       <span className="bs-caret pull-right">
                       <span className="bs-caret pull-right">
                         <span className="caret" />
                         <span className="caret" />
                       </span>
                       </span>
                     </button>
                     </button>
                     {/* TODO adjust dropdown after BS4 */}
                     {/* TODO adjust dropdown after BS4 */}
                     <ul className="dropdown-menu" role="menu">
                     <ul className="dropdown-menu" role="menu">
-                      <li key="manager" role="presentation" type="button" onClick={() => { adminLdapSecurityContainer.changeLdapBindMode('manager') }}>
-                        <a role="menuitem">{ t('security_setting.ldap.bind_manager') }</a>
+                      <li key="user" role="presentation" type="button" onClick={() => { adminLdapSecurityContainer.changeLdapBindMode(true) }}>
+                        <a role="menuitem">{t('security_setting.ldap.bind_user')}</a>
                       </li>
                       </li>
-                      <li key="user" role="presentation" type="button" onClick={() => { adminLdapSecurityContainer.changeLdapBindMode('user') }}>
-                        <a role="menuitem">{ t('security_setting.ldap.bind_user') }</a>
+                      <li key="manager" role="presentation" type="button" onClick={() => { adminLdapSecurityContainer.changeLdapBindMode(false) }}>
+                        <a role="menuitem">{t('security_setting.ldap.bind_manager')}</a>
                       </li>
                       </li>
                     </ul>
                     </ul>
                   </div>
                   </div>
@@ -94,70 +136,72 @@ class LdapSecuritySetting extends React.Component {
                   className="form-control"
                   className="form-control"
                   type="text"
                   type="text"
                   name="bindDN"
                   name="bindDN"
-                  value={adminLdapSecurityContainer.state.bindDN}
+                  defaultValue={adminLdapSecurityContainer.state.ldapBindDN}
                   onChange={e => adminLdapSecurityContainer.changeBindDN(e.target.value)}
                   onChange={e => adminLdapSecurityContainer.changeBindDN(e.target.value)}
                 />
                 />
-                {(adminLdapSecurityContainer.state.bindMode === 'manager') ? (
+                {(adminLdapSecurityContainer.state.isUserBind === false) ? (
                   <p className="help-block passport-ldap-managerbind">
                   <p className="help-block passport-ldap-managerbind">
                     <small>
                     <small>
-                      { t('security_setting.ldap.bind_DN_manager_detail') }<br />
-                      { t('security_setting.example') }1: <code>uid=admin,dc=domain,dc=com</code><br />
-                      { t('security_setting.example') }2: <code>admin@domain.com</code>
+                      {t('security_setting.ldap.bind_DN_manager_detail')}<br />
+                      {t('security_setting.example')}1: <code>uid=admin,dc=domain,dc=com</code><br />
+                      {t('security_setting.example')}2: <code>admin@domain.com</code>
                     </small>
                     </small>
                   </p>
                   </p>
-                ) : (
-                  <p className="help-block passport-ldap-userbind">
-                    <small>
-                      { t('security_setting.ldap.bind_DN_user_detail1')}<br />
-                      {/* eslint-disable-next-line react/no-danger */}
-                      <span dangerouslySetInnerHTML={{ __html: t('security_setting.ldap.bind_DN_user_detail2') }} /><br />
-                      { t('security_setting.example') }1: <code>uid={'{{ username }}'},dc=domain,dc=com</code><br />
-                      { t('security_setting.example') }2: <code>{'{{ username }}'}@domain.com</code>
-                    </small>
-                  </p>
-                )}
+                )
+                  : (
+                    <p className="help-block passport-ldap-userbind">
+                      <small>
+                        {t('security_setting.ldap.bind_DN_user_detail1')}<br />
+                        {/* eslint-disable-next-line react/no-danger */}
+                        <span dangerouslySetInnerHTML={{ __html: t('security_setting.ldap.bind_DN_user_detail2') }} /><br />
+                        {t('security_setting.example')}1: <code>uid={'{{ username }}'},dc=domain,dc=com</code><br />
+                        {t('security_setting.example')}2: <code>{'{{ username }}'}@domain.com</code>
+                      </small>
+                    </p>
+                  )}
               </div>
               </div>
             </div>
             </div>
 
 
             <div className="row mb-5">
             <div className="row mb-5">
-              <label htmlFor="bindDNPassword" className="col-xs-3 text-right">{ t('security_setting.ldap.bind_DN_password') }</label>
+              <label htmlFor="bindDNPassword" className="col-xs-3 text-right">{t('security_setting.ldap.bind_DN_password')}</label>
               <div className="col-xs-6">
               <div className="col-xs-6">
                 <input
                 <input
                   className="form-control passport-ldap-managerbind"
                   className="form-control passport-ldap-managerbind"
                   type="password"
                   type="password"
                   name="bindDNPassword"
                   name="bindDNPassword"
-                  value={adminLdapSecurityContainer.state.bindDNPassword}
+                  defaultValue={adminLdapSecurityContainer.state.ldapBindDNPassword}
                   onChange={e => adminLdapSecurityContainer.changeBindDNPassword(e.target.value)}
                   onChange={e => adminLdapSecurityContainer.changeBindDNPassword(e.target.value)}
                 />
                 />
                 {(adminLdapSecurityContainer.state.bindMode === 'manager') ? (
                 {(adminLdapSecurityContainer.state.bindMode === 'manager') ? (
                   <p className="help-block passport-ldap-managerbind">
                   <p className="help-block passport-ldap-managerbind">
                     <small>
                     <small>
-                      { t('security_setting.ldap.bind_DN_password_manager_detail') }
-                    </small>
-                  </p>
-                ) : (
-                  <p className="help-block passport-ldap-userbind">
-                    <small>
-                      { t('security_setting.ldap.bind_DN_password_user_detail') }
+                      {t('security_setting.ldap.bind_DN_password_manager_detail')}
                     </small>
                     </small>
                   </p>
                   </p>
-                )}
+                )
+                  : (
+                    <p className="help-block passport-ldap-userbind">
+                      <small>
+                        {t('security_setting.ldap.bind_DN_password_user_detail')}
+                      </small>
+                    </p>
+                  )}
               </div>
               </div>
             </div>
             </div>
 
 
             <div className="row mb-5">
             <div className="row mb-5">
-              <strong className="col-xs-3 text-right">{ t('security_setting.ldap.search_filter') }</strong>
+              <strong className="col-xs-3 text-right">{t('security_setting.ldap.search_filter')}</strong>
               <div className="col-xs-6">
               <div className="col-xs-6">
                 <input
                 <input
                   className="form-control"
                   className="form-control"
                   type="text"
                   type="text"
                   name="searchFilter"
                   name="searchFilter"
-                  value={adminLdapSecurityContainer.state.searchFilter}
+                  defaultValue={adminLdapSecurityContainer.state.ldapSearchFilter}
                   onChange={e => adminLdapSecurityContainer.changeSearchFilter(e.target.value)}
                   onChange={e => adminLdapSecurityContainer.changeSearchFilter(e.target.value)}
                 />
                 />
                 <p className="help-block">
                 <p className="help-block">
                   <small>
                   <small>
-                    { t('security_setting.ldap.search_filter_detail1') }<br />
+                    {t('security_setting.ldap.search_filter_detail1')}<br />
                     {/* eslint-disable-next-line react/no-danger */}
                     {/* eslint-disable-next-line react/no-danger */}
                     <span dangerouslySetInnerHTML={{ __html: t('security_setting.ldap.search_filter_detail2') }} /><br />
                     <span dangerouslySetInnerHTML={{ __html: t('security_setting.ldap.search_filter_detail2') }} /><br />
                     {/* eslint-disable-next-line react/no-danger */}
                     {/* eslint-disable-next-line react/no-danger */}
@@ -166,9 +210,9 @@ class LdapSecuritySetting extends React.Component {
                 </p>
                 </p>
                 <p className="help-block">
                 <p className="help-block">
                   <small>
                   <small>
-                    { t('security_setting.example') }1 - { t('security_setting.ldap.search_filter_example1') }:
+                    {t('security_setting.example')}1 - {t('security_setting.ldap.search_filter_example1')}:
                     <code>(|(uid={'{{ username }}'})(mail={'{{ username }}'}))</code><br />
                     <code>(|(uid={'{{ username }}'})(mail={'{{ username }}'}))</code><br />
-                    { t('security_setting.example') }2 - { t('security_setting.ldap.search_filter_example2') }:
+                    {t('security_setting.example')}2 - {t('security_setting.ldap.search_filter_example2')}:
                     <code>(sAMAccountName={'{{ username }}'})</code>
                     <code>(sAMAccountName={'{{ username }}'})</code>
                   </small>
                   </small>
                 </p>
                 </p>
@@ -176,7 +220,7 @@ class LdapSecuritySetting extends React.Component {
             </div>
             </div>
 
 
             <h3 className="alert-anchor border-bottom">
             <h3 className="alert-anchor border-bottom">
-              Attribute Mapping ({ t('security_setting.optional') })
+              Attribute Mapping ({t('security_setting.optional')})
             </h3>
             </h3>
 
 
             <div className="row mb-5">
             <div className="row mb-5">
@@ -187,7 +231,7 @@ class LdapSecuritySetting extends React.Component {
                   type="text"
                   type="text"
                   placeholder="Default: uid"
                   placeholder="Default: uid"
                   name="attrMapUsername"
                   name="attrMapUsername"
-                  value={adminLdapSecurityContainer.state.attrMapUsername}
+                  defaultValue={adminLdapSecurityContainer.state.ldapAttrMapUsername}
                   onChange={e => adminLdapSecurityContainer.changeAttrMapUsername(e.target.value)}
                   onChange={e => adminLdapSecurityContainer.changeAttrMapUsername(e.target.value)}
                 />
                 />
                 <p className="help-block">
                 <p className="help-block">
@@ -201,13 +245,13 @@ class LdapSecuritySetting extends React.Component {
               <div className="col-xs-offset-3 col-xs-6 text-left">
               <div className="col-xs-offset-3 col-xs-6 text-left">
                 <div className="checkbox checkbox-success">
                 <div className="checkbox checkbox-success">
                   <input
                   <input
-                    id="cbSameUsernameTreatedAsIdenticalUser"
+                    id="isSameUsernameTreatedAsIdenticalUser"
                     type="checkbox"
                     type="checkbox"
-                    checked={adminLdapSecurityContainer.state.cbSameUsernameTreatedAsIdenticalUser}
-                    onChange={() => { adminLdapSecurityContainer.switchCbSameUsernameTreatedAsIdenticalUser() }}
+                    checked={adminLdapSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser}
+                    onChange={() => { adminLdapSecurityContainer.switchIsSameUsernameTreatedAsIdenticalUser() }}
                   />
                   />
                   <label
                   <label
-                    htmlFor="cbSameUsernameTreatedAsIdenticalUser"
+                    htmlFor="isSameUsernameTreatedAsIdenticalUser"
                     // eslint-disable-next-line react/no-danger
                     // eslint-disable-next-line react/no-danger
                     dangerouslySetInnerHTML={{ __html: t('security_setting.Treat username matching as identical') }}
                     dangerouslySetInnerHTML={{ __html: t('security_setting.Treat username matching as identical') }}
                   />
                   />
@@ -220,37 +264,37 @@ class LdapSecuritySetting extends React.Component {
             </div>
             </div>
 
 
             <div className="row mb-5">
             <div className="row mb-5">
-              <strong htmlFor="attrMapMail" className="col-xs-3 text-right">{ t('Email') }</strong>
+              <strong htmlFor="attrMapMail" className="col-xs-3 text-right">{t('Email')}</strong>
               <div className="col-xs-6">
               <div className="col-xs-6">
                 <input
                 <input
                   className="form-control"
                   className="form-control"
                   type="text"
                   type="text"
                   placeholder="Default: mail"
                   placeholder="Default: mail"
                   name="attrMapMail"
                   name="attrMapMail"
-                  value={adminLdapSecurityContainer.state.attrMapMail}
+                  defaultValue={adminLdapSecurityContainer.state.ldapAttrMapMail}
                   onChange={e => adminLdapSecurityContainer.changeAttrMapMail(e.target.value)}
                   onChange={e => adminLdapSecurityContainer.changeAttrMapMail(e.target.value)}
                 />
                 />
                 <p className="help-block">
                 <p className="help-block">
                   <small>
                   <small>
-                    { t('security_setting.ldap.mail_detail') }
+                    {t('security_setting.ldap.mail_detail')}
                   </small>
                   </small>
                 </p>
                 </p>
               </div>
               </div>
             </div>
             </div>
 
 
             <div className="row mb-5">
             <div className="row mb-5">
-              <strong htmlFor="attrMapName" className="col-xs-3 text-right">{ t('Name') }</strong>
+              <strong htmlFor="attrMapName" className="col-xs-3 text-right">{t('Name')}</strong>
               <div className="col-xs-6">
               <div className="col-xs-6">
                 <input
                 <input
                   className="form-control"
                   className="form-control"
                   type="text"
                   type="text"
                   name="attrMapName"
                   name="attrMapName"
-                  value={adminLdapSecurityContainer.state.attrMapName}
+                  defaultValue={adminLdapSecurityContainer.state.ldapAttrMapName}
                   onChange={e => adminLdapSecurityContainer.changeAttrMapName(e.target.value)}
                   onChange={e => adminLdapSecurityContainer.changeAttrMapName(e.target.value)}
                 />
                 />
                 <p className="help-block">
                 <p className="help-block">
                   <small>
                   <small>
-                    { t('security_setting.ldap.name_detail') }
+                    {t('security_setting.ldap.name_detail')}
                   </small>
                   </small>
                 </p>
                 </p>
               </div>
               </div>
@@ -258,37 +302,37 @@ class LdapSecuritySetting extends React.Component {
 
 
 
 
             <h3 className="alert-anchor border-bottom">
             <h3 className="alert-anchor border-bottom">
-              { t('security_setting.ldap.group_search_filter') } ({ t('security_setting.optional') })
+              {t('security_setting.ldap.group_search_filter')} ({t('security_setting.optional')})
             </h3>
             </h3>
 
 
             <div className="row mb-5">
             <div className="row mb-5">
-              <strong htmlFor="groupSearchBase" className="col-xs-3 text-right">{ t('security_setting.ldap.group_search_base_DN') }</strong>
+              <strong htmlFor="groupSearchBase" className="col-xs-3 text-right">{t('security_setting.ldap.group_search_base_DN')}</strong>
               <div className="col-xs-6">
               <div className="col-xs-6">
                 <input
                 <input
                   className="form-control"
                   className="form-control"
                   type="text"
                   type="text"
                   name="groupSearchBase"
                   name="groupSearchBase"
-                  value={adminLdapSecurityContainer.state.groupSearchBase}
+                  defaultValue={adminLdapSecurityContainer.state.ldapGroupSearchBase}
                   onChange={e => adminLdapSecurityContainer.changeGroupSearchBase(e.target.value)}
                   onChange={e => adminLdapSecurityContainer.changeGroupSearchBase(e.target.value)}
                 />
                 />
                 <p className="help-block">
                 <p className="help-block">
                   <small>
                   <small>
                     {/* eslint-disable-next-line react/no-danger */}
                     {/* eslint-disable-next-line react/no-danger */}
                     <span dangerouslySetInnerHTML={{ __html: t('security_setting.ldap.group_search_base_DN_detail') }} /><br />
                     <span dangerouslySetInnerHTML={{ __html: t('security_setting.ldap.group_search_base_DN_detail') }} /><br />
-                    { t('security_setting.example') }: <code>ou=groups,dc=domain,dc=com</code>
+                    {t('security_setting.example')}: <code>ou=groups,dc=domain,dc=com</code>
                   </small>
                   </small>
                 </p>
                 </p>
               </div>
               </div>
             </div>
             </div>
 
 
             <div className="row mb-5">
             <div className="row mb-5">
-              <strong htmlFor="groupSearchFilter" className="col-xs-3 text-right">{ t('security_setting.ldap.group_search_filter') }</strong>
+              <strong htmlFor="groupSearchFilter" className="col-xs-3 text-right">{t('security_setting.ldap.group_search_filter')}</strong>
               <div className="col-xs-6">
               <div className="col-xs-6">
                 <input
                 <input
                   className="form-control"
                   className="form-control"
                   type="text"
                   type="text"
                   name="groupSearchFilter"
                   name="groupSearchFilter"
-                  value={adminLdapSecurityContainer.state.groupSearchFilter}
+                  defaultValue={adminLdapSecurityContainer.state.ldapGroupSearchFilter}
                   onChange={e => adminLdapSecurityContainer.changeGroupSearchFilter(e.target.value)}
                   onChange={e => adminLdapSecurityContainer.changeGroupSearchFilter(e.target.value)}
                 />
                 />
                 <p className="help-block">
                 <p className="help-block">
@@ -302,7 +346,7 @@ class LdapSecuritySetting extends React.Component {
                 </p>
                 </p>
                 <p className="help-block">
                 <p className="help-block">
                   <small>
                   <small>
-                    { t('security_setting.example') }:
+                    {t('security_setting.example')}:
                     {/* eslint-disable-next-line react/no-danger */}
                     {/* eslint-disable-next-line react/no-danger */}
                     <span dangerouslySetInnerHTML={{ __html: t('security_setting.ldap.group_search_filter_detail4') }} />
                     <span dangerouslySetInnerHTML={{ __html: t('security_setting.ldap.group_search_filter_detail4') }} />
                   </small>
                   </small>
@@ -311,14 +355,14 @@ class LdapSecuritySetting extends React.Component {
             </div>
             </div>
 
 
             <div className="row mb-5">
             <div className="row mb-5">
-              <label htmlFor="groupDnProperty" className="col-xs-3 text-right">{ t('security_setting.ldap.group_search_user_DN_property') }</label>
+              <label htmlFor="groupDnProperty" className="col-xs-3 text-right">{t('security_setting.ldap.group_search_user_DN_property')}</label>
               <div className="col-xs-6">
               <div className="col-xs-6">
                 <input
                 <input
                   className="form-control"
                   className="form-control"
                   type="text"
                   type="text"
                   placeholder="Default: uid"
                   placeholder="Default: uid"
                   name="groupDnProperty"
                   name="groupDnProperty"
-                  value={adminLdapSecurityContainer.state.groupDnProperty}
+                  defaultValue={adminLdapSecurityContainer.state.ldapGroupDnProperty}
                   onChange={e => adminLdapSecurityContainer.changeGroupDnProperty(e.target.value)}
                   onChange={e => adminLdapSecurityContainer.changeGroupDnProperty(e.target.value)}
                 />
                 />
                 <p className="help-block">
                 <p className="help-block">
@@ -331,6 +375,12 @@ class LdapSecuritySetting extends React.Component {
           </React.Fragment>
           </React.Fragment>
         )}
         )}
 
 
+        <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>
+          </div>
+        </div>
+
       </React.Fragment>
       </React.Fragment>
     );
     );
   }
   }

+ 106 - 52
src/client/js/services/AdminLdapSecurityContainer.js

@@ -17,27 +17,42 @@ export default class AdminLdapSecurityContainer extends Container {
     this.appContainer = appContainer;
     this.appContainer = appContainer;
 
 
     this.state = {
     this.state = {
-      // TODO GW-583 set value
       serverUrl: '',
       serverUrl: '',
-      bindMode: 'manager',
-      bindDN: '',
-      bindDNPassword: '',
-      searchFilter: '',
-      attrMapUsername: '',
-      cbSameUsernameTreatedAsIdenticalUser: true,
-      attrMapMail: '',
-      attrMapName: '',
-      groupSearchBase: '',
-      groupSearchFilter: '',
-      groupDnProperty: '',
+      isUserBind: false,
+      ldapBindDN: '',
+      ldapBindDNPassword: '',
+      ldapSearchFilter: '',
+      ldapAttrMapUsername: '',
+      isSameUsernameTreatedAsIdenticalUser: false,
+      ldapAttrMapMail: '',
+      ldapAttrMapName: '',
+      ldapGroupSearchBase: '',
+      ldapGroupSearchFilter: '',
+      ldapGroupDnProperty: '',
     };
     };
 
 
-    this.init();
-
   }
   }
 
 
-  init() {
-    // TODO GW-583 fetch config value with api
+  /**
+   * retrieve security data
+   */
+  async retrieveSecurityData() {
+    const response = await this.appContainer.apiv3.get('/security-setting/');
+    const { ldapAuth } = response.data.securityParams;
+    this.setState({
+      serverUrl: ldapAuth.serverUrl || '',
+      isUserBind: ldapAuth.isUserBind || false,
+      ldapBindDN: ldapAuth.ldapBindDN || '',
+      ldapBindDNPassword: ldapAuth.ldapBindDNPassword || '',
+      ldapSearchFilter: ldapAuth.ldapSearchFilter || '',
+      ldapAttrMapUsername: ldapAuth.ldapAttrMapUsername || '',
+      isSameUsernameTreatedAsIdenticalUser: ldapAuth.isSameUsernameTreatedAsIdenticalUser || false,
+      ldapAttrMapMail: ldapAuth.ldapAttrMapMail || '',
+      ldapAttrMapName: ldapAuth.ldapAttrMapName || '',
+      ldapGroupSearchBase: ldapAuth.ldapGroupSearchBase || '',
+      ldapGroupSearchFilter: ldapAuth.ldapGroupSearchFilter || '',
+      ldapGroupDnProperty: ldapAuth.ldapGroupDnProperty || '',
+    });
   }
   }
 
 
 
 
@@ -49,87 +64,126 @@ export default class AdminLdapSecurityContainer extends Container {
   }
   }
 
 
   /**
   /**
-   * Change server url
+   * Change serverUrl
+   */
+  changeServerUrl(serverUrl) {
+    this.setState({ serverUrl });
+  }
+
+  /**
+   * Change ldapBindMode
    */
    */
-  changeServerUrl(inputValue) {
-    this.setState({ serverUrl: inputValue });
+  changeLdapBindMode() {
+    this.setState({ isUserBind: !this.state.isUserBind });
   }
   }
 
 
   /**
   /**
-   * Change ldap bind mode
+   * Change bindDN
    */
    */
-  changeLdapBindMode(mode) {
-    this.setState({ bindMode: mode });
+  changeBindDN(ldapBindDN) {
+    this.setState({ ldapBindDN });
   }
   }
 
 
   /**
   /**
-   * Change bind DN
+   * Change bindDNPassword
    */
    */
-  changeBindDN(inputValue) {
-    this.setState({ bindDN: inputValue });
+  changeBindDNPassword(ldapBindDNPassword) {
+    this.setState({ ldapBindDNPassword });
   }
   }
 
 
   /**
   /**
-   * Change bind DN password
+   * Change ldapSearchFilter
    */
    */
-  changeBindDNPassword(inputValue) {
-    this.setState({ bindDNPassword: inputValue });
+  changeSearchFilter(ldapSearchFilter) {
+    this.setState({ ldapSearchFilter });
   }
   }
 
 
   /**
   /**
-   * Change search filter
+   * Change ldapAttrMapUsername
    */
    */
-  changeSearchFilter(inputValue) {
-    this.setState({ searchFilter: inputValue });
+  changeAttrMapUsername(ldapAttrMapUsername) {
+    this.setState({ ldapAttrMapUsername });
   }
   }
 
 
   /**
   /**
-   * Change attr map username
+   * Switch is same username treated as identical user
    */
    */
-  changeAttrMapUsername(inputValue) {
-    this.setState({ attrMapUsername: inputValue });
+  switchIsSameUsernameTreatedAsIdenticalUser() {
+    this.setState({ isSameUsernameTreatedAsIdenticalUser: !this.state.isSameUsernameTreatedAsIdenticalUser });
   }
   }
 
 
   /**
   /**
-   * Switch cb same username treated as identical user
+   * Change ldapAttrMapMail
    */
    */
-  switchCbSameUsernameTreatedAsIdenticalUser() {
-    this.setState({ cbSameUsernameTreatedAsIdenticalUser: !this.state.cbSameUsernameTreatedAsIdenticalUser });
+  changeAttrMapMail(ldapAttrMapMail) {
+    this.setState({ ldapAttrMapMail });
   }
   }
 
 
   /**
   /**
-   * Change attr map email
+   * Change ldapAttrMapName
    */
    */
-  changeAttrMapMail(inputValue) {
-    this.setState({ attrMapMail: inputValue });
+  changeAttrMapName(ldapAttrMapName) {
+    this.setState({ ldapAttrMapName });
   }
   }
 
 
   /**
   /**
-   * Change attr map name
+   * Change ldapGroupSearchBase
    */
    */
-  changeAttrMapName(inputValue) {
-    this.setState({ attrMapName: inputValue });
+  changeGroupSearchBase(ldapGroupSearchBase) {
+    this.setState({ ldapGroupSearchBase });
   }
   }
 
 
   /**
   /**
-   * Change group search base
+   * Change ldapGroupSearchFilter
    */
    */
-  changeGroupSearchBase(inputValue) {
-    this.setState({ groupSearchBase: inputValue });
+  changeGroupSearchFilter(ldapGroupSearchFilter) {
+    this.setState({ ldapGroupSearchFilter });
   }
   }
 
 
   /**
   /**
-   * Change group search filter
+   * Change ldapGroupDnProperty
    */
    */
-  changeGroupSearchFilter(inputValue) {
-    this.setState({ groupSearchFilter: inputValue });
+  changeGroupDnProperty(ldapGroupDnProperty) {
+    this.setState({ ldapGroupDnProperty });
   }
   }
 
 
   /**
   /**
-   * Change group dn property
+   * Update ldap option
    */
    */
-  changeGroupDnProperty(inputValue) {
-    this.setState({ groupDnProperty: inputValue });
+  async updateLdapSetting() {
+
+    const response = await this.appContainer.apiv3.put('/security-setting/ldap', {
+      serverUrl: this.state.serverUrl,
+      isUserBind: this.state.isUserBind,
+      ldapBindDN: this.state.ldapBindDN,
+      ldapBindDNPassword: this.state.ldapBindDNPassword,
+      ldapSearchFilter: this.state.ldapSearchFilter,
+      ldapAttrMapUsername: this.state.ldapAttrMapUsername,
+      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
+      ldapAttrMapMail: this.state.ldapAttrMapMail,
+      ldapAttrMapName: this.state.ldapAttrMapName,
+      ldapGroupSearchBase: this.state.ldapGroupSearchBase,
+      ldapGroupSearchFilter: this.state.ldapGroupSearchFilter,
+      ldapGroupDnProperty: this.state.ldapGroupDnProperty,
+    });
+
+    const { securitySettingParams } = response.data;
+
+    this.setState({
+      serverUrl: securitySettingParams.serverUrl || '',
+      isUserBind: securitySettingParams.isUserBind || false,
+      ldapBindDN: securitySettingParams.ldapBindDN || '',
+      ldapBindDNPassword: securitySettingParams.ldapBindDNPassword || '',
+      ldapSearchFilter: securitySettingParams.ldapSearchFilter || '',
+      ldapAttrMapUsername: securitySettingParams.ldapAttrMapUsername || '',
+      isSameUsernameTreatedAsIdenticalUser: securitySettingParams.isSameUsernameTreatedAsIdenticalUser || false,
+      ldapAttrMapMail: securitySettingParams.ldapAttrMapMail || '',
+      ldapAttrMapName: securitySettingParams.ldapAttrMapName || '',
+      ldapGroupSearchBase: securitySettingParams.ldapGroupSearchBase || '',
+      ldapGroupSearchFilter: securitySettingParams.ldapGroupSearchFilter || '',
+      ldapGroupDnProperty: securitySettingParams.ldapGroupDnProperty || '',
+    });
+    return response;
   }
   }
 
 
 }
 }

+ 272 - 155
src/server/routes/apiv3/security-setting.js

@@ -19,6 +19,20 @@ const validator = {
     body('hideRestrictedByOwner').isBoolean(),
     body('hideRestrictedByOwner').isBoolean(),
     body('hideRestrictedByGroup').isBoolean(),
     body('hideRestrictedByGroup').isBoolean(),
   ],
   ],
+  ldapAuth: [
+    body('serverUrl').isString(),
+    body('isUserBind').isBoolean(),
+    body('ldapBindDN').isString(),
+    body('ldapBindDNPassword').isString(),
+    body('ldapSearchFilter').isString(),
+    body('ldapAttrMapUsername').isString(),
+    body('isSameUsernameTreatedAsIdenticalUser').isBoolean(),
+    body('ldapAttrMapMail').isString(),
+    body('ldapAttrMapName').isString(),
+    body('ldapGroupSearchBase').isString(),
+    body('ldapGroupSearchFilter').isString(),
+    body('ldapGroupDnProperty').isString(),
+  ],
   samlAuth: [
   samlAuth: [
     body('samlEntryPoint').isString(),
     body('samlEntryPoint').isString(),
     body('samlIssuer').isString(),
     body('samlIssuer').isString(),
@@ -74,133 +88,169 @@ const validator = {
  *
  *
  *  components:
  *  components:
  *    schemas:
  *    schemas:
- *      SecurityParams:
- *        type: object
- *          GeneralSetting:
- *            type:object
- *              GuestModeParams:
- *                type: object
- *                properties:
- *                  restrictGuestMode:
- *                    type: string
- *                    description: type of restrictGuestMode
- *              PageDeletionParams:
- *                type: object
- *                properties:
- *                  pageCompleteDeletionAuthority:
- *                    type: string
- *                    description: type of pageDeletionAuthority
- *              Function:
- *                type: object
- *                properties:
- *                  hideRestrictedByOwner:
- *                    type: boolean
- *                    description: enable hide by owner
- *                  hideRestrictedByGroup:
- *                    type: boolean
- *                    description: enable hide by group
- *          SamlAuthSetting:
- *            type:object
- *              samlEntryPoint:
- *                type: string
- *                description: entry point for saml
- *              samlIssuer:
- *                type: string
- *                description: issuer for saml
- *              samlCert:
- *                type: string
- *                description: certificate for saml
- *              samlAttrMapId:
- *                type: string
- *                description: attribute mapping id for saml
- *              samlAttrMapUserName:
- *                type: string
- *                description: attribute mapping user name for saml
- *              samlAttrMapMail:
- *                type: string
- *                description: attribute mapping mail for saml
- *              samlAttrMapFirstName:
+ *      GeneralSetting:
+ *        type:object
+ *          GuestModeParams:
+ *            type: object
+ *            properties:
+ *              restrictGuestMode:
  *                type: string
  *                type: string
- *                description: attribute mapping first name for saml
- *              samlAttrMapLastName:
+ *                description: type of restrictGuestMode
+ *          PageDeletionParams:
+ *            type: object
+ *            properties:
+ *              pageCompleteDeletionAuthority:
  *                type: string
  *                type: string
- *                description: attribute mapping last name for saml
- *              isSameUsernameTreatedAsIdenticalUser
+ *                description: type of pageDeletionAuthority
+ *          Function:
+ *            type: object
+ *            properties:
+ *              hideRestrictedByOwner:
  *                type: boolean
  *                type: boolean
- *                description: local account automatically linked the user name matched
- *              isSameEmailTreatedAsIdenticalUser
+ *                description: enable hide by owner
+ *              hideRestrictedByGroup:
  *                type: boolean
  *                type: boolean
- *                description: local account automatically linked the email matched
- *          OidcAuthSetting:
- *            type:object
- *              oidcProviderName:
- *                type: string
- *                description: provider name for oidc
- *              oidcIssuerHost:
- *                type: string
- *                description: issuer host for oidc
- *              oidcClientId:
- *                type: string
- *                description: client id for oidc
- *              oidcClientSecret:
- *                type: string
- *                description: client secret for oidc
- *              oidcAttrMapId:
- *                type: string
- *                description: attr map id for oidc
- *              oidcAttrMapUserName:
- *                type: string
- *                description: attr map username for oidc
- *              oidcAttrMapName:
- *                type: string
- *                description: attr map name for oidc
- *              oidcAttrMapMail:
- *                type: string
- *                description: attr map mail for oidc
- *              isSameUsernameTreatedAsIdenticalUser
- *                type: boolean
- *                description: local account automatically linked the user name matched
- *              isSameEmailTreatedAsIdenticalUser
- *                type: boolean
- *                description: local account automatically linked the email matched
- *          BasicAuthSetting:
- *            type:object
- *              isSameUsernameTreatedAsIdenticalUser
- *                type: boolean
- *                description: local account automatically linked the email matched
- *          GitHubOAuthSetting:
- *            type:object
- *              githubClientId:
- *                type: string
- *                description: key of comsumer
- *              githubClientSecret:
- *                type: string
- *                description: password of comsumer
- *              isSameUsernameTreatedAsIdenticalUser
- *                type: boolean
- *                description: local account automatically linked the email matched
- *          GoogleOAuthSetting:
- *            type:object
- *              googleClientId:
- *                type: string
- *                description: key of comsumer
- *              googleClientSecret:
- *                type: string
- *                description: password of comsumer
- *              isSameUsernameTreatedAsIdenticalUser
- *                type: boolean
- *                description: local account automatically linked the email matched
- *          TwitterOAuthSetting:
- *            type:object
- *              twitterConsumerKey:
- *                type: string
- *                description: key of comsumer
- *              twitterConsumerSecret:
- *                type: string
- *                description: password of comsumer
- *              isSameUsernameTreatedAsIdenticalUser
- *                type: boolean
- *                description: local account automatically linked the email matched
+ *                description: enable hide by group
+ *      LdapAuthSetting:
+ *        type:object
+ *          serverUrl:
+ *            type: string
+ *            description: server url for ldap
+ *          isUserBind:
+ *            type: boolean
+ *            description: enable user bind
+ *          ldapBindDN:
+ *            type: string
+ *            description: the query used to bind with the directory service
+ *          ldapBindDNPassword:
+ *            type: string
+ *            description: the password that is entered in the login page will be used to bind
+ *          ldapSearchFilter:
+ *            type: string
+ *            description: the query used to locate the authenticated user
+ *          ldapAttrMapUsername:
+ *            type: string
+ *            description: specification of mappings for username when creating new users
+ *          isSameUsernameTreatedAsIdenticalUser:
+ *            type: boolean
+ *            description: local account automatically linked the user name matched
+ *          ldapAttrMapMail:
+ *            type: string
+ *            description: specification of mappings for mail address when creating new users
+ *          ldapAttrMapName:
+ *            type: string
+ *            description: Specification of mappings for full name address when creating new users
+ *          ldapGroupSearchBase:
+ *            type: string
+ *            description: the base DN from which to search for groups.
+ *          ldapGroupSearchFilter:
+ *            type: string
+ *            description: the query used to filter for groups
+ *          ldapGroupDnProperty:
+ *            type: string
+ *            description: The property of user object to use in dn interpolation of Group Search Filter
+ *      SamlAuthSetting:
+ *        type:object
+ *          samlEntryPoint:
+ *            type: string
+ *            description: entry point for saml
+ *          samlIssuer:
+ *            type: string
+ *            description: issuer for saml
+ *          samlCert:
+ *            type: string
+ *            description: certificate for saml
+ *          samlAttrMapId:
+ *            type: string
+ *            description: attribute mapping id for saml
+ *          samlAttrMapUserName:
+ *            type: string
+ *            description: attribute mapping user name for saml
+ *          samlAttrMapMail:
+ *            type: string
+ *            description: attribute mapping mail for saml
+ *          samlAttrMapFirstName:
+ *            type: string
+ *            description: attribute mapping first name for saml
+ *          samlAttrMapLastName:
+ *            type: string
+ *            description: attribute mapping last name for saml
+ *          isSameUsernameTreatedAsIdenticalUser
+ *            type: boolean
+ *            description: local account automatically linked the user name matched
+ *          isSameEmailTreatedAsIdenticalUser
+ *            type: boolean
+ *            description: local account automatically linked the email matched
+ *      OidcAuthSetting:
+ *        type:object
+ *          oidcProviderName:
+ *            type: string
+ *            description: provider name for oidc
+ *          oidcIssuerHost:
+ *            type: string
+ *            description: issuer host for oidc
+ *          oidcClientId:
+ *            type: string
+ *            description: client id for oidc
+ *          oidcClientSecret:
+ *            type: string
+ *            description: client secret for oidc
+ *          oidcAttrMapId:
+ *            type: string
+ *            description: attr map id for oidc
+ *          oidcAttrMapUserName:
+ *            type: string
+ *            description: attr map username for oidc
+ *          oidcAttrMapName:
+ *            type: string
+ *            description: attr map name for oidc
+ *          oidcAttrMapMail:
+ *            type: string
+ *            description: attr map mail for oidc
+ *          isSameUsernameTreatedAsIdenticalUser
+ *            type: boolean
+ *            description: local account automatically linked the user name matched
+ *          isSameEmailTreatedAsIdenticalUser
+ *            type: boolean
+ *            description: local account automatically linked the email matched
+ *      BasicAuthSetting:
+ *        type:object
+ *          isSameUsernameTreatedAsIdenticalUser
+ *            type: boolean
+ *            description: local account automatically linked the email matched
+ *      GitHubOAuthSetting:
+ *        type:object
+ *          githubClientId:
+ *            type: string
+ *            description: key of comsumer
+ *          githubClientSecret:
+ *            type: string
+ *            description: password of comsumer
+ *          isSameUsernameTreatedAsIdenticalUser
+ *            type: boolean
+ *            description: local account automatically linked the email matched
+ *      GoogleOAuthSetting:
+ *        type:object
+ *          googleClientId:
+ *            type: string
+ *            description: key of comsumer
+ *          googleClientSecret:
+ *            type: string
+ *            description: password of comsumer
+ *          isSameUsernameTreatedAsIdenticalUser
+ *            type: boolean
+ *            description: local account automatically linked the email matched
+ *      TwitterOAuthSetting:
+ *        type:object
+ *          twitterConsumerKey:
+ *            type: string
+ *            description: key of comsumer
+ *          twitterConsumerSecret:
+ *            type: string
+ *            description: password of comsumer
+ *          isSameUsernameTreatedAsIdenticalUser
+ *            type: boolean
+ *            description: local account automatically linked the email matched
  */
  */
 module.exports = (crowi) => {
 module.exports = (crowi) => {
   const loginRequiredStrictly = require('../../middleware/login-required')(crowi);
   const loginRequiredStrictly = require('../../middleware/login-required')(crowi);
@@ -222,14 +272,20 @@ module.exports = (crowi) => {
    *            content:
    *            content:
    *              application/json:
    *              application/json:
    *                schema:
    *                schema:
-   *                  properties:
-   *                    securityParams:
-   *                      $ref: '#/components/schemas/SecurityParams'
+   *                  $ref: '#/components/schemas/GeneralSetting'
+   *                  $ref: '#/components/schemas/LdapAuthSetting'
+   *                  $ref: '#/components/schemas/SamlAuthSetting'
+   *                  $ref: '#/components/schemas/OidcAuthSetting'
+   *                  $ref: '#/components/schemas/BasicAuthSetting'
+   *                  $ref: '#/components/schemas/GitHubOAuthSetting'
+   *                  $ref: '#/components/schemas/GoogleOAuthSetting'
+   *                  $ref: '#/components/schemas/TwitterOAuthSetting'
    */
    */
   router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
   router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
 
 
     const securityParams = {
     const securityParams = {
       generalAuth: {
       generalAuth: {
+        isLdapEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isEnabled'),
         isSamlEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-saml:isEnabled'),
         isSamlEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-saml:isEnabled'),
         isOidcEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:isEnabled'),
         isOidcEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:isEnabled'),
         isBasicEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-basic:isEnabled'),
         isBasicEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-basic:isEnabled'),
@@ -237,6 +293,20 @@ module.exports = (crowi) => {
         isGithubOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-github:isEnabled'),
         isGithubOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-github:isEnabled'),
         isTwitterOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:isEnabled'),
         isTwitterOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:isEnabled'),
       },
       },
+      ldapAuth: {
+        serverUrl: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:serverUrl'),
+        isUserBind: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isUserBind'),
+        ldapBindDN: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:bindDN'),
+        ldapBindDNPassword: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:bindDNPassword'),
+        ldapSearchFilter: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:searchFilter'),
+        ldapAttrMapUsername: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:attrMapUsername'),
+        isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isSameUsernameTreatedAsIdenticalUser'),
+        ldapAttrMapMail: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:attrMapMail'),
+        ldapAttrMapName: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:attrMapName'),
+        ldapGroupSearchBase: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:groupSearchBase'),
+        ldapGroupSearchFilter: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:groupSearchFilter'),
+        ldapGroupDnProperty: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:groupDnProperty'),
+      },
       samlAuth: {
       samlAuth: {
         samlEntryPoint: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:entryPoint'),
         samlEntryPoint: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:entryPoint'),
         samlEnvVarEntryPoint: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:entryPoint'),
         samlEnvVarEntryPoint: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:entryPoint'),
@@ -304,29 +374,14 @@ module.exports = (crowi) => {
    *          content:
    *          content:
    *            application/json:
    *            application/json:
    *              schema:
    *              schema:
-   *                type: object
-   *                properties:
-   *                  restrictGuestMode:
-   *                    description: type of restrictGuestMode
-   *                    type: string
-   *                  pageCompleteDeletionAuthority:
-   *                    type: string
-   *                    description: type of pageDeletionAuthority
-   *                  hideRestrictedByOwner:
-   *                    type: boolean
-   *                    description: enable hide by owner
-   *                  hideRestrictedByGroup:
-   *                    type: boolean
-   *                    description: enable hide by group
+   *                $ref: '#/components/schemas/GeneralSetting'
    *        responses:
    *        responses:
    *          200:
    *          200:
    *            description: Succeeded to update general Setting
    *            description: Succeeded to update general Setting
    *            content:
    *            content:
    *              application/json:
    *              application/json:
    *                schema:
    *                schema:
-   *                  properties:
-   *                    status:
-   *                      $ref: '#/components/schemas/SecurityParams/GeneralSetting'
+   *                  $ref: '#/components/schemas/GeneralSetting'
    */
    */
   router.put('/general-setting', loginRequiredStrictly, adminRequired, csrf, validator.generalSetting, ApiV3FormValidator, async(req, res) => {
   router.put('/general-setting', loginRequiredStrictly, adminRequired, csrf, validator.generalSetting, ApiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
@@ -353,6 +408,68 @@ module.exports = (crowi) => {
     }
     }
   });
   });
 
 
+  /**
+   * @swagger
+   *
+   *    /security-setting/ldap:
+   *      put:
+   *        tags: [SecuritySetting]
+   *        description: Update LDAP setting
+   *        requestBody:
+   *          required: true
+   *          content:
+   *            application/json:
+   *              schema:
+   *                $ref: '#/components/schemas/LdapAuthSetting'
+   *        responses:
+   *          200:
+   *            description: Succeeded to update LDAP setting
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  $ref: '#/components/schemas/LdapAuthSetting'
+   */
+  router.put('/ldap', loginRequiredStrictly, adminRequired, csrf, validator.ldapAuth, ApiV3FormValidator, async(req, res) => {
+    const requestParams = {
+      'security:passport-ldap:serverUrl': req.body.serverUrl,
+      'security:passport-ldap:isUserBind': req.body.isUserBind,
+      'security:passport-ldap:bindDN': req.body.ldapBindDN,
+      'security:passport-ldap:bindDNPassword': req.body.ldapBindDNPassword,
+      'security:passport-ldap:searchFilter': req.body.ldapSearchFilter,
+      'security:passport-ldap:attrMapUsername': req.body.ldapAttrMapUserName,
+      'security:passport-ldap:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
+      'security:passport-ldap:attrMapMail': req.body.ldapAttrMapMail,
+      'security:passport-ldap:attrMapName': req.body.ldapAttrMapName,
+      'security:passport-ldap:groupSearchBase': req.body.ldapGroupSearchBase,
+      'security:passport-ldap:groupSearchFilter': req.body.ldapGroupSearchFilter,
+      'security:passport-ldap:groupDnProperty': req.body.ldapGroupDnProperty,
+    };
+
+    try {
+      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      const securitySettingParams = {
+        serverUrl: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:serverUrl'),
+        isUserBind: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isUserBind'),
+        ldapBindDN: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:bindDN'),
+        ldapBindDNPassword: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:bindDNPassword'),
+        ldapSearchFilter: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:searchFilter'),
+        ldapAttrMapUsername: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:attrMapUsername'),
+        isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isSameUsernameTreatedAsIdenticalUser'),
+        ldapAttrMapMail: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:attrMapMail'),
+        ldapAttrMapName: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:attrMapName'),
+        ldapGroupSearchBase: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:groupSearchBase'),
+        ldapGroupSearchFilter: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:groupSearchFilter'),
+        ldapGroupDnProperty: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:groupDnProperty'),
+      };
+      return res.apiv3({ securitySettingParams });
+    }
+    catch (err) {
+      const msg = 'Error occurred in updating SAML setting';
+      logger.error('Error', err);
+      return res.apiv3Err(new ErrorV3(msg, 'update-SAML-failed'));
+    }
+  });
+
   /**
   /**
    * @swagger
    * @swagger
    *
    *
@@ -365,14 +482,14 @@ module.exports = (crowi) => {
    *          content:
    *          content:
    *            application/json:
    *            application/json:
    *              schema:
    *              schema:
-   *                $ref: '#/components/schemas/SecurityParams/SamlAuthSetting'
+   *                $ref: '#/components/schemas/SamlAuthSetting'
    *        responses:
    *        responses:
    *          200:
    *          200:
    *            description: Succeeded to update SAML setting
    *            description: Succeeded to update SAML setting
    *            content:
    *            content:
    *              application/json:
    *              application/json:
    *                schema:
    *                schema:
-   *                  $ref: '#/components/schemas/SecurityParams/SamlAuthSetting'
+   *                  $ref: '#/components/schemas/SamlAuthSetting'
    */
    */
   router.put('/saml', loginRequiredStrictly, adminRequired, csrf, validator.samlAuth, ApiV3FormValidator, async(req, res) => {
   router.put('/saml', loginRequiredStrictly, adminRequired, csrf, validator.samlAuth, ApiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
@@ -423,14 +540,14 @@ module.exports = (crowi) => {
    *          content:
    *          content:
    *            application/json:
    *            application/json:
    *              schema:
    *              schema:
-   *                $ref: '#/components/schemas/SecurityParams/OidcAuthSetting'
+   *                $ref: '#/components/schemas/OidcAuthSetting'
    *        responses:
    *        responses:
    *          200:
    *          200:
    *            description: Succeeded to update OpenID Connect setting
    *            description: Succeeded to update OpenID Connect setting
    *            content:
    *            content:
    *              application/json:
    *              application/json:
    *                schema:
    *                schema:
-   *                  $ref: '#/components/schemas/SecurityParams/OidcAuthSetting'
+   *                  $ref: '#/components/schemas/OidcAuthSetting'
    */
    */
   router.put('/oidc', loginRequiredStrictly, adminRequired, csrf, validator.oidcAuth, ApiV3FormValidator, async(req, res) => {
   router.put('/oidc', loginRequiredStrictly, adminRequired, csrf, validator.oidcAuth, ApiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
@@ -481,14 +598,14 @@ module.exports = (crowi) => {
    *          content:
    *          content:
    *            application/json:
    *            application/json:
    *              schema:
    *              schema:
-   *                $ref: '#/components/schemas/SecurityParams/BasicAuthSetting'
+   *                $ref: '#/components/schemas/BasicAuthSetting'
    *        responses:
    *        responses:
    *          200:
    *          200:
    *            description: Succeeded to update basic
    *            description: Succeeded to update basic
    *            content:
    *            content:
    *              application/json:
    *              application/json:
    *                schema:
    *                schema:
-   *                  $ref: '#/components/schemas/SecurityParams/BasicAuthSetting'
+   *                  $ref: '#/components/schemas/BasicAuthSetting'
    */
    */
   router.put('/basic', loginRequiredStrictly, adminRequired, csrf, validator.basicAuth, ApiV3FormValidator, async(req, res) => {
   router.put('/basic', loginRequiredStrictly, adminRequired, csrf, validator.basicAuth, ApiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
@@ -521,14 +638,14 @@ module.exports = (crowi) => {
    *          content:
    *          content:
    *            application/json:
    *            application/json:
    *              schema:
    *              schema:
-   *                $ref: '#/components/schemas/SecurityParams/GoogleOAuthSetting'
+   *                $ref: '#/components/schemas/GoogleOAuthSetting'
    *        responses:
    *        responses:
    *          200:
    *          200:
    *            description: Succeeded to google OAuth
    *            description: Succeeded to google OAuth
    *            content:
    *            content:
    *              application/json:
    *              application/json:
    *                schema:
    *                schema:
-   *                  $ref: '#/components/schemas/SecurityParams/GoogleOAuthSetting'
+   *                  $ref: '#/components/schemas/GoogleOAuthSetting'
    */
    */
   router.put('/google-oauth', loginRequiredStrictly, adminRequired, csrf, validator.googleOAuth, ApiV3FormValidator, async(req, res) => {
   router.put('/google-oauth', loginRequiredStrictly, adminRequired, csrf, validator.googleOAuth, ApiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
@@ -565,14 +682,14 @@ module.exports = (crowi) => {
    *          content:
    *          content:
    *            application/json:
    *            application/json:
    *              schema:
    *              schema:
-   *                $ref: '#/components/schemas/SecurityParams/GitHubOAuthSetting'
+   *                $ref: '#/components/schemas/GitHubOAuthSetting'
    *        responses:
    *        responses:
    *          200:
    *          200:
    *            description: Succeeded to github OAuth
    *            description: Succeeded to github OAuth
    *            content:
    *            content:
    *              application/json:
    *              application/json:
    *                schema:
    *                schema:
-   *                  $ref: '#/components/schemas/SecurityParams/GitHubOAuthSetting'
+   *                  $ref: '#/components/schemas/GitHubOAuthSetting'
    */
    */
   router.put('/github-oauth', loginRequiredStrictly, adminRequired, csrf, validator.githubOAuth, ApiV3FormValidator, async(req, res) => {
   router.put('/github-oauth', loginRequiredStrictly, adminRequired, csrf, validator.githubOAuth, ApiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {
@@ -609,14 +726,14 @@ module.exports = (crowi) => {
    *          content:
    *          content:
    *            application/json:
    *            application/json:
    *              schema:
    *              schema:
-   *                $ref: '#/components/schemas/SecurityParams/TwitterOAuthSetting'
+   *                $ref: '#/components/schemas/TwitterOAuthSetting'
    *        responses:
    *        responses:
    *          200:
    *          200:
    *            description: Succeeded to update twitter OAuth
    *            description: Succeeded to update twitter OAuth
    *            content:
    *            content:
    *              application/json:
    *              application/json:
    *                schema:
    *                schema:
-   *                  $ref: '#/components/schemas/SecurityParams/TwitterOAuthSetting'
+   *                  $ref: '#/components/schemas/TwitterOAuthSetting'
    */
    */
   router.put('/twitter-oauth', loginRequiredStrictly, adminRequired, csrf, validator.twitterOAuth, ApiV3FormValidator, async(req, res) => {
   router.put('/twitter-oauth', loginRequiredStrictly, adminRequired, csrf, validator.twitterOAuth, ApiV3FormValidator, async(req, res) => {
     const requestParams = {
     const requestParams = {