index.js 56 KB

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