Просмотр исходного кода

Merge branch 'master' into support/apply-bootstrap4

Yuki Takei 6 лет назад
Родитель
Сommit
1a64e63007

+ 4 - 0
CHANGES.md

@@ -6,6 +6,10 @@
 * Feature: SAML Attribute-based Login Control
 * Improvement: Reactify admin pages (Security)
 
+## v3.6.10
+
+* Fix: Redirect logic for users except for actives
+    * Introduced by 3.6.9
 
 ## v3.6.9
 

+ 1 - 1
config/env.prod.js

@@ -1,4 +1,4 @@
 module.exports = {
   NODE_ENV: 'production',
-  // FORMAT_NODE_LOG: false,
+  // FORMAT_NODE_LOG: false, // default: true
 };

+ 3 - 0
config/logger/config.prod.js

@@ -1,3 +1,6 @@
 module.exports = {
   default: 'info',
+
+  'growi:routes:login-passport': 'debug',
+  'growi:service:PassportService': 'debug',
 };

+ 12 - 14
src/client/js/components/Admin/Security/SecuritySetting.jsx

@@ -46,11 +46,6 @@ class SecuritySetting extends React.Component {
   render() {
     const { t, adminGeneralSecurityContainer } = this.props;
     const { currentRestrictGuestMode, currentPageCompleteDeletionAuthority } = adminGeneralSecurityContainer.state;
-    const helpPageListingByOwner = { __html: t('security_setting.page_listing_1') };
-    const helpPageListingByGroup = { __html: t('security_setting.page_listing_2') };
-    // eslint-disable-next-line max-len
-    const helpForceWikiMode = { __html: t('security_setting.Fixed by env var', { forcewikimode: 'FORCE_WIKI_MODE', wikimode: adminGeneralSecurityContainer.state.wikiMode }) };
-
 
     return (
       <React.Fragment>
@@ -63,18 +58,17 @@ class SecuritySetting extends React.Component {
               <p>{t('Error occurred')} : {this.state.retrieveError}</p>
             </div>
           )}
-          <div className="row mb-5">
+          <div className="row">
             <strong className="col-xs-3 text-right"> {t('security_setting.Guest Users Access')} </strong>
             <div className="col-xs-9 text-left">
               <div className="my-0 btn-group">
                 <div className="dropdown">
                   <button
-                    className="btn btn-default dropdown-toggle w-100"
+                    className={`btn btn-default dropdown-toggle w-100 ${adminGeneralSecurityContainer.isWikiModeForced && 'disabled'}`}
                     type="button"
                     data-toggle="dropdown"
                     aria-haspopup="true"
                     aria-expanded="false"
-                    disabled={adminGeneralSecurityContainer.state.isWikiModeForced}
                   >
                     <span className="pull-left">
                       {currentRestrictGuestMode === 'Deny' && t('security_setting.guest_mode.deny')}
@@ -107,20 +101,24 @@ class SecuritySetting extends React.Component {
               </div>
             </div>
           </div>
-          {adminGeneralSecurityContainer.state.isWikiModeForced && (
+          {adminGeneralSecurityContainer.isWikiModeForced && (
             <div className="row mb-5">
-              <div className="col-xs-3 text-right" />
-              <div className="col-xs-9 text-left">
+              <div className="col-xs-offset-3 col-xs-6 text-left">
                 <p className="alert alert-warning mt-2 text-left">
                   <i className="icon-exclamation icon-fw">
                   </i><b>FIXED</b><br />
-                  {<b dangerouslySetInnerHTML={helpForceWikiMode} />}
+                  <b
+                    dangerouslySetInnerHTML={{
+                    __html: t('security_setting.Fixed by env var',
+                    { forcewikimode: 'FORCE_WIKI_MODE', wikimode: adminGeneralSecurityContainer.state.wikiMode }),
+                    }}
+                  />
                 </p>
               </div>
             </div>
           )}
           <div className="row mb-5">
-            <strong className="col-xs-3 text-right" dangerouslySetInnerHTML={helpPageListingByOwner} />
+            <strong className="col-xs-3 text-right" dangerouslySetInnerHTML={{ __html: t('security_setting.page_listing_1') }} />
             <div className="col-xs-6 text-left">
               <div className="checkbox checkbox-success">
                 <input
@@ -137,7 +135,7 @@ class SecuritySetting extends React.Component {
           </div>
 
           <div className="row mb-5">
-            <strong className="col-xs-3 text-right" dangerouslySetInnerHTML={helpPageListingByGroup} />
+            <strong className="col-xs-3 text-right" dangerouslySetInnerHTML={{ __html: t('security_setting.page_listing_2') }} />
             <div className="col-xs-6 text-left">
               <div className="checkbox checkbox-success">
                 <input

+ 8 - 13
src/client/js/services/AdminGeneralSecurityContainer.js

@@ -15,7 +15,6 @@ export default class AdminGeneralSecurityContainer extends Container {
     this.appContainer = appContainer;
 
     this.state = {
-      isWikiModeForced: false,
       wikiMode: '',
       currentRestrictGuestMode: 'Deny',
       currentPageCompleteDeletionAuthority: 'adminOnly',
@@ -34,14 +33,12 @@ export default class AdminGeneralSecurityContainer extends Container {
       setupStrategies: [],
     };
 
-    this.onIsWikiModeForced = this.onIsWikiModeForced.bind(this);
   }
 
   async retrieveSecurityData() {
     await this.retrieveSetupStratedies();
     const response = await this.appContainer.apiv3.get('/security-setting/');
     const { generalSetting, generalAuth } = response.data.securityParams;
-    this.onIsWikiModeForced(generalSetting.wikiMode);
     this.setState({
       currentPageCompleteDeletionAuthority: generalSetting.pageCompleteDeletionAuthority,
       isShowRestrictedByOwner: !generalSetting.hideRestrictedByOwner,
@@ -66,6 +63,14 @@ export default class AdminGeneralSecurityContainer extends Container {
     return 'AdminGeneralSecurityContainer';
   }
 
+  /**
+   * get isWikiModeForced
+   * @return {bool} isWikiModeForced
+   */
+  get isWikiModeForced() {
+    return this.state.wikiMode === 'public' || this.state.wikiMode === 'private';
+  }
+
   /**
    * Change restrictGuestMode
    */
@@ -94,16 +99,6 @@ export default class AdminGeneralSecurityContainer extends Container {
     this.setState({ isShowRestrictedByGroup:  !this.state.isShowRestrictedByGroup });
   }
 
-  onIsWikiModeForced(wikiModeSetting) {
-    if (wikiModeSetting === 'private') {
-      this.setState({ isWikiModeForced: true });
-    }
-    else {
-      this.setState({ isWikiModeForced: false });
-    }
-  }
-
-
   /**
    * Update restrictGuestMode
    * @memberOf AdminGeneralSecuritySContainer

+ 2 - 0
src/client/js/services/AdminSamlSecurityContainer.js

@@ -21,6 +21,7 @@ export default class AdminSamlSecurityContainer extends Container {
 
     this.state = {
       retrieveError: null,
+      // TODO GW-1324 ABLCRure DB value takes precedence
       useOnlyEnvVars: false,
       callbackUrl: urljoin(pathUtils.removeTrailingSlash(appContainer.config.crowi.url), '/passport/saml/callback'),
       missingMandatoryConfigKeys: [],
@@ -48,6 +49,7 @@ export default class AdminSamlSecurityContainer extends Container {
       const { samlAuth } = response.data.securityParams;
       this.setState({
         missingMandatoryConfigKeys: samlAuth.missingMandatoryConfigKeys,
+        useOnlyEnvVars: samlAuth.useOnlyEnvVarsForSomeOptions,
         samlEntryPoint: samlAuth.samlEntryPoint,
         samlIssuer: samlAuth.samlIssuer,
         samlCert: samlAuth.samlCert,

+ 3 - 0
src/lib/service/logger/stream.prod.js

@@ -17,6 +17,9 @@ else {
     const bunyanFormat = require('bunyan-format');
     stream = bunyanFormat({ outputMode: 'long' });
   }
+  else {
+    stream = process.stdout;
+  }
 }
 
 module.exports = stream;

+ 2 - 2
src/server/crowi/express-init.js

@@ -19,7 +19,7 @@ module.exports = function(crowi, app) {
   const i18nSprintf = require('i18next-sprintf-postprocessor');
   const i18nMiddleware = require('i18next-express-middleware');
 
-  const safeRedirect = require('../middleware/safe-redirect')();
+  const registerSafeRedirect = require('../middleware/safe-redirect')();
 
   const avoidSessionRoutes = require('../routes/avoid-session-routes');
   const i18nUserSettingDetector = require('../util/i18nUserSettingDetector');
@@ -115,7 +115,7 @@ module.exports = function(crowi, app) {
 
   app.use(flash());
 
-  app.use(safeRedirect);
+  app.use(registerSafeRedirect);
 
   const middlewares = require('../util/middlewares')(crowi, app);
 

+ 2 - 1
src/server/routes/apiv3/security-setting.js

@@ -351,6 +351,7 @@ module.exports = (crowi) => {
       },
       samlAuth: {
         missingMandatoryConfigKeys: await crowi.passportService.getSamlMissingMandatoryConfigKeys(),
+        useOnlyEnvVarsForSomeOptions: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:useOnlyEnvVarsForSomeOptions'),
         samlEntryPoint: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:entryPoint'),
         samlEnvVarEntryPoint: await crowi.configManager.getConfigFromEnvVars('crowi', 'security:passport-saml:entryPoint'),
         samlIssuer: await crowi.configManager.getConfigFromDB('crowi', 'security:passport-saml:issuer'),
@@ -524,7 +525,7 @@ module.exports = (crowi) => {
       'security:list-policy:hideRestrictedByGroup': req.body.hideRestrictedByGroup,
     };
     const wikiMode = await crowi.configManager.getConfig('crowi', 'security:wikiMode');
-    if (wikiMode === 'private') {
+    if (wikiMode === 'private' || wikiMode === 'public') {
       logger.debug('security:restrictGuestMode will not be changed because wiki mode is forced to set');
       delete requestParams['security:restrictGuestMode'];
     }

+ 2 - 1
src/server/routes/login.js

@@ -56,7 +56,8 @@ module.exports = function(crowi, app) {
 
   actions.preLogin = function(req, res, next) {
     // user has already logged in
-    if (req.user != null) {
+    const { user } = req;
+    if (user != null && user.status === User.STATUS_ACTIVE) {
       const { redirectTo } = req.session;
       // remove session.redirectTo
       delete req.session.redirectTo;

+ 1 - 0
src/server/service/passport.js

@@ -684,6 +684,7 @@ class PassportService {
   verifySAMLResponseByABLCRule(response) {
     const rule = this.crowi.configManager.getConfig('crowi', 'security:passport-saml:ABLCRule');
     if (rule == null) {
+      debug('There is no ABLCRule.');
       return true;
     }
 

+ 8 - 8
src/test/middleware/safe-redirect.test.js

@@ -1,7 +1,7 @@
 /* eslint-disable arrow-body-style */
 
 describe('safeRedirect', () => {
-  let safeRedirect;
+  let registerSafeRedirect;
 
   const whitelistOfHosts = [
     'white1.example.com:8080',
@@ -9,7 +9,7 @@ describe('safeRedirect', () => {
   ];
 
   beforeEach(async(done) => {
-    safeRedirect = require('@server/middleware/safe-redirect')(whitelistOfHosts);
+    registerSafeRedirect = require('@server/middleware/safe-redirect')(whitelistOfHosts);
     done();
   });
 
@@ -26,7 +26,7 @@ describe('safeRedirect', () => {
     const next = jest.fn();
 
     test('redirects to \'/\' because specified url causes open redirect vulnerability', () => {
-      safeRedirect(req, res, next);
+      registerSafeRedirect(req, res, next);
 
       const result = res.safeRedirect('//evil.example.com');
 
@@ -39,7 +39,7 @@ describe('safeRedirect', () => {
     });
 
     test('redirects to \'/\' because specified host without port is not in whitelist', () => {
-      safeRedirect(req, res, next);
+      registerSafeRedirect(req, res, next);
 
       const result = res.safeRedirect('http://white1.example.com/path/to/page');
 
@@ -52,7 +52,7 @@ describe('safeRedirect', () => {
     });
 
     test('redirects to the specified local url', () => {
-      safeRedirect(req, res, next);
+      registerSafeRedirect(req, res, next);
 
       const result = res.safeRedirect('/path/to/page');
 
@@ -65,7 +65,7 @@ describe('safeRedirect', () => {
     });
 
     test('redirects to the specified local url (fqdn)', () => {
-      safeRedirect(req, res, next);
+      registerSafeRedirect(req, res, next);
 
       const result = res.safeRedirect('http://example.com/path/to/page');
 
@@ -78,7 +78,7 @@ describe('safeRedirect', () => {
     });
 
     test('redirects to the specified whitelisted url (white1.example.com:8080)', () => {
-      safeRedirect(req, res, next);
+      registerSafeRedirect(req, res, next);
 
       const result = res.safeRedirect('http://white1.example.com:8080/path/to/page');
 
@@ -91,7 +91,7 @@ describe('safeRedirect', () => {
     });
 
     test('redirects to the specified whitelisted url (white2.example.com:8080)', () => {
-      safeRedirect(req, res, next);
+      registerSafeRedirect(req, res, next);
 
       const result = res.safeRedirect('http://white2.example.com:8080/path/to/page');