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

save on/off, id, secret, bindDuplicatedUser

sou 7 лет назад
Родитель
Сommit
0f7537579d

+ 1 - 0
lib/crowi/index.js

@@ -264,6 +264,7 @@ Crowi.prototype.setupPassport = function() {
   this.passportService.setupLocalStrategy();
   this.passportService.setupLocalStrategy();
   this.passportService.setupLdapStrategy();
   this.passportService.setupLdapStrategy();
   this.passportService.setupGoogleStrategy();
   this.passportService.setupGoogleStrategy();
+  this.passportService.setupGitHubStrategy();
   return Promise.resolve();
   return Promise.resolve();
 };
 };
 
 

+ 12 - 0
lib/form/admin/securityPassportGitHub.js

@@ -0,0 +1,12 @@
+'use strict';
+
+var form = require('express-form')
+  , field = form.field
+  ;
+
+module.exports = form(
+  field('settingForm[security:passport-github:isEnabled]').trim().toBooleanStrict().required(),
+  field('settingForm[security:passport-github:clientId]').trim(),
+  field('settingForm[security:passport-github:clientSecret]').trim(),
+  field('settingForm[security:passport-github:isSameUsernameTreatedAsIdenticalUser]').trim().toBooleanStrict()
+);

+ 1 - 0
lib/form/index.js

@@ -20,6 +20,7 @@ module.exports = {
     securityMechanism: require('./admin/securityMechanism'),
     securityMechanism: require('./admin/securityMechanism'),
     securityPassportLdap: require('./admin/securityPassportLdap'),
     securityPassportLdap: require('./admin/securityPassportLdap'),
     securityPassportGoogle: require('./admin/securityPassportGoogle'),
     securityPassportGoogle: require('./admin/securityPassportGoogle'),
+    securityPassportGitHub: require('./admin/securityPassportGitHub'),
     markdown: require('./admin/markdown'),
     markdown: require('./admin/markdown'),
     customcss: require('./admin/customcss'),
     customcss: require('./admin/customcss'),
     customscript: require('./admin/customscript'),
     customscript: require('./admin/customscript'),

+ 6 - 0
lib/models/config.js

@@ -65,6 +65,7 @@ module.exports = function(crowi) {
       'security:passport-ldap:groupDnProperty' : undefined,
       'security:passport-ldap:groupDnProperty' : undefined,
       'security:passport-ldap:isSameUsernameTreatedAsIdenticalUser': false,
       'security:passport-ldap:isSameUsernameTreatedAsIdenticalUser': false,
       'security:passport-google:isEnabled' : false,
       'security:passport-google:isEnabled' : false,
+      'security:passport-github:isEnabled' : false,
 
 
       'aws:bucket'          : 'growi',
       'aws:bucket'          : 'growi',
       'aws:region'          : 'ap-northeast-1',
       'aws:region'          : 'ap-northeast-1',
@@ -273,6 +274,11 @@ module.exports = function(crowi) {
     return getValueForCrowiNS(config, key);
     return getValueForCrowiNS(config, key);
   };
   };
 
 
+  configSchema.statics.isEnabledPassportGitHub = function(config) {
+    const key = 'security:passport-github:isEnabled';
+    return getValueForCrowiNS(config, key);
+  };
+
   configSchema.statics.isSameUsernameTreatedAsIdenticalUser = function(config, providerType) {
   configSchema.statics.isSameUsernameTreatedAsIdenticalUser = function(config, providerType) {
     const key = `security:passport-${providerType}:isSameUsernameTreatedAsIdenticalUser`;
     const key = `security:passport-${providerType}:isSameUsernameTreatedAsIdenticalUser`;
     return getValueForCrowiNS(config, key);
     return getValueForCrowiNS(config, key);

+ 22 - 1
lib/routes/admin.js

@@ -903,7 +903,7 @@ module.exports = function(crowi, app) {
       });
       });
   };
   };
 
 
