Azure AD support + defaultReadAccess option + All Pages UI work

This commit is contained in:
NGPixel 2017-04-09 21:13:53 -04:00
parent 5a010f224f
commit 7c1dd8b92a
17 changed files with 206 additions and 116 deletions

View File

@ -21,6 +21,7 @@ defaults:
lang: en
public: false
auth:
defaultReadAccess: false
local:
enabled: true
microsoft:
@ -35,6 +36,8 @@ defaults:
enabled: false
ldap:
enabled: false
azure:
enabled: false
db: mongodb://localhost/wiki
sessionSecret: null
admin: null
@ -55,6 +58,7 @@ defaults:
loggly: false
papertrail: false
rollbar: false
sentry: false
langs:
-
id: en

View File

@ -54,6 +54,7 @@ $(() => {
// ====================================
require('./pages/view.js')(alerts)
require('./pages/all.js')(alerts, socket)
require('./pages/create.js')(alerts, socket)
require('./pages/edit.js')(alerts, socket)
require('./pages/source.js')(alerts)

9
client/js/pages/all.js Normal file
View File

@ -0,0 +1,9 @@
'use strict'
import $ from 'jquery'
module.exports = (alerts, socket) => {
if ($('#page-type-all').length) {
}
}

View File

@ -1,25 +1,52 @@
.has-collapsable-nav {
background-color: mc('blue-grey', '50');
display: flex;
justify-content: flex-start;
align-items: stretch;
}
.collapsable-nav {
width: 300px;
background-color: mc($primary, '500');
background-color: mc('blue-grey', '900');
color: #FFF;
min-height: 80vh;
transition: all .6s ease;
border-left: 1px solid darken(mc('blue-grey', '900'), 5%);
&:last-child {
border-bottom-right-radius: 5px;
}
&.has-children {
width: 50px;
background-color: mc($primary, '500');
border-left: 1px solid mc($primary, '700');
&:nth-child(2) {
border-left: 1px solid darken(mc('blue-grey', '900'), 5%);
}
li {
border-top: none;
display: none;
}
}
li {
display: flex;
border-top: 1px solid mc($primary, '700');
border-top: 1px solid darken(mc('blue-grey', '900'), 5%);
&.is-title {
background-color: mc('blue-grey', '800');
padding: 8px 15px;
color: mc('blue-grey', '300');
font-size: 13px;
letter-spacing: 1px;
text-transform: uppercase;
box-shadow: 0 0 5px rgba(0,0,0,0.3);
margin-right:1px;
}
&.is-active {
display: flex;
@ -32,7 +59,6 @@
a {
height: 50px;
}
}
}
@ -61,40 +87,3 @@
}
}
.collapsable-nav-sub {
width: 300px;
background-color: mc('blue-grey', '800');
border-left: 1px solid mc('blue-grey', '900');
color: #FFF;
min-height: 80vh;
li {
display: flex;
border-top: 1px solid mc('blue-grey', '900');
}
a {
display: flex;
height: 40px;
width: 100%;
align-items: center;
padding: 0 15px;
color: #FFF;
cursor: pointer;
transition: all .4s ease;
background-color: rgba(0,0,0,0);
i {
font-size: 14px;
margin-right: 10px;
}
&:hover {
background-color: rgba(0,0,0,.1);
text-decoration: none;
}
}
}

View File

@ -87,10 +87,6 @@
width: 50px;
aside {
.sidebar-label {
margin-right: 1px;
}
.sidebar-menu li a {
padding: 10px 0;
justify-content: center;

View File

@ -54,6 +54,7 @@ lang: en
public: false
auth:
defaultReadAccess: false
local:
enabled: true
google:
@ -85,6 +86,12 @@ auth:
searchFilter: (uid={{username}})
tlsEnabled: false
tlsCertPath: C:\example\root_ca_cert.crt
azure:
enabled: false
clientID: APP_ID
clientSecret: APP_SECRET_KEY,
resource: '00000002-0000-0000-c000-000000000000',
tenant: 'YOUR_TENANT.onmicrosoft.com'
# ---------------------------------------------------------------------
# Secret key to use when encrypting sessions

View File

@ -94,12 +94,14 @@ router.get('/login/google', passport.authenticate('google', { scope: ['profile',
router.get('/login/facebook', passport.authenticate('facebook', { scope: ['public_profile', 'email'] }))
router.get('/login/github', passport.authenticate('github', { scope: ['user:email'] }))
router.get('/login/slack', passport.authenticate('slack', { scope: ['identity.basic', 'identity.email'] }))
router.get('/login/azure', passport.authenticate('azure_ad_oauth2'))
router.get('/login/ms/callback', passport.authenticate('windowslive', { failureRedirect: '/login', successRedirect: '/' }))
router.get('/login/google/callback', passport.authenticate('google', { failureRedirect: '/login', successRedirect: '/' }))
router.get('/login/facebook/callback', passport.authenticate('facebook', { failureRedirect: '/login', successRedirect: '/' }))
router.get('/login/github/callback', passport.authenticate('github', { failureRedirect: '/login', successRedirect: '/' }))
router.get('/login/slack/callback', passport.authenticate('slack', { failureRedirect: '/login', successRedirect: '/' }))
router.get('/login/azure/callback', passport.authenticate('azure_ad_oauth2', { failureRedirect: '/login', successRedirect: '/' }))
/**
* Logout

View File

@ -2,13 +2,6 @@
/* global appconfig, appdata, db, winston */
const LocalStrategy = require('passport-local').Strategy
const GoogleStrategy = require('passport-google-oauth20').Strategy
const WindowsLiveStrategy = require('passport-windowslive').Strategy
const FacebookStrategy = require('passport-facebook').Strategy
const GitHubStrategy = require('passport-github2').Strategy
const SlackStrategy = require('passport-slack').Strategy
const LdapStrategy = require('passport-ldapauth').Strategy
const fs = require('fs')
module.exports = function (passport) {
@ -34,6 +27,7 @@ module.exports = function (passport) {
// Local Account
if (!appdata.capabilities.manyAuthProviders || (appconfig.auth.local && appconfig.auth.local.enabled)) {
const LocalStrategy = require('passport-local').Strategy
passport.use('local',
new LocalStrategy({
usernameField: 'email',
@ -60,6 +54,7 @@ module.exports = function (passport) {
// Google ID
if (appdata.capabilities.manyAuthProviders && appconfig.auth.google && appconfig.auth.google.enabled) {
const GoogleStrategy = require('passport-google-oauth20').Strategy
passport.use('google',
new GoogleStrategy({
clientID: appconfig.auth.google.clientId,
@ -79,6 +74,7 @@ module.exports = function (passport) {
// Microsoft Accounts
if (appdata.capabilities.manyAuthProviders && appconfig.auth.microsoft && appconfig.auth.microsoft.enabled) {
const WindowsLiveStrategy = require('passport-windowslive').Strategy
passport.use('windowslive',
new WindowsLiveStrategy({
clientID: appconfig.auth.microsoft.clientId,
@ -98,6 +94,7 @@ module.exports = function (passport) {
// Facebook
if (appdata.capabilities.manyAuthProviders && appconfig.auth.facebook && appconfig.auth.facebook.enabled) {
const FacebookStrategy = require('passport-facebook').Strategy
passport.use('facebook',
new FacebookStrategy({
clientID: appconfig.auth.facebook.clientId,
@ -118,6 +115,7 @@ module.exports = function (passport) {
// GitHub
if (appdata.capabilities.manyAuthProviders && appconfig.auth.github && appconfig.auth.github.enabled) {
const GitHubStrategy = require('passport-github2').Strategy
passport.use('github',
new GitHubStrategy({
clientID: appconfig.auth.github.clientId,
@ -138,6 +136,7 @@ module.exports = function (passport) {
// Slack
if (appdata.capabilities.manyAuthProviders && appconfig.auth.slack && appconfig.auth.slack.enabled) {
const SlackStrategy = require('passport-slack').Strategy
passport.use('slack',
new SlackStrategy({
clientID: appconfig.auth.slack.clientId,
@ -157,6 +156,7 @@ module.exports = function (passport) {
// LDAP
if (appdata.capabilities.manyAuthProviders && appconfig.auth.ldap && appconfig.auth.ldap.enabled) {
const LdapStrategy = require('passport-ldapauth').Strategy
passport.use('ldapauth',
new LdapStrategy({
server: {
@ -187,6 +187,32 @@ module.exports = function (passport) {
))
}
// AZURE AD
if (appdata.capabilities.manyAuthProviders && appconfig.auth.azure && appconfig.auth.azure.enabled) {
const AzureAdOAuth2Strategy = require('passport-azure-ad-oauth2').Strategy
const jwt = require('jsonwebtoken')
passport.use('azure_ad_oauth2',
new AzureAdOAuth2Strategy({
clientID: appconfig.auth.azure.clientId,
clientSecret: appconfig.auth.azure.clientSecret,
callbackURL: appconfig.host + '/login/azure/callback',
resource: appconfig.auth.azure.resource,
tenant: appconfig.auth.azure.tenant
},
(accessToken, refreshToken, params, profile, cb) => {
let waadProfile = jwt.decode(params.id_token)
waadProfile.id = waadProfile.oid
waadProfile.provider = 'azure'
db.User.processProfile(waadProfile).then((user) => {
return cb(null, user) || true
}).catch((err) => {
return cb(err, null) || true
})
}
))
}
// Create users for first-time
db.onReady.then(() => {

View File

@ -1,7 +1,5 @@
'use strict'
/* global winston */
const fs = require('fs')
const yaml = require('js-yaml')
const _ = require('lodash')
@ -25,7 +23,7 @@ module.exports = (confPaths) => {
appconfig = yaml.safeLoad(fs.readFileSync(confPaths.config, 'utf8'))
appdata = yaml.safeLoad(fs.readFileSync(confPaths.data, 'utf8'))
} catch (ex) {
winston.error(ex)
console.error(ex)
process.exit(1)
}
@ -41,7 +39,7 @@ module.exports = (confPaths) => {
socialEnabled: (_.chain(appconfig.auth).omit('local').reject({ enabled: false }).value().length > 0)
}
if (appconfig.authStrategies.list.length < 1) {
winston.error(new Error('You must enable at least 1 authentication strategy!'))
console.error(new Error('You must enable at least 1 authentication strategy!'))
process.exit(1)
}
} else {

View File

@ -2,10 +2,11 @@
"providers": {
"local": "Local",
"windowslive": "Microsoft Account",
"azure": "Azure Active Directory",
"google": "Google ID",
"facebook": "Facebook",
"github": "GitHub",
"slack": "Slack",
"ldap": "LDAP / Active Directory"
}
}
}

View File

@ -72,9 +72,8 @@ userSchema.statics.processProfile = (profile) => {
}, {
new: true
}).then((user) => {
// LDAP - Handle unregistered accounts
// Todo: Allow this behavior for any provider...
if (!user && profile.provider === 'ldap') {
// Handle unregistered accounts
if (!user && profile.provider !== 'local' && (appconfig.auth.defaultReadAccess || profile.provider === 'ldap' || profile.provider === 'azure')) {
let nUsr = {
email: primaryEmail,
provider: profile.provider,

View File

@ -70,6 +70,7 @@
"image-size": "^0.5.1",
"jimp": "github:ngpixel/jimp",
"js-yaml": "^3.8.3",
"jsonwebtoken": "^7.3.0",
"klaw": "^1.3.1",
"levelup": "^1.3.5",
"lodash": "^4.17.3",
@ -91,6 +92,7 @@
"multer": "^1.2.1",
"ora": "^1.2.0",
"passport": "^0.3.2",
"passport-azure-ad-oauth2": "0.0.4",
"passport-facebook": "^2.1.1",
"passport-github2": "^0.1.10",
"passport-google-oauth20": "^1.0.0",

View File

@ -47,6 +47,10 @@ html(data-logic='login')
button.ms(onclick='window.location.assign("/login/ms")')
i.icon-windows2
span Microsoft Account
if appconfig.auth.azure && appconfig.auth.azure.enabled
button.ms(onclick='window.location.assign("/login/azure")')
i.icon-windows2
span Azure AD
if appconfig.auth.google && appconfig.auth.google.enabled
button.google(onclick='window.location.assign("/login/google")')
i.icon-google

View File

@ -36,6 +36,7 @@ block adminContent
case user.provider
when 'local': i.icon-server
when 'windowslive': i.icon-windows2.is-blue
when 'azure': i.icon-windows2.is-blue
when 'google': i.icon-google.is-blue
when 'facebook': i.icon-facebook.is-indigo
when 'github': i.icon-github.is-grey

View File

@ -30,6 +30,9 @@ block adminContent
when 'windowslive'
i.icon-windows2.is-blue
| Microsoft Account
when 'azure'
i.icon-windows2.is-blue
| Azure Active Directory
when 'google'
i.icon-google.is-blue
| Google ID

View File

@ -37,6 +37,9 @@ block adminContent
when 'windowslive'
i.icon-windows2.is-blue
| Microsoft Account
when 'azure'
i.icon-windows2.is-blue
| Azure Active Directory
when 'google'
i.icon-google.is-blue
| Google ID

View File

@ -7,61 +7,106 @@ block content
#page-type-all
.container.is-fluid.has-collapsable-nav
.columns.is-gapless
.column.is-narrow.is-hidden-touch.sidebar.is-collapsed
aside
.sidebar-label
span NAV
ul.sidebar-menu
.sidebar.is-collapsed
aside
.sidebar-label
span NAV
ul.sidebar-menu
li
a(href='/')
i.icon-home
span Home
if !isGuest
li
a(href='/')
i.icon-home
span Home
if !isGuest
li
a(href='/admin')
i.icon-head
span Account
else
li
a(href='/login')
i.icon-unlock
span Login
.column.is-narrow
ul.collapsable-nav.has-children
li: a
i.icon-file
span Page 1
li: a
i.icon-file
span Page 2
li: a
i.icon-file
span Page 3
li.is-active: a
i.icon-folder2
span Page 4
li: a
i.icon-file
span Page 5
.column.is-narrow
ul.collapsable-nav-sub
li: a
i.icon-file
span Page 1
li: a
i.icon-file
span Page 2
li: a
i.icon-file
span Page 3
li: a
i.icon-file
span Page 4
li: a
i.icon-file
span Page 5
a(href='/admin')
i.icon-head
span Account
else
li
a(href='/login')
i.icon-unlock
span Login
ul.collapsable-nav.has-children
li: a
i.icon-file
span Page 1
li: a
i.icon-file
span Page 2
li: a
i.icon-file
span Page 3
li.is-active: a
i.icon-folder2
span Page 4
li: a
i.icon-file
span Page 5
ul.collapsable-nav.has-children
li.is-title page-4
li: a
i.icon-file
span Page 1
li.is-active: a
i.icon-file
span Page 2
li: a
i.icon-file
span Page 3
li: a
i.icon-file
span Page 4
li: a
i.icon-file
span Page 5
ul.collapsable-nav.has-children
li.is-title page-4
li: a
i.icon-file
span Page 1
li.is-active: a
i.icon-file
span Page 2
li: a
i.icon-file
span Page 3
li: a
i.icon-file
span Page 4
li: a
i.icon-file
span Page 5
ul.collapsable-nav.has-children
li.is-title page-4
li: a
i.icon-file
span Page 1
li.is-active: a
i.icon-file
span Page 2
li: a
i.icon-file
span Page 3
li: a
i.icon-file
span Page 4
li: a
i.icon-file
span Page 5
ul.collapsable-nav
li.is-title Sub-Pages
li: a
i.icon-file
span Page 1
li: a
i.icon-file
span Page 2
li: a
i.icon-file
span Page 3
li: a
i.icon-file
span Page 4
li: a
i.icon-file
span Page 5