security-setting.js 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213
  1. import { ErrorV3 } from '@growi/core';
  2. import { SupportedAction } from '~/interfaces/activity';
  3. import { PageDeleteConfigValue } from '~/interfaces/page-delete-config';
  4. import loggerFactory from '~/utils/logger';
  5. import { removeNullPropertyFromObject } from '~/utils/object-utils';
  6. import { validateDeleteConfigs, prepareDeleteConfigValuesForCalc } from '~/utils/page-delete-config';
  7. import { generateAddActivityMiddleware } from '../../middlewares/add-activity';
  8. import { apiV3FormValidator } from '../../middlewares/apiv3-form-validator';
  9. import { GrowiExternalAuthProviderType } from '~/features/questionnaire/interfaces/growi-info';
  10. import { configManager } from '../../service/config-manager';
  11. const logger = loggerFactory('growi:routes:apiv3:security-setting');
  12. const express = require('express');
  13. const router = express.Router();
  14. const { body } = require('express-validator');
  15. const validator = {
  16. generalSetting: [
  17. body('sessionMaxAge').optional({ checkFalsy: true }).trim().isInt(),
  18. body('restrictGuestMode').if(value => value != null).isString().isIn([
  19. 'Deny', 'Readonly',
  20. ]),
  21. body('pageCompleteDeletionAuthority').if(value => value != null).isString().isIn(Object.values(PageDeleteConfigValue)),
  22. body('hideRestrictedByOwner').if(value => value != null).isBoolean(),
  23. body('hideRestrictedByGroup').if(value => value != null).isBoolean(),
  24. ],
  25. shareLinkSetting: [
  26. body('disableLinkSharing').if(value => value != null).isBoolean(),
  27. ],
  28. authenticationSetting: [
  29. body('isEnabled').if(value => value != null).isBoolean(),
  30. body('authId').isString().isIn([
  31. 'local', 'ldap', 'saml', 'oidc', 'google', 'github',
  32. ]),
  33. ],
  34. localSetting: [
  35. body('registrationMode').isString().isIn([
  36. 'Open', 'Restricted', 'Closed',
  37. ]),
  38. body('registrationWhitelist').if(value => value != null).isArray().customSanitizer((value, { req }) => {
  39. return value.filter(email => email !== '');
  40. }),
  41. ],
  42. ldapAuth: [
  43. body('serverUrl').if(value => value != null).isString(),
  44. body('isUserBind').if(value => value != null).isBoolean(),
  45. body('ldapBindDN').if(value => value != null).isString(),
  46. body('ldapBindDNPassword').if(value => value != null).isString(),
  47. body('ldapSearchFilter').if(value => value != null).isString(),
  48. body('ldapAttrMapUsername').if(value => value != null).isString(),
  49. body('isSameUsernameTreatedAsIdenticalUser').if(value => value != null).isBoolean(),
  50. body('ldapAttrMapMail').if(value => value != null).isString(),
  51. body('ldapAttrMapName').if(value => value != null).isString(),
  52. body('ldapGroupSearchBase').if(value => value != null).isString(),
  53. body('ldapGroupSearchFilter').if(value => value != null).isString(),
  54. body('ldapGroupDnProperty').if(value => value != null).isString(),
  55. ],
  56. samlAuth: [
  57. body('entryPoint').if(value => value != null).isString(),
  58. body('issuer').if(value => value != null).isString(),
  59. body('cert').if(value => value != null).isString(),
  60. body('attrMapId').if(value => value != null).isString(),
  61. body('attrMapUsername').if(value => value != null).isString(),
  62. body('attrMapMail').if(value => value != null).isString(),
  63. body('attrMapFirstName').if(value => value != null).isString(),
  64. body('attrMapLastName').if(value => value != null).isString(),
  65. body('isSameUsernameTreatedAsIdenticalUser').if(value => value != null).isBoolean(),
  66. body('isSameEmailTreatedAsIdenticalUser').if(value => value != null).isBoolean(),
  67. body('ABLCRule').if(value => value != null).isString(),
  68. ],
  69. oidcAuth: [
  70. body('oidcProviderName').if(value => value != null).isString(),
  71. body('oidcIssuerHost').if(value => value != null).isString(),
  72. body('oidcAuthorizationEndpoint').if(value => value != null).isString(),
  73. body('oidcTokenEndpoint').if(value => value != null).isString(),
  74. body('oidcRevocationEndpoint').if(value => value != null).isString(),
  75. body('oidcIntrospectionEndpoint').if(value => value != null).isString(),
  76. body('oidcUserInfoEndpoint').if(value => value != null).isString(),
  77. body('oidcEndSessionEndpoint').if(value => value != null).isString(),
  78. body('oidcRegistrationEndpoint').if(value => value != null).isString(),
  79. body('oidcJWKSUri').if(value => value != null).isString(),
  80. body('oidcClientId').if(value => value != null).isString(),
  81. body('oidcClientSecret').if(value => value != null).isString(),
  82. body('oidcAttrMapId').if(value => value != null).isString(),
  83. body('oidcAttrMapUserName').if(value => value != null).isString(),
  84. body('oidcAttrMapEmail').if(value => value != null).isString(),
  85. body('isSameUsernameTreatedAsIdenticalUser').if(value => value != null).isBoolean(),
  86. body('isSameEmailTreatedAsIdenticalUser').if(value => value != null).isBoolean(),
  87. ],
  88. googleOAuth: [
  89. body('googleClientId').if(value => value != null).isString(),
  90. body('googleClientSecret').if(value => value != null).isString(),
  91. body('isSameUsernameTreatedAsIdenticalUser').if(value => value != null).isBoolean(),
  92. ],
  93. githubOAuth: [
  94. body('githubClientId').if(value => value != null).isString(),
  95. body('githubClientSecret').if(value => value != null).isString(),
  96. body('isSameUsernameTreatedAsIdenticalUser').if(value => value != null).isBoolean(),
  97. ],
  98. };
  99. /**
  100. * @swagger
  101. * tags:
  102. * name: SecuritySetting
  103. */
  104. /**
  105. * @swagger
  106. *
  107. * components:
  108. * schemas:
  109. * GeneralSetting:
  110. * type: object
  111. * properties:
  112. * restrictGuestMode:
  113. * type: string
  114. * description: type of restrictGuestMode
  115. * pageCompleteDeletionAuthority:
  116. * type: string
  117. * description: type of pageDeletionAuthority
  118. * hideRestrictedByOwner:
  119. * type: boolean
  120. * description: enable hide by owner
  121. * hideRestrictedByGroup:
  122. * type: boolean
  123. * description: enable hide by group
  124. * ShareLinkSetting:
  125. * type: object
  126. * properties:
  127. * disableLinkSharing:
  128. * type: boolean
  129. * description: disable link sharing
  130. * LocalSetting:
  131. * type: object
  132. * properties:
  133. * isLocalEnabled:
  134. * type: boolean
  135. * description: local setting mode
  136. * registrationMode:
  137. * type: string
  138. * description: type of registrationMode
  139. * registrationWhitelist:
  140. * type: array
  141. * description: array of regsitrationList
  142. * items:
  143. * type: string
  144. * description: registration whitelist
  145. * LdapAuthSetting:
  146. * type: object
  147. * properties:
  148. * serverUrl:
  149. * type: string
  150. * description: server url for ldap
  151. * isUserBind:
  152. * type: boolean
  153. * description: enable user bind
  154. * ldapBindDN:
  155. * type: string
  156. * description: the query used to bind with the directory service
  157. * ldapBindDNPassword:
  158. * type: string
  159. * description: the password that is entered in the login page will be used to bind
  160. * ldapSearchFilter:
  161. * type: string
  162. * description: the query used to locate the authenticated user
  163. * ldapAttrMapUsername:
  164. * type: string
  165. * description: specification of mappings for username when creating new users
  166. * isSameUsernameTreatedAsIdenticalUser:
  167. * type: boolean
  168. * description: local account automatically linked the user name matched
  169. * ldapAttrMapMail:
  170. * type: string
  171. * description: specification of mappings for mail address when creating new users
  172. * ldapAttrMapName:
  173. * type: string
  174. * description: Specification of mappings for full name address when creating new users
  175. * ldapGroupSearchBase:
  176. * type: string
  177. * description: the base DN from which to search for groups.
  178. * ldapGroupSearchFilter:
  179. * type: string
  180. * description: the query used to filter for groups
  181. * ldapGroupDnProperty:
  182. * type: string
  183. * description: The property of user object to use in dn interpolation of Group Search Filter
  184. * SamlAuthSetting:
  185. * type: object
  186. * properties:
  187. * samlEntryPoint:
  188. * type: string
  189. * description: entry point for saml
  190. * samlIssuer:
  191. * type: string
  192. * description: issuer for saml
  193. * samlCert:
  194. * type: string
  195. * description: certificate for saml
  196. * samlAttrMapId:
  197. * type: string
  198. * description: attribute mapping id for saml
  199. * samlAttrMapUserName:
  200. * type: string
  201. * description: attribute mapping user name for saml
  202. * samlAttrMapMail:
  203. * type: string
  204. * description: attribute mapping mail for saml
  205. * samlAttrMapFirstName:
  206. * type: string
  207. * description: attribute mapping first name for saml
  208. * samlAttrMapLastName:
  209. * type: string
  210. * description: attribute mapping last name for saml
  211. * isSameUsernameTreatedAsIdenticalUser:
  212. * type: boolean
  213. * description: local account automatically linked the user name matched
  214. * isSameEmailTreatedAsIdenticalUser:
  215. * type: boolean
  216. * description: local account automatically linked the email matched
  217. * samlABLCRule:
  218. * type: string
  219. * description: ABLCRule for saml
  220. * OidcAuthSetting:
  221. * type: object
  222. * properties:
  223. * oidcProviderName:
  224. * type: string
  225. * description: provider name for oidc
  226. * oidcIssuerHost:
  227. * type: string
  228. * description: issuer host for oidc
  229. * oidcAuthorizationEndpoint:
  230. * type: string
  231. * description: authorization endpoint for oidc
  232. * oidcTokenEndpoint:
  233. * type: string
  234. * description: token endpoint for oidc
  235. * oidcRevocationEndpoint:
  236. * type: string
  237. * description: revocation endpoint for oidc
  238. * oidcIntrospectionEndpoint:
  239. * type: string
  240. * description: introspection endpoint for oidc
  241. * oidcUserInfoEndpoint:
  242. * type: string
  243. * description: userinfo endpoint for oidc
  244. * oidcEndSessionEndpoint:
  245. * type: string
  246. * description: end session endpoint for oidc
  247. * oidcRegistrationEndpoint:
  248. * type: string
  249. * description: registration endpoint for oidc
  250. * oidcJWKSUri:
  251. * type: string
  252. * description: JSON Web Key Set URI for oidc
  253. * oidcClientId:
  254. * type: string
  255. * description: client id for oidc
  256. * oidcClientSecret:
  257. * type: string
  258. * description: client secret for oidc
  259. * oidcAttrMapId:
  260. * type: string
  261. * description: attr map id for oidc
  262. * oidcAttrMapUserName:
  263. * type: string
  264. * description: attr map username for oidc
  265. * oidcAttrMapName:
  266. * type: string
  267. * description: attr map name for oidc
  268. * oidcAttrMapMail:
  269. * type: string
  270. * description: attr map mail for oidc
  271. * isSameUsernameTreatedAsIdenticalUser:
  272. * type: boolean
  273. * description: local account automatically linked the user name matched
  274. * isSameEmailTreatedAsIdenticalUser:
  275. * type: boolean
  276. * description: local account automatically linked the email matched
  277. * GitHubOAuthSetting:
  278. * type: object
  279. * properties:
  280. * githubClientId:
  281. * type: string
  282. * description: key of comsumer
  283. * githubClientSecret:
  284. * type: string
  285. * description: password of comsumer
  286. * isSameUsernameTreatedAsIdenticalUser:
  287. * type: boolean
  288. * description: local account automatically linked the email matched
  289. * GoogleOAuthSetting:
  290. * type: object
  291. * properties:
  292. * googleClientId:
  293. * type: string
  294. * description: key of comsumer
  295. * googleClientSecret:
  296. * type: string
  297. * description: password of comsumer
  298. * isSameUsernameTreatedAsIdenticalUser:
  299. * type: boolean
  300. * description: local account automatically linked the email matched
  301. */
  302. module.exports = (crowi) => {
  303. const loginRequiredStrictly = require('../../middlewares/login-required')(crowi);
  304. const adminRequired = require('../../middlewares/admin-required')(crowi);
  305. const addActivity = generateAddActivityMiddleware(crowi);
  306. const activityEvent = crowi.event('activity');
  307. async function updateAndReloadStrategySettings(authId, params) {
  308. const { configManager, passportService } = crowi;
  309. // update config without publishing S2sMessage
  310. await configManager.updateConfigsInTheSameNamespace('crowi', params, true);
  311. await passportService.setupStrategyById(authId);
  312. passportService.publishUpdatedMessage(authId);
  313. }
  314. /**
  315. * @swagger
  316. *
  317. * /_api/v3/security-setting/:
  318. * get:
  319. * tags: [SecuritySetting, apiv3]
  320. * description: Get security paramators
  321. * responses:
  322. * 200:
  323. * description: params of security
  324. * content:
  325. * application/json:
  326. * schema:
  327. * properties:
  328. * securityParams:
  329. * type: object
  330. * description: security params
  331. */
  332. router.get('/', loginRequiredStrictly, adminRequired, async(req, res) => {
  333. const securityParams = {
  334. generalSetting: {
  335. restrictGuestMode: crowi.aclService.getGuestModeValue(),
  336. pageDeletionAuthority: await crowi.configManager.getConfig('crowi', 'security:pageDeletionAuthority'),
  337. pageCompleteDeletionAuthority: await crowi.configManager.getConfig('crowi', 'security:pageCompleteDeletionAuthority'),
  338. pageRecursiveDeletionAuthority: await crowi.configManager.getConfig('crowi', 'security:pageRecursiveDeletionAuthority'),
  339. pageRecursiveCompleteDeletionAuthority: await crowi.configManager.getConfig('crowi', 'security:pageRecursiveCompleteDeletionAuthority'),
  340. hideRestrictedByOwner: await crowi.configManager.getConfig('crowi', 'security:list-policy:hideRestrictedByOwner'),
  341. hideRestrictedByGroup: await crowi.configManager.getConfig('crowi', 'security:list-policy:hideRestrictedByGroup'),
  342. wikiMode: await crowi.configManager.getConfig('crowi', 'security:wikiMode'),
  343. sessionMaxAge: await crowi.configManager.getConfig('crowi', 'security:sessionMaxAge'),
  344. },
  345. shareLinkSetting: {
  346. disableLinkSharing: await crowi.configManager.getConfig('crowi', 'security:disableLinkSharing'),
  347. },
  348. localSetting: {
  349. useOnlyEnvVarsForSomeOptions: await crowi.configManager.getConfig('crowi', 'security:passport-local:useOnlyEnvVarsForSomeOptions'),
  350. registrationMode: await crowi.configManager.getConfig('crowi', 'security:registrationMode'),
  351. registrationWhitelist: await crowi.configManager.getConfig('crowi', 'security:registrationWhitelist'),
  352. isPasswordResetEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-local:isPasswordResetEnabled'),
  353. isEmailAuthenticationEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-local:isEmailAuthenticationEnabled'),
  354. },
  355. generalAuth: {
  356. isLocalEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-local:isEnabled'),
  357. isLdapEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isEnabled'),
  358. isSamlEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-saml:isEnabled'),
  359. isOidcEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:isEnabled'),
  360. isGoogleEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-google:isEnabled'),
  361. isGitHubEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-github:isEnabled'),
  362. },
  363. ldapAuth: {
  364. serverUrl: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:serverUrl'),
  365. isUserBind: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isUserBind'),
  366. ldapBindDN: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:bindDN'),
  367. ldapBindDNPassword: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:bindDNPassword'),
  368. ldapSearchFilter: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:searchFilter'),
  369. ldapAttrMapUsername: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:attrMapUsername'),
  370. isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isSameUsernameTreatedAsIdenticalUser'),
  371. ldapAttrMapMail: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:attrMapMail'),
  372. ldapAttrMapName: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:attrMapName'),
  373. ldapGroupSearchBase: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:groupSearchBase'),
  374. ldapGroupSearchFilter: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:groupSearchFilter'),
  375. ldapGroupDnProperty: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:groupDnProperty'),
  376. },
  377. samlAuth: {
  378. missingMandatoryConfigKeys: await crowi.passportService.getSamlMissingMandatoryConfigKeys(),
  379. useOnlyEnvVarsForSomeOptions: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:useOnlyEnvVarsForSomeOptions'),
  380. samlEntryPoint: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:entryPoint'),
  381. samlEnvVarEntryPoint: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:entryPoint'),
  382. samlIssuer: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:issuer'),
  383. samlEnvVarIssuer: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:issuer'),
  384. samlCert: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:cert'),
  385. samlEnvVarCert: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:cert'),
  386. samlAttrMapId: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:attrMapId'),
  387. samlEnvVarAttrMapId: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:attrMapId'),
  388. samlAttrMapUsername: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:attrMapUsername'),
  389. samlEnvVarAttrMapUsername: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:attrMapUsername'),
  390. samlAttrMapMail: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:attrMapMail'),
  391. samlEnvVarAttrMapMail: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:attrMapMail'),
  392. samlAttrMapFirstName: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:attrMapFirstName'),
  393. samlEnvVarAttrMapFirstName: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:attrMapFirstName'),
  394. samlAttrMapLastName: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:attrMapLastName'),
  395. samlEnvVarAttrMapLastName: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:attrMapLastName'),
  396. isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-saml:isSameUsernameTreatedAsIdenticalUser'),
  397. isSameEmailTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-saml:isSameEmailTreatedAsIdenticalUser'),
  398. samlABLCRule: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:ABLCRule'),
  399. samlEnvVarABLCRule: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:ABLCRule'),
  400. },
  401. oidcAuth: {
  402. oidcProviderName: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:providerName'),
  403. oidcIssuerHost: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:issuerHost'),
  404. oidcAuthorizationEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:authorizationEndpoint'),
  405. oidcTokenEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:tokenEndpoint'),
  406. oidcRevocationEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:revocationEndpoint'),
  407. oidcIntrospectionEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:introspectionEndpoint'),
  408. oidcUserInfoEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:userInfoEndpoint'),
  409. oidcEndSessionEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:endSessionEndpoint'),
  410. oidcRegistrationEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:registrationEndpoint'),
  411. oidcJWKSUri: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:jwksUri'),
  412. oidcClientId: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:clientId'),
  413. oidcClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:clientSecret'),
  414. oidcAttrMapId: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:attrMapId'),
  415. oidcAttrMapUserName: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:attrMapUserName'),
  416. oidcAttrMapName: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:attrMapName'),
  417. oidcAttrMapEmail: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:attrMapMail'),
  418. isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:isSameUsernameTreatedAsIdenticalUser'),
  419. isSameEmailTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:isSameEmailTreatedAsIdenticalUser'),
  420. },
  421. googleOAuth: {
  422. googleClientId: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientId'),
  423. googleClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientSecret'),
  424. isSameEmailTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-google:isSameEmailTreatedAsIdenticalUser'),
  425. },
  426. githubOAuth: {
  427. githubClientId: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientId'),
  428. githubClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientSecret'),
  429. isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-github:isSameUsernameTreatedAsIdenticalUser'),
  430. },
  431. };
  432. return res.apiv3({ securityParams });
  433. });
  434. /**
  435. * @swagger
  436. *
  437. * /_api/v3/security-setting/authentication/enabled:
  438. * put:
  439. * tags: [SecuritySetting, apiv3]
  440. * description: Update authentication isEnabled
  441. * requestBody:
  442. * required: true
  443. * content:
  444. * application/json:
  445. * schema:
  446. * type: object
  447. * properties:
  448. * isEnabled:
  449. * type: boolean
  450. * target:
  451. * type: string
  452. * responses:
  453. * 200:
  454. * description: Succeeded to enable authentication
  455. * content:
  456. * application/json:
  457. * schema:
  458. * type: object
  459. * description: updated param
  460. */
  461. // eslint-disable-next-line max-len
  462. router.put('/authentication/enabled', loginRequiredStrictly, adminRequired, addActivity, validator.authenticationSetting, apiV3FormValidator, async(req, res) => {
  463. const { isEnabled, authId } = req.body;
  464. const ExternalAccount = crowi.model('ExternalAccount');
  465. const User = crowi.model('User');
  466. let setupStrategies = await crowi.passportService.getSetupStrategies();
  467. const parameters = {};
  468. // Reflect request param
  469. setupStrategies = setupStrategies.filter(strategy => strategy !== authId);
  470. if (setupStrategies.length === 0) {
  471. return res.apiv3Err(new ErrorV3('Can not turn everything off'), 405);
  472. }
  473. const allActiveAuthMethodsWithAdmin = await getAllActiveAuthMethodsWithAdmin();
  474. // Return an error when disabling an authentication method when there are no active authentication methods with admin-enabled login
  475. if (!isEnabled && allActiveAuthMethodsWithAdmin.length === 0) {
  476. return res.apiv3Err(new ErrorV3('Must have admin enabled authentication method'), 405);
  477. }
  478. // Get all authentication methods that have admin users
  479. async function getAllActiveAuthMethodsWithAdmin() {
  480. const activeAuthMethodsWithAdmin = [];
  481. // Check the local auth method
  482. await checkAndAddActiveAuthMethodWithAdmin('local', 'crowi', 'security:passport-local:isEnabled', checkLocalStrategyHasAdmin, activeAuthMethodsWithAdmin);
  483. // Check external auth methods
  484. const externalAuthTypes = Object.values(GrowiExternalAuthProviderType);
  485. await Promise.all(externalAuthTypes.map(async(strategy) => {
  486. const configKey = `security:passport-${strategy}:isEnabled`;
  487. await checkAndAddActiveAuthMethodWithAdmin(strategy, 'crowi', configKey, checkExternalStrategyHasAdmin, activeAuthMethodsWithAdmin);
  488. }));
  489. return activeAuthMethodsWithAdmin;
  490. }
  491. // Check and add an authentication method with admin to the list
  492. async function checkAndAddActiveAuthMethodWithAdmin(strategy, configNamespace, configKey, checkHasAdminFunction, activeAuthMethodsWithAdmin) {
  493. const isEnabled = configManager.getConfig(configNamespace, configKey);
  494. const hasAdmin = await checkHasAdminFunction(strategy);
  495. if (isEnabled && hasAdmin && setupStrategies.includes(strategy)) {
  496. activeAuthMethodsWithAdmin.push(strategy);
  497. }
  498. }
  499. // Check if local accounts have admins
  500. async function checkLocalStrategyHasAdmin() {
  501. // Get all local admin accounts and filter local admins that are not in external accounts
  502. const adminAccounts = await User.aggregate([
  503. { $match: { admin: true } },
  504. {
  505. $lookup: {
  506. from: 'externalaccounts',
  507. localField: '_id',
  508. foreignField: 'user',
  509. as: 'externalAccounts',
  510. },
  511. },
  512. { $match: { externalAccounts: [] } },
  513. ]);
  514. return adminAccounts.length > 0;
  515. }
  516. // Check if external accounts have admins
  517. async function checkExternalStrategyHasAdmin(providerType) {
  518. const externalAccounts = await ExternalAccount.find({ providerType }).populate('user').exec();
  519. return externalAccounts.some(externalAccount => externalAccount.user && externalAccount.user.admin);
  520. }
  521. const enableParams = { [`security:passport-${authId}:isEnabled`]: isEnabled };
  522. try {
  523. await updateAndReloadStrategySettings(authId, enableParams);
  524. const responseParams = {
  525. [`security:passport-${authId}:isEnabled`]: await crowi.configManager.getConfig('crowi', `security:passport-${authId}:isEnabled`),
  526. };
  527. switch (authId) {
  528. case 'local':
  529. if (isEnabled) {
  530. parameters.action = SupportedAction.ACTION_ADMIN_AUTH_ID_PASS_ENABLED;
  531. break;
  532. }
  533. parameters.action = SupportedAction.ACTION_ADMIN_AUTH_ID_PASS_DISABLED;
  534. break;
  535. case 'ldap':
  536. if (isEnabled) {
  537. parameters.action = SupportedAction.ACTION_ADMIN_AUTH_LDAP_ENABLED;
  538. break;
  539. }
  540. parameters.action = SupportedAction.ACTION_ADMIN_AUTH_LDAP_DISABLED;
  541. break;
  542. case 'saml':
  543. if (isEnabled) {
  544. parameters.action = SupportedAction.ACTION_ADMIN_AUTH_SAML_ENABLED;
  545. break;
  546. }
  547. parameters.action = SupportedAction.ACTION_ADMIN_AUTH_SAML_DISABLED;
  548. break;
  549. case 'oidc':
  550. if (isEnabled) {
  551. parameters.action = SupportedAction.ACTION_ADMIN_AUTH_OIDC_ENABLED;
  552. break;
  553. }
  554. parameters.action = SupportedAction.ACTION_ADMIN_AUTH_OIDC_DISABLED;
  555. break;
  556. case 'google':
  557. if (isEnabled) {
  558. parameters.action = SupportedAction.ACTION_ADMIN_AUTH_GOOGLE_ENABLED;
  559. break;
  560. }
  561. parameters.action = SupportedAction.ACTION_ADMIN_AUTH_GOOGLE_DISABLED;
  562. break;
  563. case 'github':
  564. if (isEnabled) {
  565. parameters.action = SupportedAction.ACTION_ADMIN_AUTH_GITHUB_ENABLED;
  566. break;
  567. }
  568. parameters.action = SupportedAction.ACTION_ADMIN_AUTH_GITHUB_DISABLED;
  569. break;
  570. }
  571. activityEvent.emit('update', res.locals.activity._id, parameters);
  572. return res.apiv3({ responseParams });
  573. }
  574. catch (err) {
  575. const msg = 'Error occurred in updating enable setting';
  576. logger.error('Error', err);
  577. return res.apiv3Err(new ErrorV3(msg, 'update-enable-setting failed'));
  578. }
  579. });
  580. /**
  581. * @swagger
  582. *
  583. * /_api/v3/security-setting/authentication:
  584. * get:
  585. * tags: [SecuritySetting, apiv3]
  586. * description: Get setup strategies for passport
  587. * responses:
  588. * 200:
  589. * description: params of setup strategies
  590. * content:
  591. * application/json:
  592. * schema:
  593. * properties:
  594. * setupStrategies:
  595. * type: array
  596. * description: setup strategies list
  597. * items:
  598. * type: string
  599. * description: setup strategie
  600. * example: ["local"]
  601. */
  602. router.get('/authentication/', loginRequiredStrictly, adminRequired, async(req, res) => {
  603. const setupStrategies = await crowi.passportService.getSetupStrategies();
  604. return res.apiv3({ setupStrategies });
  605. });
  606. /**
  607. * @swagger
  608. *
  609. * /_api/v3/security-setting/general-setting:
  610. * put:
  611. * tags: [SecuritySetting, apiv3]
  612. * description: Update GeneralSetting
  613. * requestBody:
  614. * required: true
  615. * content:
  616. * application/json:
  617. * schema:
  618. * $ref: '#/components/schemas/GeneralSetting'
  619. * responses:
  620. * 200:
  621. * description: Succeeded to update general Setting
  622. * content:
  623. * application/json:
  624. * schema:
  625. * $ref: '#/components/schemas/GeneralSetting'
  626. */
  627. router.put('/general-setting', loginRequiredStrictly, adminRequired, addActivity, validator.generalSetting, apiV3FormValidator, async(req, res) => {
  628. const updateData = {
  629. 'security:sessionMaxAge': parseInt(req.body.sessionMaxAge),
  630. 'security:restrictGuestMode': req.body.restrictGuestMode,
  631. 'security:pageDeletionAuthority': req.body.pageDeletionAuthority,
  632. 'security:pageRecursiveDeletionAuthority': req.body.pageRecursiveDeletionAuthority,
  633. 'security:pageCompleteDeletionAuthority': req.body.pageCompleteDeletionAuthority,
  634. 'security:pageRecursiveCompleteDeletionAuthority': req.body.pageRecursiveCompleteDeletionAuthority,
  635. 'security:list-policy:hideRestrictedByOwner': req.body.hideRestrictedByOwner,
  636. 'security:list-policy:hideRestrictedByGroup': req.body.hideRestrictedByGroup,
  637. };
  638. // Validate delete config
  639. const [singleAuthority1, recursiveAuthority1] = prepareDeleteConfigValuesForCalc(req.body.pageDeletionAuthority, req.body.pageRecursiveDeletionAuthority);
  640. // eslint-disable-next-line max-len
  641. const [singleAuthority2, recursiveAuthority2] = prepareDeleteConfigValuesForCalc(req.body.pageCompleteDeletionAuthority, req.body.pageRecursiveCompleteDeletionAuthority);
  642. const isDeleteConfigNormalized = validateDeleteConfigs(singleAuthority1, recursiveAuthority1)
  643. && validateDeleteConfigs(singleAuthority2, recursiveAuthority2);
  644. if (!isDeleteConfigNormalized) {
  645. return res.apiv3Err(new ErrorV3('Delete config values are not correct.', 'delete_config_not_normalized'));
  646. }
  647. const wikiMode = await crowi.configManager.getConfig('crowi', 'security:wikiMode');
  648. if (wikiMode === 'private' || wikiMode === 'public') {
  649. logger.debug('security:restrictGuestMode will not be changed because wiki mode is forced to set');
  650. delete updateData['security:restrictGuestMode'];
  651. }
  652. try {
  653. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', updateData);
  654. const securitySettingParams = {
  655. sessionMaxAge: await crowi.configManager.getConfig('crowi', 'security:sessionMaxAge'),
  656. restrictGuestMode: await crowi.configManager.getConfig('crowi', 'security:restrictGuestMode'),
  657. pageDeletionAuthority: await crowi.configManager.getConfig('crowi', 'security:pageDeletionAuthority'),
  658. pageCompleteDeletionAuthority: await crowi.configManager.getConfig('crowi', 'security:pageCompleteDeletionAuthority'),
  659. pageRecursiveDeletionAuthority: await crowi.configManager.getConfig('crowi', 'security:pageRecursiveDeletionAuthority'),
  660. pageRecursiveCompleteDeletionAuthority: await crowi.configManager.getConfig('crowi', 'security:pageRecursiveCompleteDeletionAuthority'),
  661. hideRestrictedByOwner: await crowi.configManager.getConfig('crowi', 'security:list-policy:hideRestrictedByOwner'),
  662. hideRestrictedByGroup: await crowi.configManager.getConfig('crowi', 'security:list-policy:hideRestrictedByGroup'),
  663. };
  664. const parameters = { action: SupportedAction.ACTION_ADMIN_SECURITY_SETTINGS_UPDATE };
  665. activityEvent.emit('update', res.locals.activity._id, parameters);
  666. return res.apiv3({ securitySettingParams });
  667. }
  668. catch (err) {
  669. const msg = 'Error occurred in updating security setting';
  670. logger.error('Error', err);
  671. return res.apiv3Err(new ErrorV3(msg, 'update-secuirty-setting failed'));
  672. }
  673. });
  674. /**
  675. * @swagger
  676. *
  677. * /_api/v3/security-setting/share-link-setting:
  678. * put:
  679. * tags: [SecuritySetting, apiv3]
  680. * description: Update ShareLink Setting
  681. * requestBody:
  682. * required: true
  683. * content:
  684. * application/json:
  685. * schema:
  686. * $ref: '#/components/schemas/ShareLinkSetting'
  687. * responses:
  688. * 200:
  689. * description: Succeeded to update ShareLink Setting
  690. * content:
  691. * application/json:
  692. * schema:
  693. * $ref: '#/components/schemas/ShareLinkSetting'
  694. */
  695. router.put('/share-link-setting', loginRequiredStrictly, adminRequired, addActivity, validator.generalSetting, apiV3FormValidator, async(req, res) => {
  696. const updateData = {
  697. 'security:disableLinkSharing': req.body.disableLinkSharing,
  698. };
  699. try {
  700. await crowi.configManager.updateConfigsInTheSameNamespace('crowi', updateData);
  701. const securitySettingParams = {
  702. disableLinkSharing: crowi.configManager.getConfig('crowi', 'security:disableLinkSharing'),
  703. };
  704. // eslint-disable-next-line max-len
  705. const parameters = { action: updateData['security:disableLinkSharing'] ? SupportedAction.ACTION_ADMIN_REJECT_SHARE_LINK : SupportedAction.ACTION_ADMIN_PERMIT_SHARE_LINK };
  706. activityEvent.emit('update', res.locals.activity._id, parameters);
  707. return res.apiv3({ securitySettingParams });
  708. }
  709. catch (err) {
  710. const msg = 'Error occurred in updating security setting';
  711. logger.error('Error', err);
  712. return res.apiv3Err(new ErrorV3(msg, 'update-secuirty-setting failed'));
  713. }
  714. });
  715. /**
  716. * @swagger
  717. *
  718. * /_api/v3/security-setting/all-share-links:
  719. * get:
  720. * tags: [ShareLinkSettings, apiv3]
  721. * description: Get All ShareLinks at Share Link Setting
  722. * responses:
  723. * 200:
  724. * description: all share links
  725. * content:
  726. * application/json:
  727. * schema:
  728. * properties:
  729. * securityParams:
  730. * type: object
  731. * description: suceed to get all share links
  732. */
  733. router.get('/all-share-links/', loginRequiredStrictly, adminRequired, async(req, res) => {
  734. const ShareLink = crowi.model('ShareLink');
  735. const page = parseInt(req.query.page) || 1;
  736. const limit = 10;
  737. const linkQuery = {};
  738. try {
  739. const paginateResult = await ShareLink.paginate(
  740. linkQuery,
  741. {
  742. page,
  743. limit,
  744. populate: {
  745. path: 'relatedPage',
  746. select: 'path',
  747. },
  748. },
  749. );
  750. return res.apiv3({ paginateResult });
  751. }
  752. catch (err) {
  753. const msg = 'Error occured in get share link';
  754. logger.error('Error', err);
  755. return res.apiv3Err(new ErrorV3(msg, 'get-all-share-links-failed'));
  756. }
  757. });
  758. /**
  759. * @swagger
  760. *
  761. * /_api/v3/security-setting/all-share-links:
  762. * delete:
  763. * tags: [ShareLinkSettings, apiv3]
  764. * description: Delete All ShareLinks at Share Link Setting
  765. * responses:
  766. * 200:
  767. * description: succeed to delete all share links
  768. */
  769. router.delete('/all-share-links/', loginRequiredStrictly, adminRequired, async(req, res) => {
  770. const ShareLink = crowi.model('ShareLink');
  771. try {
  772. const removedAct = await ShareLink.remove({});
  773. const removeTotal = await removedAct.n;
  774. return res.apiv3({ removeTotal });
  775. }
  776. catch (err) {
  777. const msg = 'Error occured in delete all share links';
  778. logger.error('Error', err);
  779. return res.apiv3Err(new ErrorV3(msg, 'failed-to-delete-all-share-links'));
  780. }
  781. });
  782. /**
  783. * @swagger
  784. *
  785. * /_api/v3/security-setting/local-setting:
  786. * put:
  787. * tags: [LocalSetting, apiv3]
  788. * description: Update LocalSetting
  789. * requestBody:
  790. * required: true
  791. * content:
  792. * application/json:
  793. * schema:
  794. * $ref: '#/components/schemas/LocalSetting'
  795. * responses:
  796. * 200:
  797. * description: Succeeded to update local Setting
  798. * content:
  799. * application/json:
  800. * schema:
  801. * $ref: '#/components/schemas/LocalSetting'
  802. */
  803. router.put('/local-setting', loginRequiredStrictly, adminRequired, addActivity, validator.localSetting, apiV3FormValidator, async(req, res) => {
  804. const requestParams = {
  805. 'security:registrationMode': req.body.registrationMode,
  806. 'security:registrationWhitelist': req.body.registrationWhitelist,
  807. 'security:passport-local:isPasswordResetEnabled': req.body.isPasswordResetEnabled,
  808. 'security:passport-local:isEmailAuthenticationEnabled': req.body.isEmailAuthenticationEnabled,
  809. };
  810. try {
  811. await updateAndReloadStrategySettings('local', requestParams);
  812. const localSettingParams = {
  813. registrationMode: await crowi.configManager.getConfig('crowi', 'security:registrationMode'),
  814. registrationWhitelist: await crowi.configManager.getConfig('crowi', 'security:registrationWhitelist'),
  815. isPasswordResetEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-local:isPasswordResetEnabled'),
  816. isEmailAuthenticationEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-local:isEmailAuthenticationEnabled'),
  817. };
  818. const parameters = { action: SupportedAction.ACTION_ADMIN_AUTH_ID_PASS_UPDATE };
  819. activityEvent.emit('update', res.locals.activity._id, parameters);
  820. return res.apiv3({ localSettingParams });
  821. }
  822. catch (err) {
  823. const msg = 'Error occurred in updating local setting';
  824. logger.error('Error', err);
  825. return res.apiv3Err(new ErrorV3(msg, 'update-local-setting failed'));
  826. }
  827. });
  828. /**
  829. * @swagger
  830. *
  831. * /_api/v3/security-setting/ldap:
  832. * put:
  833. * tags: [SecuritySetting, apiv3]
  834. * description: Update LDAP setting
  835. * requestBody:
  836. * required: true
  837. * content:
  838. * application/json:
  839. * schema:
  840. * $ref: '#/components/schemas/LdapAuthSetting'
  841. * responses:
  842. * 200:
  843. * description: Succeeded to update LDAP setting
  844. * content:
  845. * application/json:
  846. * schema:
  847. * $ref: '#/components/schemas/LdapAuthSetting'
  848. */
  849. router.put('/ldap', loginRequiredStrictly, adminRequired, addActivity, validator.ldapAuth, apiV3FormValidator, async(req, res) => {
  850. const requestParams = {
  851. 'security:passport-ldap:serverUrl': req.body.serverUrl,
  852. 'security:passport-ldap:isUserBind': req.body.isUserBind,
  853. 'security:passport-ldap:bindDN': req.body.ldapBindDN,
  854. 'security:passport-ldap:bindDNPassword': req.body.ldapBindDNPassword,
  855. 'security:passport-ldap:searchFilter': req.body.ldapSearchFilter,
  856. 'security:passport-ldap:attrMapUsername': req.body.ldapAttrMapUsername,
  857. 'security:passport-ldap:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
  858. 'security:passport-ldap:attrMapMail': req.body.ldapAttrMapMail,
  859. 'security:passport-ldap:attrMapName': req.body.ldapAttrMapName,
  860. 'security:passport-ldap:groupSearchBase': req.body.ldapGroupSearchBase,
  861. 'security:passport-ldap:groupSearchFilter': req.body.ldapGroupSearchFilter,
  862. 'security:passport-ldap:groupDnProperty': req.body.ldapGroupDnProperty,
  863. };
  864. try {
  865. await updateAndReloadStrategySettings('ldap', requestParams);
  866. const securitySettingParams = {
  867. serverUrl: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:serverUrl'),
  868. isUserBind: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isUserBind'),
  869. ldapBindDN: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:bindDN'),
  870. ldapBindDNPassword: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:bindDNPassword'),
  871. ldapSearchFilter: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:searchFilter'),
  872. ldapAttrMapUsername: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:attrMapUsername'),
  873. isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:isSameUsernameTreatedAsIdenticalUser'),
  874. ldapAttrMapMail: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:attrMapMail'),
  875. ldapAttrMapName: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:attrMapName'),
  876. ldapGroupSearchBase: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:groupSearchBase'),
  877. ldapGroupSearchFilter: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:groupSearchFilter'),
  878. ldapGroupDnProperty: await crowi.configManager.getConfig('crowi', 'security:passport-ldap:groupDnProperty'),
  879. };
  880. const parameters = { action: SupportedAction.ACTION_ADMIN_AUTH_LDAP_UPDATE };
  881. activityEvent.emit('update', res.locals.activity._id, parameters);
  882. return res.apiv3({ securitySettingParams });
  883. }
  884. catch (err) {
  885. const msg = 'Error occurred in updating SAML setting';
  886. logger.error('Error', err);
  887. return res.apiv3Err(new ErrorV3(msg, 'update-SAML-failed'));
  888. }
  889. });
  890. /**
  891. * @swagger
  892. *
  893. * /_api/v3/security-setting/saml:
  894. * put:
  895. * tags: [SecuritySetting, apiv3]
  896. * description: Update SAML setting
  897. * requestBody:
  898. * required: true
  899. * content:
  900. * application/json:
  901. * schema:
  902. * $ref: '#/components/schemas/SamlAuthSetting'
  903. * responses:
  904. * 200:
  905. * description: Succeeded to update SAML setting
  906. * content:
  907. * application/json:
  908. * schema:
  909. * $ref: '#/components/schemas/SamlAuthSetting'
  910. */
  911. router.put('/saml', loginRequiredStrictly, adminRequired, addActivity, validator.samlAuth, apiV3FormValidator, async(req, res) => {
  912. // For the value of each mandatory items,
  913. // check whether it from the environment variables is empty and form value to update it is empty
  914. // validate the syntax of a attribute - based login control rule
  915. const invalidValues = [];
  916. for (const configKey of crowi.passportService.mandatoryConfigKeysForSaml) {
  917. const key = configKey.replace('security:passport-saml:', '');
  918. const formValue = req.body[key];
  919. if (crowi.configManager.getConfigFromEnvVars('crowi', configKey) === null && formValue == null) {
  920. const formItemName = req.t(`security_setting.form_item_name.${key}`);
  921. invalidValues.push(req.t('form_validation.required', formItemName));
  922. }
  923. }
  924. if (invalidValues.length !== 0) {
  925. return res.apiv3Err(req.t('form_validation.error_message'), 400, invalidValues);
  926. }
  927. const rule = req.body.ABLCRule;
  928. // Empty string disables attribute-based login control.
  929. // So, when rule is empty string, validation is passed.
  930. if (rule != null) {
  931. try {
  932. crowi.passportService.parseABLCRule(rule);
  933. }
  934. catch (err) {
  935. return res.apiv3Err(req.t('form_validation.invalid_syntax', req.t('security_settings.form_item_name.ABLCRule')), 400);
  936. }
  937. }
  938. const requestParams = {
  939. 'security:passport-saml:entryPoint': req.body.entryPoint,
  940. 'security:passport-saml:issuer': req.body.issuer,
  941. 'security:passport-saml:cert': req.body.cert,
  942. 'security:passport-saml:attrMapId': req.body.attrMapId,
  943. 'security:passport-saml:attrMapUsername': req.body.attrMapUsername,
  944. 'security:passport-saml:attrMapMail': req.body.attrMapMail,
  945. 'security:passport-saml:attrMapFirstName': req.body.attrMapFirstName,
  946. 'security:passport-saml:attrMapLastName': req.body.attrMapLastName,
  947. 'security:passport-saml:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
  948. 'security:passport-saml:isSameEmailTreatedAsIdenticalUser': req.body.isSameEmailTreatedAsIdenticalUser,
  949. 'security:passport-saml:ABLCRule': req.body.ABLCRule,
  950. };
  951. try {
  952. await updateAndReloadStrategySettings('saml', requestParams);
  953. const securitySettingParams = {
  954. missingMandatoryConfigKeys: await crowi.passportService.getSamlMissingMandatoryConfigKeys(),
  955. samlEntryPoint: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:entryPoint'),
  956. samlIssuer: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:issuer'),
  957. samlCert: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:cert'),
  958. samlAttrMapId: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:attrMapId'),
  959. samlAttrMapUsername: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:attrMapUsername'),
  960. samlAttrMapMail: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:attrMapMail'),
  961. samlAttrMapFirstName: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:attrMapFirstName'),
  962. samlAttrMapLastName: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:attrMapLastName'),
  963. isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-saml:isSameUsernameTreatedAsIdenticalUser'),
  964. isSameEmailTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-saml:isSameEmailTreatedAsIdenticalUser'),
  965. samlABLCRule: await crowi.configManager.getConfig('crowi', 'security:passport-saml:ABLCRule'),
  966. };
  967. const parameters = { action: SupportedAction.ACTION_ADMIN_AUTH_SAML_UPDATE };
  968. activityEvent.emit('update', res.locals.activity._id, parameters);
  969. return res.apiv3({ securitySettingParams });
  970. }
  971. catch (err) {
  972. const msg = 'Error occurred in updating SAML setting';
  973. logger.error('Error', err);
  974. return res.apiv3Err(new ErrorV3(msg, 'update-SAML-failed'));
  975. }
  976. });
  977. /**
  978. * @swagger
  979. *
  980. * /_api/v3/security-setting/oidc:
  981. * put:
  982. * tags: [SecuritySetting, apiv3]
  983. * description: Update OpenID Connect setting
  984. * requestBody:
  985. * required: true
  986. * content:
  987. * application/json:
  988. * schema:
  989. * $ref: '#/components/schemas/OidcAuthSetting'
  990. * responses:
  991. * 200:
  992. * description: Succeeded to update OpenID Connect setting
  993. * content:
  994. * application/json:
  995. * schema:
  996. * $ref: '#/components/schemas/OidcAuthSetting'
  997. */
  998. router.put('/oidc', loginRequiredStrictly, adminRequired, addActivity, validator.oidcAuth, apiV3FormValidator, async(req, res) => {
  999. const requestParams = {
  1000. 'security:passport-oidc:providerName': req.body.oidcProviderName,
  1001. 'security:passport-oidc:issuerHost': req.body.oidcIssuerHost,
  1002. 'security:passport-oidc:authorizationEndpoint': req.body.oidcAuthorizationEndpoint,
  1003. 'security:passport-oidc:tokenEndpoint': req.body.oidcTokenEndpoint,
  1004. 'security:passport-oidc:revocationEndpoint': req.body.oidcRevocationEndpoint,
  1005. 'security:passport-oidc:introspectionEndpoint': req.body.oidcIntrospectionEndpoint,
  1006. 'security:passport-oidc:userInfoEndpoint': req.body.oidcUserInfoEndpoint,
  1007. 'security:passport-oidc:endSessionEndpoint': req.body.oidcEndSessionEndpoint,
  1008. 'security:passport-oidc:registrationEndpoint': req.body.oidcRegistrationEndpoint,
  1009. 'security:passport-oidc:jwksUri': req.body.oidcJWKSUri,
  1010. 'security:passport-oidc:clientId': req.body.oidcClientId,
  1011. 'security:passport-oidc:clientSecret': req.body.oidcClientSecret,
  1012. 'security:passport-oidc:attrMapId': req.body.oidcAttrMapId,
  1013. 'security:passport-oidc:attrMapUserName': req.body.oidcAttrMapUserName,
  1014. 'security:passport-oidc:attrMapName': req.body.oidcAttrMapName,
  1015. 'security:passport-oidc:attrMapMail': req.body.oidcAttrMapEmail,
  1016. 'security:passport-oidc:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
  1017. 'security:passport-oidc:isSameEmailTreatedAsIdenticalUser': req.body.isSameEmailTreatedAsIdenticalUser,
  1018. };
  1019. try {
  1020. await updateAndReloadStrategySettings('oidc', requestParams);
  1021. const securitySettingParams = {
  1022. oidcProviderName: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:providerName'),
  1023. oidcIssuerHost: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:issuerHost'),
  1024. oidcAuthorizationEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:authorizationEndpoint'),
  1025. oidcTokenEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:tokenEndpoint'),
  1026. oidcRevocationEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:revocationEndpoint'),
  1027. oidcIntrospectionEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:introspectionEndpoint'),
  1028. oidcUserInfoEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:userInfoEndpoint'),
  1029. oidcEndSessionEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:endSessionEndpoint'),
  1030. oidcRegistrationEndpoint: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:registrationEndpoint'),
  1031. oidcJWKSUri: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:jwksUri'),
  1032. oidcClientId: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:clientId'),
  1033. oidcClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:clientSecret'),
  1034. oidcAttrMapId: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:attrMapId'),
  1035. oidcAttrMapUserName: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:attrMapUserName'),
  1036. oidcAttrMapName: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:attrMapName'),
  1037. oidcAttrMapEmail: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:attrMapMail'),
  1038. isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:isSameUsernameTreatedAsIdenticalUser'),
  1039. isSameEmailTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-oidc:isSameEmailTreatedAsIdenticalUser'),
  1040. };
  1041. const parameters = { action: SupportedAction.ACTION_ADMIN_AUTH_OIDC_UPDATE };
  1042. activityEvent.emit('update', res.locals.activity._id, parameters);
  1043. return res.apiv3({ securitySettingParams });
  1044. }
  1045. catch (err) {
  1046. const msg = 'Error occurred in updating OpenIDConnect';
  1047. logger.error('Error', err);
  1048. return res.apiv3Err(new ErrorV3(msg, 'update-OpenIDConnect-failed'));
  1049. }
  1050. });
  1051. /**
  1052. * @swagger
  1053. *
  1054. * /_api/v3/security-setting/google-oauth:
  1055. * put:
  1056. * tags: [SecuritySetting, apiv3]
  1057. * description: Update google OAuth
  1058. * requestBody:
  1059. * required: true
  1060. * content:
  1061. * application/json:
  1062. * schema:
  1063. * $ref: '#/components/schemas/GoogleOAuthSetting'
  1064. * responses:
  1065. * 200:
  1066. * description: Succeeded to google OAuth
  1067. * content:
  1068. * application/json:
  1069. * schema:
  1070. * $ref: '#/components/schemas/GoogleOAuthSetting'
  1071. */
  1072. router.put('/google-oauth', loginRequiredStrictly, adminRequired, addActivity, validator.googleOAuth, apiV3FormValidator, async(req, res) => {
  1073. const requestParams = {
  1074. 'security:passport-google:clientId': req.body.googleClientId,
  1075. 'security:passport-google:clientSecret': req.body.googleClientSecret,
  1076. 'security:passport-google:isSameEmailTreatedAsIdenticalUser': req.body.isSameEmailTreatedAsIdenticalUser,
  1077. };
  1078. try {
  1079. await updateAndReloadStrategySettings('google', requestParams);
  1080. const securitySettingParams = {
  1081. googleClientId: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientId'),
  1082. googleClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientSecret'),
  1083. isSameEmailTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-google:isSameEmailTreatedAsIdenticalUser'),
  1084. };
  1085. const parameters = { action: SupportedAction.ACTION_ADMIN_AUTH_GOOGLE_UPDATE };
  1086. activityEvent.emit('update', res.locals.activity._id, parameters);
  1087. return res.apiv3({ securitySettingParams });
  1088. }
  1089. catch (err) {
  1090. const msg = 'Error occurred in updating googleOAuth';
  1091. logger.error('Error', err);
  1092. return res.apiv3Err(new ErrorV3(msg, 'update-googleOAuth-failed'));
  1093. }
  1094. });
  1095. /**
  1096. * @swagger
  1097. *
  1098. * /_api/v3/security-setting/github-oauth:
  1099. * put:
  1100. * tags: [SecuritySetting, apiv3]
  1101. * description: Update github OAuth
  1102. * requestBody:
  1103. * required: true
  1104. * content:
  1105. * application/json:
  1106. * schema:
  1107. * $ref: '#/components/schemas/GitHubOAuthSetting'
  1108. * responses:
  1109. * 200:
  1110. * description: Succeeded to github OAuth
  1111. * content:
  1112. * application/json:
  1113. * schema:
  1114. * $ref: '#/components/schemas/GitHubOAuthSetting'
  1115. */
  1116. router.put('/github-oauth', loginRequiredStrictly, adminRequired, addActivity, validator.githubOAuth, apiV3FormValidator, async(req, res) => {
  1117. const requestParams = {
  1118. 'security:passport-github:clientId': req.body.githubClientId,
  1119. 'security:passport-github:clientSecret': req.body.githubClientSecret,
  1120. 'security:passport-github:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
  1121. };
  1122. try {
  1123. await updateAndReloadStrategySettings('github', requestParams);
  1124. const securitySettingParams = {
  1125. githubClientId: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientId'),
  1126. githubClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientSecret'),
  1127. isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-github:isSameUsernameTreatedAsIdenticalUser'),
  1128. };
  1129. const parameters = { action: SupportedAction.ACTION_ADMIN_AUTH_GITHUB_UPDATE };
  1130. activityEvent.emit('update', res.locals.activity._id, parameters);
  1131. return res.apiv3({ securitySettingParams });
  1132. }
  1133. catch (err) {
  1134. // reset strategy
  1135. await crowi.passportService.resetGitHubStrategy();
  1136. const msg = 'Error occurred in updating githubOAuth';
  1137. logger.error('Error', err);
  1138. return res.apiv3Err(new ErrorV3(msg, 'update-githubOAuth-failed'));
  1139. }
  1140. });
  1141. return router;
  1142. };