-  actions.api.securityPassportGoogleSetting = async function(req, res) {
+  actions.api.securityPassportGoogleSetting = async(req, res) => {
     var form = req.form.settingForm;
     var form = req.form.settingForm;
 
 
     if (!req.form.isValid) {
     if (!req.form.isValid) {
@@ -924,6 +924,27 @@ module.exports = function(crowi, app) {
     return res.json({status: true});
     return res.json({status: true});
   };
   };
 
 
+  actions.api.securityPassportGitHubSetting = async(req, res) => {
+    var form = req.form.settingForm;
+
+    if (!req.form.isValid) {
+      return res.json({status: false, message: req.form.errors.join('\n')});
+    }
+
+    debug('form content', form);
+    await saveSettingAsync(form);
+    const config = await crowi.getConfig();
+
+    // reset strategy
+    await crowi.passportService.resetGitHubStrategy();
+    // setup strategy
+    if (Config.isEnabledPassportGoogle(config)) {
+      await crowi.passportService.setupGitHubStrategy(true);
+    }
+
+    return res.json({status: true});
+  };
+
   actions.api.customizeSetting = function(req, res) {
   actions.api.customizeSetting = function(req, res) {
     var form = req.form.settingForm;
     var form = req.form.settingForm;
 
 

+ 3 - 0
lib/routes/index.js

@@ -71,6 +71,9 @@ module.exports = function(crowi, app) {
   app.post('/_api/admin/security/passport-google' , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.securityPassportGoogle, admin.api.securityPassportGoogleSetting);
   app.post('/_api/admin/security/passport-google' , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.securityPassportGoogle, admin.api.securityPassportGoogleSetting);
   app.get('/passport/google'                      , loginPassport.loginPassportGoogle);
   app.get('/passport/google'                      , loginPassport.loginPassportGoogle);
   app.get('/passport/google/callback'             , loginPassport.loginPassportGoogleCallback);
   app.get('/passport/google/callback'             , loginPassport.loginPassportGoogleCallback);
+  app.post('/_api/admin/security/passport-github' , loginRequired(crowi, app) , middleware.adminRequired() , csrf, form.admin.securityPassportGitHub, admin.api.securityPassportGitHubSetting);
+  // app.get('/passport/github'                      , loginPassport.loginPassportGoogle);
+  // app.get('/passport/github/callback'             , loginPassport.loginPassportGoogleCallback);
 
 
   // markdown admin
   // markdown admin
   app.get('/admin/markdown'                   , loginRequired(crowi, app) , middleware.adminRequired() , admin.markdown.index);
   app.get('/admin/markdown'                   , loginRequired(crowi, app) , middleware.adminRequired() , admin.markdown.index);

+ 47 - 0
lib/service/passport.js

@@ -3,6 +3,7 @@ const passport = require('passport');
 const LocalStrategy = require('passport-local').Strategy;
 const LocalStrategy = require('passport-local').Strategy;
 const LdapStrategy = require('passport-ldapauth');
 const LdapStrategy = require('passport-ldapauth');
 const GoogleStrategy = require('passport-google-auth').Strategy;
 const GoogleStrategy = require('passport-google-auth').Strategy;
+const GitHubStrategy = require('passport-github').Strategy;
 
 
 /**
 /**
  * the service class of Passport
  * the service class of Passport
@@ -292,6 +293,52 @@ class PassportService {
     this.isGoogleStrategySetup = false;
     this.isGoogleStrategySetup = false;
   }
   }
 
 
+  setupGitHubStrategy() {
+    // check whether the strategy has already been set up
+    if (this.isGitHubStrategySetup) {
+      throw new Error('GitHubStrategy has already been set up');
+    }
+
+    const config = this.crowi.config;
+    const Config = this.crowi.model('Config');
+    //this
+    const isGitHubEnabled = Config.isEnabledPassportGitHub(config);
+
+    // when disabled
+    if (!isGitHubEnabled) {
+      return;
+    }
+
+    debug('GitHubStrategy: setting up..');
+    passport.use(new GitHubStrategy({
+      clientID: config.crowi['security:passport-github:clientId'],
+      clientSecret: config.crowi['security:passport-github:clientSecret'],
+      callbackURL: 'http://localhost:3000/passport/github/callback',  //change this
+      skipUserProfile: false,
+    }, function(accessToken, refreshToken, profile, done) {
+      if (profile) {
+        return done(null, profile);
+      }
+      else {
+        return done(null, false);
+      }
+    }));
+
+    this.isGitHubStrategySetup = true;
+    debug('GitHubStrategy: setup is done');
+  }
+
+  /**
+   * reset GoogleStrategy
+   *
+   * @memberof PassportService
+   */
+  resetGitHubStrategy() {
+    debug('GitHubStrategy: reset');
+    passport.unuse('github');
+    this.isGitHubStrategySetup = false;
+  }
+
   /**
   /**
    * setup serializer and deserializer
    * setup serializer and deserializer
    *
    *

+ 165 - 4
lib/views/admin/widget/passport/github.html

@@ -1,6 +1,167 @@
-<form action="" method="post" class="form-horizontal passportStrategy" id="githubOauthSetting" role="form">
-  <fieldset>
-    <legend>Github OAuth {{ t("security_setting.configuration") }}</legend>
-    <p class="well">(TBD)</p>
+<form action="/_api/admin/security/passport-github" method="post" class="form-horizontal passportStrategy" id="githubSetting" role="form"
+    {% if isRestartingServerNeeded %}style="opacity: 0.4;"{% endif %}>
+  <legend>GitHub OAuth {{ t("security_setting.configuration") }}</legend>
+  <p class="well alert-anchor">{{ t("security_setting.connect_api_manager") }}</p>
+  {% set nameForIsGitHubEnabled = "settingForm[security:passport-github:isEnabled]" %}
+  {% set isGitHubEnabled = settingForm['security:passport-github:isEnabled'] %}
+  <div class="form-group">
+    <label for="{{nameForIsGitHubEnabled}}" class="col-xs-3 control-label">{{ t("security_setting.GitHub_OAuth.use_GitHub_OAuth") }}</label>
+    <div class="col-xs-6">
+      <div class="btn-group btn-toggle" data-toggle="buttons">
+        <label class="btn btn-default btn-rounded btn-outline {% if isGitHubEnabled %}active{% endif %}" data-active-class="primary">
+          <input name="{{nameForIsGitHubEnabled}}" value="true" type="radio"
+              {% if true === isGitHubEnabled %}checked{% endif %}> ON
+        </label>
+        <label class="btn btn-default btn-rounded btn-outline {% if !isGitHubEnabled %}active{% endif %}" data-active-class="default">
+          <input name="{{nameForIsGitHubEnabled}}" value="false" type="radio"
+              {% if !isGitHubEnabled %}checked{% endif %}> OFF
+        </label>
+      </div>
+    </div>
+  </div>
+  <fieldset id="passport-github-hide-when-disabled" {%if !isGitHubEnabled %}style="display: none;"{% endif %}>
+
+    <div class="form-group">
+      <label for="settingForm[security:passport-github:clientId]" class="col-xs-3 control-label">{{ t("security_setting.github_setting") }}</label>
+      <div class="col-xs-6">
+        <ol class="help-block">
+          <li>{{ t("security_setting.access_api_manager") }}</li>
+          <li>{{ t("security_setting.create_project") }}</li>
+          <li>{{ t("security_setting.create_auth_to_oauth") }}</li>
+          <ol>
+            <li>{{ t("security_setting.select_webapp") }}</li>
+            <li>{{ t("security_setting.GitHub_OAuth.change_redirect_url", "https://${growi.host}/passport/github/callback", "${growi.host}") }}</li>
+          </ol>
+        </ol>
+      </div>
+    </div>
+
+    <div class="form-group">
+      <label for="settingForm[security:passport-github:clientId]" class="col-xs-3 control-label">{{ t("security_setting.clientID") }}</label>
+      <div class="col-xs-6">
+        <input class="form-control" type="text" name="settingForm[security:passport-github:clientId]" value="{{ settingForm['security:passport-github:clientId'] || '' }}">
+      </div>
+    </div>
+
+    <div class="form-group">
+      <label for="settingForm[security:passport-github:clientSecret]" class="col-xs-3 control-label">{{ t("security_setting.client_secret") }}</label>
+      <div class="col-xs-6">
+        <input class="form-control" type="text" name="settingForm[security:passport-github:clientSecret]" value="{{ settingForm['security:passport-github:clientSecret'] || '' }}">
+      </div>
+    </div>
+    <div class="form-group">
+      <div class="col-xs-6 col-xs-offset-3">
+        <div class="checkbox checkbox-info">
+          <input type="checkbox" id="bindByUserName-GitHub" name="settingForm[security:passport-github:isSameUsernameTreatedAsIdenticalUser]" value="1"
+              {% if settingForm['security:passport-github:isSameUsernameTreatedAsIdenticalUser'] %}checked{% endif %} />
+          <label for="bindByUserName-GitHub">
+            {{ t("security_setting.ldap.Treat username matching as identical") }}
+          </label>
+          <p class="help-block">
+            <small>
+              {{ t("security_setting.ldap.Treat username matching as identical_warn") }}
+            </small>
+          </p>
+        </div>
+      </div>
+    </div>
+
   </fieldset>
   </fieldset>
+
+  <div class="form-group" id="btn-update">
+    <div class="col-xs-offset-3 col-xs-6">
+      <input type="hidden" name="_csrf" value="{{ csrf() }}">
+      <button type="submit" class="btn btn-primary">{{ t('Update') }}</button>
+    </div>
+  </div>
+
 </form>
 </form>
+{% if false %}
+<hr>
+<h4>
+  <i class="fa fa-question-circle" aria-hidden="true"></i>
+  <a href="#collapseHelpForApp" data-toggle="collapse">How to configure Slack App?</a>
+</h4>
+
+<ol id="collapseHelpForApp" class="collapse">
+  <li>
+    Register Slack App
+    <ol>
+      <li>
+        Create App from <a href="https://api.slack.com/applications/new">this link</a>, and fill the form out as below:
+        <dl class="dl-horizontal">
+          <dt>App Name</dt> <dd><code>growi</code> </dd>
+          <dt>Development Slack Team</dt> <dd>Select the team you want to notify to.</dd>
+        </dl>
+      </li>
+      <li><strong>Save</strong> it.</li>
+    </ol>
+  </li>
+  <li>
+    Get App Credentials
+    <ol>
+      <li>Go To "Basic Information" page and make a note "Client ID" and "Client Secret".</li>
+    </ol>
+  </li>
+  <li>
+    Set Redirect URLs
+    <ol>
+      <li>Go to "OAuth &amp; Permissions" page.</li>
+      <li>Add <code><script>document.write(location.origin);</script>/admin/notification/slackAuth</code> .</li>
+      <li>Don't forget to <strong>save</strong>.</li>
+    </ol>
+  </li>
+  <li>
+    Set Permission Scopes to the App
+    <ol>
+      <li>Go to "OAuth &amp; Permissions" page.</li>
+      <li>Add "Send messages as GROWI"(<code>chat:write:bot</code>).</li>
+      <li>Don't forget to <strong>save</strong>.</li>
+    </ol>
+  </li>
+  <li>
+    Create a bot user
+    <ol>
+      <li>Go to "Bot Users" page and add.</li>
+    </ol>
+  </li>
+  <li>
+    Install the app
+    <ol>
+      <li>Go to "Install App to Your Team" page and install.</li>
+    </ol>
+  </li>
+  <li>
+    (At Team) Approve the app
+    <ol>
+      <li>Go to the management Apps page for the team you installed the app and approve "growi".</li>
+    </ol>
+  </li>
+  <li>
+    (At Team) Invite the bot to your team
+    <ol>
+      <li>Invite the user you created in <code>4. Add a bot user</code> to the channel you notify to.</li>
+    </ol>
+  </li>
+  <li>
+    (At GROWI admin page) Input "clientId" and "clientSecret" and submit on this page.
+  </li>
+  <li>
+    (At GROWI admin page) Click "Connect to Slack" button to start OAuth process.
+  </li>
+</ol>
+{% endif %}
+
+<script>
+  $('input[name="settingForm[security:passport-github:isEnabled]"]').change(function() {
+      const isEnabled = ($(this).val() === "true");
+
+      if (isEnabled) {
+        $('#passport-github-hide-when-disabled').show(400);
+      }
+      else {
+        $('#passport-github-hide-when-disabled').hide(400);
+      }
+    });
+</script>
+