Merge pull request #606 from DoubleMalt/feature/MattermostAuth

Add Mattermost authentication strategy
This commit is contained in:
Sheogorath 2017-10-31 12:11:41 +01:00 committed by GitHub
commit 16b3e015ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 116 additions and 13 deletions

View file

@ -8,8 +8,8 @@ HackMD
[![version][github-version-badge]][github-release-page] [![version][github-version-badge]][github-release-page]
HackMD lets you create realtime collaborative markdown notes on all platforms. HackMD lets you create realtime collaborative markdown notes on all platforms.
Inspired by Hackpad, with more focus on speed and flexibility. Inspired by Hackpad, with more focus on speed and flexibility.
Still in the early stage, feel free to fork or contribute to HackMD. Still in the early stage, feel free to fork or contribute to HackMD.
Thanks for using! :smile: Thanks for using! :smile:
@ -112,13 +112,13 @@ If you are upgrading HackMD from an older version, follow these steps:
* [migration-to-0.5.0](https://github.com/hackmdio/migration-to-0.5.0) * [migration-to-0.5.0](https://github.com/hackmdio/migration-to-0.5.0)
We don't use LZString to compress socket.io data and DB data after version 0.5.0. We don't use LZString to compress socket.io data and DB data after version 0.5.0.
Please run the migration tool if you're upgrading from the old version. Please run the migration tool if you're upgrading from the old version.
* [migration-to-0.4.0](https://github.com/hackmdio/migration-to-0.4.0) * [migration-to-0.4.0](https://github.com/hackmdio/migration-to-0.4.0)
We've dropped MongoDB after version 0.4.0. We've dropped MongoDB after version 0.4.0.
So here is the migration tool for you to transfer the old DB data to the new DB. So here is the migration tool for you to transfer the old DB data to the new DB.
This tool is also used for official service. This tool is also used for official service.
# Configuration # Configuration
@ -156,6 +156,9 @@ There are some configs you need to change in the files below
| HMD_GITLAB_BASEURL | no example | GitLab authentication endpoint, set to use other endpoint than GitLab.com (optional) | | HMD_GITLAB_BASEURL | no example | GitLab authentication endpoint, set to use other endpoint than GitLab.com (optional) |
| HMD_GITLAB_CLIENTID | no example | GitLab API client id | | HMD_GITLAB_CLIENTID | no example | GitLab API client id |
| HMD_GITLAB_CLIENTSECRET | no example | GitLab API client secret | | HMD_GITLAB_CLIENTSECRET | no example | GitLab API client secret |
| HMD_MATTERMOST_BASEURL | no example | Mattermost authentication endpoint |
| HMD_MATTERMOST_CLIENTID | no example | Mattermost API client id |
| HMD_MATTERMOST_CLIENTSECRET | no example | Mattermost API client secret |
| HMD_DROPBOX_CLIENTID | no example | Dropbox API client id | | HMD_DROPBOX_CLIENTID | no example | Dropbox API client id |
| HMD_DROPBOX_CLIENTSECRET | no example | Dropbox API client secret | | HMD_DROPBOX_CLIENTSECRET | no example | Dropbox API client secret |
| HMD_GOOGLE_CLIENTID | no example | Google API client id | | HMD_GOOGLE_CLIENTID | no example | Google API client id |
@ -231,7 +234,7 @@ There are some configs you need to change in the files below
| service | settings location | description | | service | settings location | description |
| ------- | --------- | ----------- | | ------- | --------- | ----------- |
| facebook, twitter, github, gitlab, dropbox, google, ldap | environment variables or `config.json` | for signin | | facebook, twitter, github, gitlab, mattermost, dropbox, google, ldap | environment variables or `config.json` | for signin |
| imgur | environment variables or `config.json` | for image upload | | imgur | environment variables or `config.json` | for image upload |
| google drive(`google/apiKey`, `google/clientID`), dropbox(`dropbox/appKey`) | `config.json` | for export and import | | google drive(`google/apiKey`, `google/clientID`), dropbox(`dropbox/appKey`) | `config.json` | for export and import |
@ -243,6 +246,7 @@ There are some configs you need to change in the files below
| twitter | `/auth/twitter/callback` | | twitter | `/auth/twitter/callback` |
| github | `/auth/github/callback` | | github | `/auth/github/callback` |
| gitlab | `/auth/gitlab/callback` | | gitlab | `/auth/gitlab/callback` |
| mattermost | `/auth/mattermost/callback` |
| dropbox | `/auth/dropbox/callback` | | dropbox | `/auth/dropbox/callback` |
| google | `/auth/google/callback` | | google | `/auth/google/callback` |
@ -264,9 +268,9 @@ hackmd/
## Operational Transformation ## Operational Transformation
From 0.3.2, we started supporting operational transformation. From 0.3.2, we started supporting operational transformation.
It makes concurrent editing safe and will not break up other users' operations. It makes concurrent editing safe and will not break up other users' operations.
Additionally, now can show other clients' selections. Additionally, now can show other clients' selections.
See more at [http://operational-transformation.github.io/](http://operational-transformation.github.io/) See more at [http://operational-transformation.github.io/](http://operational-transformation.github.io/)

View file

@ -100,6 +100,18 @@
"description": "GitLab API client scope (optional)", "description": "GitLab API client scope (optional)",
"required": false "required": false
}, },
"HMD_MATTERMOST_BASEURL": {
"description": "Mattermost authentication endpoint",
"required": false
},
"HMD_MATTERMOST_CLIENTID": {
"description": "Mattermost API client id",
"required": false
},
"HMD_MATTERMOST_CLIENTSECRET": {
"description": "Mattermost API client secret",
"required": false
},
"HMD_DROPBOX_CLIENTID": { "HMD_DROPBOX_CLIENTID": {
"description": "Dropbox API client id", "description": "Dropbox API client id",
"required": false "required": false

View file

@ -48,6 +48,11 @@
"clientSecret": "change this", "clientSecret": "change this",
"scope": "use 'read_user' scope for auth user only or remove this property if you need gitlab snippet import/export support (will result to be default scope 'api')" "scope": "use 'read_user' scope for auth user only or remove this property if you need gitlab snippet import/export support (will result to be default scope 'api')"
}, },
"mattermost": {
"baseURL": "change this",
"clientID": "change this",
"clientSecret": "change this"
},
"dropbox": { "dropbox": {
"clientID": "change this", "clientID": "change this",
"clientSecret": "change this", "clientSecret": "change this",

View file

@ -74,6 +74,11 @@ module.exports = {
clientSecret: undefined, clientSecret: undefined,
scope: undefined scope: undefined
}, },
mattermost: {
baseURL: undefined,
clientID: undefined,
clientSecret: undefined
},
dropbox: { dropbox: {
clientID: undefined, clientID: undefined,
clientSecret: undefined clientSecret: undefined

View file

@ -38,6 +38,10 @@ if (fs.existsSync(basePath)) {
clientID: getSecret('gitlab_clientID'), clientID: getSecret('gitlab_clientID'),
clientSecret: getSecret('gitlab_clientSecret') clientSecret: getSecret('gitlab_clientSecret')
}, },
mattermost: {
clientID: getSecret('mattermost_clientID'),
clientSecret: getSecret('mattermost_clientSecret')
},
dropbox: { dropbox: {
clientID: getSecret('dropbox_clientID'), clientID: getSecret('dropbox_clientID'),
clientSecret: getSecret('dropbox_clientSecret') clientSecret: getSecret('dropbox_clientSecret')

View file

@ -49,6 +49,11 @@ module.exports = {
clientSecret: process.env.HMD_GITLAB_CLIENTSECRET, clientSecret: process.env.HMD_GITLAB_CLIENTSECRET,
scope: process.env.HMD_GITLAB_SCOPE scope: process.env.HMD_GITLAB_SCOPE
}, },
mattermost: {
baseURL: process.env.HMD_MATTERMOST_BASEURL,
clientID: process.env.HMD_MATTERMOST_CLIENTID,
clientSecret: process.env.HMD_MATTERMOST_CLIENTSECRET
},
dropbox: { dropbox: {
clientID: process.env.HMD_DROPBOX_CLIENTID, clientID: process.env.HMD_DROPBOX_CLIENTID,
clientSecret: process.env.HMD_DROPBOX_CLIENTSECRET clientSecret: process.env.HMD_DROPBOX_CLIENTSECRET

View file

@ -90,6 +90,7 @@ config.isTwitterEnable = config.twitter.consumerKey && config.twitter.consumerSe
config.isEmailEnable = config.email config.isEmailEnable = config.email
config.isGitHubEnable = config.github.clientID && config.github.clientSecret config.isGitHubEnable = config.github.clientID && config.github.clientSecret
config.isGitLabEnable = config.gitlab.clientID && config.gitlab.clientSecret config.isGitLabEnable = config.gitlab.clientID && config.gitlab.clientSecret
config.isMattermostEnable = config.mattermost.clientID && config.mattermost.clientSecret
config.isLDAPEnable = config.ldap.url config.isLDAPEnable = config.ldap.url
config.isPDFExportEnable = config.allowpdfexport config.isPDFExportEnable = config.allowpdfexport

View file

@ -111,6 +111,15 @@ module.exports = function (sequelize, DataTypes) {
photo = letterAvatars(profile.username) photo = letterAvatars(profile.username)
} }
break break
case 'mattermost':
photo = profile.avatarUrl
if (photo) {
if (bigger) photo = photo.replace(/(\?s=)\d*$/i, '$1400')
else photo = photo.replace(/(\?s=)\d*$/i, '$196')
} else {
photo = letterAvatars(profile.username)
}
break
case 'dropbox': case 'dropbox':
// no image api provided, use gravatar // no image api provided, use gravatar
photo = 'https://www.gravatar.com/avatar/' + md5(profile.emails[0].value) photo = 'https://www.gravatar.com/avatar/' + md5(profile.emails[0].value)

View file

@ -64,6 +64,7 @@ function showIndex (req, res, next) {
twitter: config.isTwitterEnable, twitter: config.isTwitterEnable,
github: config.isGitHubEnable, github: config.isGitHubEnable,
gitlab: config.isGitLabEnable, gitlab: config.isGitLabEnable,
mattermost: config.isMattermostEnable,
dropbox: config.isDropboxEnable, dropbox: config.isDropboxEnable,
google: config.isGoogleEnable, google: config.isGoogleEnable,
ldap: config.isLDAPEnable, ldap: config.isLDAPEnable,

View file

@ -33,6 +33,7 @@ if (config.isFacebookEnable) authRouter.use(require('./facebook'))
if (config.isTwitterEnable) authRouter.use(require('./twitter')) if (config.isTwitterEnable) authRouter.use(require('./twitter'))
if (config.isGitHubEnable) authRouter.use(require('./github')) if (config.isGitHubEnable) authRouter.use(require('./github'))
if (config.isGitLabEnable) authRouter.use(require('./gitlab')) if (config.isGitLabEnable) authRouter.use(require('./gitlab'))
if (config.isMattermostEnable) authRouter.use(require('./mattermost'))
if (config.isDropboxEnable) authRouter.use(require('./dropbox')) if (config.isDropboxEnable) authRouter.use(require('./dropbox'))
if (config.isGoogleEnable) authRouter.use(require('./google')) if (config.isGoogleEnable) authRouter.use(require('./google'))
if (config.isLDAPEnable) authRouter.use(require('./ldap')) if (config.isLDAPEnable) authRouter.use(require('./ldap'))

View file

@ -0,0 +1,49 @@
'use strict'
const Router = require('express').Router
const passport = require('passport')
const Mattermost = require('mattermost')
const OAuthStrategy = require('passport-oauth2').Strategy
const config = require('../../../config')
const {setReturnToFromReferer, passportGeneralCallback} = require('../utils')
const mattermost = new Mattermost.Client()
let mattermostAuth = module.exports = Router()
let mattermostStrategy = new OAuthStrategy({
authorizationURL: config.mattermost.baseURL + '/oauth/authorize',
tokenURL: config.mattermost.baseURL + '/oauth/access_token',
clientID: config.mattermost.clientID,
clientSecret: config.mattermost.clientSecret,
callbackURL: config.serverurl + '/auth/mattermost/callback'
}, passportGeneralCallback)
mattermostStrategy.userProfile = (accessToken, done) => {
mattermost.setUrl(config.mattermost.baseURL)
mattermost.token = accessToken
mattermost.useHeaderToken()
mattermost.getMe(
(data) => {
done(null, data)
},
(err) => {
done(err)
}
)
}
passport.use(mattermostStrategy)
mattermostAuth.get('/auth/mattermost', function (req, res, next) {
setReturnToFromReferer(req)
passport.authenticate('oauth2')(req, res, next)
})
// mattermost auth callback
mattermostAuth.get('/auth/mattermost/callback',
passport.authenticate('oauth2', {
successReturnToOrRedirect: config.serverurl + '/',
failureRedirect: config.serverurl + '/'
})
)

View file

@ -76,6 +76,7 @@
"markdown-pdf": "^7.0.0", "markdown-pdf": "^7.0.0",
"mathjax": "~2.7.0", "mathjax": "~2.7.0",
"mermaid": "~7.1.0", "mermaid": "~7.1.0",
"mattermost": "^3.4.0",
"meta-marked": "^0.4.2", "meta-marked": "^0.4.2",
"method-override": "^2.3.7", "method-override": "^2.3.7",
"moment": "^2.17.1", "moment": "^2.17.1",
@ -91,6 +92,7 @@
"passport-google-oauth20": "^1.0.0", "passport-google-oauth20": "^1.0.0",
"passport-ldapauth": "^0.6.0", "passport-ldapauth": "^0.6.0",
"passport-local": "^1.0.0", "passport-local": "^1.0.0",
"passport-oauth2": "^1.4.0",
"passport-twitter": "^1.0.4", "passport-twitter": "^1.0.4",
"passport.socketio": "^3.7.0", "passport.socketio": "^3.7.0",
"pdfobject": "^2.0.201604172", "pdfobject": "^2.0.201604172",

View file

@ -15,7 +15,7 @@
<% if(allowAnonymous) { %> <% if(allowAnonymous) { %>
<a type="button" href="<%- url %>/new" class="btn btn-sm btn-primary"><i class="fa fa-plus"></i> <%= __('New guest note') %></a> <a type="button" href="<%- url %>/new" class="btn btn-sm btn-primary"><i class="fa fa-plus"></i> <%= __('New guest note') %></a>
<% } %> <% } %>
<% if(facebook || twitter || github || gitlab || dropbox || google || ldap || email) { %> <% if(facebook || twitter || github || gitlab || mattermost || dropbox || google || ldap || email) { %>
<button class="btn btn-sm btn-success ui-signin" data-toggle="modal" data-target=".signin-modal"><%= __('Sign In') %></button> <button class="btn btn-sm btn-success ui-signin" data-toggle="modal" data-target=".signin-modal"><%= __('Sign In') %></button>
<% } %> <% } %>
</div> </div>
@ -48,7 +48,7 @@
<% if (errorMessage && errorMessage.length > 0) { %> <% if (errorMessage && errorMessage.length > 0) { %>
<div class="alert alert-danger" style="max-width: 400px; margin: 0 auto;"><%= errorMessage %></div> <div class="alert alert-danger" style="max-width: 400px; margin: 0 auto;"><%= errorMessage %></div>
<% } %> <% } %>
<% if(facebook || twitter || github || gitlab || dropbox || google || ldap || email) { %> <% if(facebook || twitter || github || gitlab || mattermost || dropbox || google || ldap || email) { %>
<span class="ui-signin"> <span class="ui-signin">
<br> <br>
<a type="button" class="btn btn-lg btn-success ui-signin" data-toggle="modal" data-target=".signin-modal" style="min-width: 200px;"><%= __('Sign In') %></a> <a type="button" class="btn btn-lg btn-success ui-signin" data-toggle="modal" data-target=".signin-modal" style="min-width: 200px;"><%= __('Sign In') %></a>

View file

@ -28,6 +28,11 @@
<i class="fa fa-gitlab"></i> <%= __('Sign in via %s', 'GitLab') %> <i class="fa fa-gitlab"></i> <%= __('Sign in via %s', 'GitLab') %>
</a> </a>
<% } %> <% } %>
<% if(mattermost) { %>
<a href="<%- url %>/auth/mattermost" class="btn btn-lg btn-block btn-social btn-soundcloud">
<i class="fa fa-mattermost"></i> <%= __('Sign in via %s', 'Mattermost') %>
</a>
<% } %>
<% if(dropbox) { %> <% if(dropbox) { %>
<a href="<%- url %>/auth/dropbox" class="btn btn-lg btn-block btn-social btn-dropbox"> <a href="<%- url %>/auth/dropbox" class="btn btn-lg btn-block btn-social btn-dropbox">
<i class="fa fa-dropbox"></i> <%= __('Sign in via %s', 'Dropbox') %> <i class="fa fa-dropbox"></i> <%= __('Sign in via %s', 'Dropbox') %>
@ -38,7 +43,7 @@
<i class="fa fa-google"></i> <%= __('Sign in via %s', 'Google') %> <i class="fa fa-google"></i> <%= __('Sign in via %s', 'Google') %>
</a> </a>
<% } %> <% } %>
<% if((facebook || twitter || github || gitlab || dropbox || google) && ldap) { %> <% if((facebook || twitter || github || gitlab || mattermost || dropbox || google) && ldap) { %>
<hr> <hr>
<% }%> <% }%>
<% if(ldap) { %> <% if(ldap) { %>
@ -63,7 +68,7 @@
</div> </div>
</form> </form>
<% } %> <% } %>
<% if((facebook || twitter || github || gitlab || dropbox || google || ldap) && email) { %> <% if((facebook || twitter || github || gitlab || mattermost || dropbox || google || ldap) && email) { %>
<hr> <hr>
<% }%> <% }%>
<% if(email) { %> <% if(email) { %>