-
-
Notifications
You must be signed in to change notification settings - Fork 730
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement authentication support for Unleash UI.
- Loading branch information
ivaosthu
committed
Jan 16, 2018
1 parent
8eb0fdc
commit 323320b
Showing
20 changed files
with
671 additions
and
197 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Securing Unleash | ||
|
||
TODO: write about how to secure `/api/client` and `/api/admin` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
'use strict'; | ||
|
||
module.exports = class AuthenticationRequired { | ||
constructor({ type, path, message }) { | ||
this.type = type; | ||
this.path = path; | ||
this.message = message; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
'use strict'; | ||
|
||
function extractUsername(req) { | ||
return req.cookies.username || 'unknown'; | ||
return req.user ? req.user.email : 'unknown'; | ||
} | ||
|
||
module.exports = extractUsername; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
'use strict'; | ||
|
||
const User = require('../user'); | ||
const AuthenticationRequired = require('../authentication-required'); | ||
|
||
function unsecureAuthentication(app) { | ||
app.post('/api/admin/login', (req, res) => { | ||
const user = req.body; | ||
req.session.user = new User({ email: user.email }); | ||
res | ||
.status(200) | ||
.json(req.session.user) | ||
.end(); | ||
}); | ||
|
||
app.use('/api/admin/', (req, res, next) => { | ||
if (req.session.user && req.session.user.email) { | ||
req.user = req.session.user; | ||
} | ||
next(); | ||
}); | ||
|
||
app.use('/api/admin/', (req, res, next) => { | ||
if (req.user) { | ||
next(); | ||
} else { | ||
return res | ||
.status('401') | ||
.json( | ||
new AuthenticationRequired({ | ||
path: '/api/admin/login', | ||
type: 'unsecure', | ||
message: | ||
'You have to indetify yourself in order to use Unleash.', | ||
}) | ||
) | ||
.end(); | ||
} | ||
}); | ||
|
||
app.use((req, res, next) => { | ||
// Updates active sessions every hour | ||
req.session.nowInHours = Math.floor(Date.now() / 3600e3); | ||
next(); | ||
}); | ||
} | ||
|
||
module.exports = unsecureAuthentication; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
'use strict'; | ||
|
||
const { Router } = require('express'); | ||
|
||
exports.router = function() { | ||
const router = Router(); | ||
|
||
router.get('/', (req, res) => { | ||
if (req.user) { | ||
return res | ||
.status(200) | ||
.json(req.user) | ||
.end(); | ||
} else { | ||
return res.status(404).end(); | ||
} | ||
}); | ||
|
||
return router; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
'use strict'; | ||
|
||
const gravatar = require('gravatar'); | ||
const assert = require('assert'); | ||
|
||
module.exports = class User { | ||
constructor({ name, email, imageUrl } = {}) { | ||
assert(email, 'Email is required'); | ||
this.email = email; | ||
this.name = name; | ||
this.imageUrl = | ||
imageUrl || gravatar.url(email, { s: '42', d: 'retro' }); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
'use strict'; | ||
|
||
const { test } = require('ava'); | ||
const User = require('./user'); | ||
|
||
test('should create user', t => { | ||
const user = new User({ name: 'ole', email: '[email protected]' }); | ||
t.is(user.name, 'ole'); | ||
t.is(user.email, '[email protected]'); | ||
t.is( | ||
user.imageUrl, | ||
'//www.gravatar.com/avatar/d8ffeba65ee5baf57e4901690edc8e1b?s=42&d=retro' | ||
); | ||
}); | ||
|
||
test('should require email', t => { | ||
const error = t.throws(() => { | ||
const user = new User(); // eslint-disable-line | ||
}, Error); | ||
|
||
t.is(error.message, 'Email is required'); | ||
}); | ||
|
||
test('Should create user with only email defined', t => { | ||
const user = new User({ email: '[email protected]' }); | ||
|
||
t.is(user.email, '[email protected]'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
'use strict'; | ||
|
||
const { test } = require('ava'); | ||
const { setupAppWithAuth } = require('./../../helpers/test-helper'); | ||
|
||
test.serial('creates new feature toggle with createdBy', async t => { | ||
t.plan(1); | ||
const { request, destroy } = await setupAppWithAuth('feature_api_auth'); | ||
// Login | ||
await request.post('/api/admin/login').send({ | ||
email: '[email protected]', | ||
}); | ||
|
||
// create toggle | ||
await request.post('/api/admin/features').send({ | ||
name: 'com.test.Username', | ||
enabled: false, | ||
strategies: [{ name: 'default' }], | ||
}); | ||
|
||
await request | ||
.get('/api/admin/events') | ||
.expect(res => { | ||
t.true(res.body.events[0].createdBy === '[email protected]'); | ||
}) | ||
.then(destroy); | ||
}); | ||
|
||
test.serial('should require authenticated user', async t => { | ||
t.plan(0); | ||
const { request, destroy } = await setupAppWithAuth('feature_api_auth'); | ||
return request | ||
.get('/api/admin/features') | ||
.expect(401) | ||
.then(destroy); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
'use strict'; | ||
|
||
const { test } = require('ava'); | ||
const { setupAppWithCustomAuth } = require('./../../helpers/test-helper'); | ||
const AuthenticationRequired = require('./../../../../lib/authentication-required'); | ||
const User = require('./../../../../lib/user'); | ||
|
||
test.serial('should require authenticated user', async t => { | ||
t.plan(0); | ||
const preHook = app => { | ||
app.use('/api/admin/', (req, res) => | ||
res | ||
.status('401') | ||
.json( | ||
new AuthenticationRequired({ | ||
path: '/api/admin/login', | ||
type: 'custom', | ||
message: `You have to identify yourself.`, | ||
}) | ||
) | ||
.end() | ||
); | ||
}; | ||
const { request, destroy } = await setupAppWithCustomAuth( | ||
'feature_api_custom_auth', | ||
preHook | ||
); | ||
return request | ||
.get('/api/admin/features') | ||
.expect(401) | ||
.then(destroy); | ||
}); | ||
|
||
test.serial('creates new feature toggle with createdBy', async t => { | ||
t.plan(1); | ||
const user = new User({ email: '[email protected]' }); | ||
|
||
const preHook = app => { | ||
app.use('/api/admin/', (req, res, next) => { | ||
req.user = user; | ||
next(); | ||
}); | ||
}; | ||
const { request, destroy } = await setupAppWithCustomAuth( | ||
'feature_api_custom_auth', | ||
preHook | ||
); | ||
|
||
// create toggle | ||
await request.post('/api/admin/features').send({ | ||
name: 'com.test.Username', | ||
enabled: false, | ||
strategies: [{ name: 'default' }], | ||
}); | ||
|
||
await request | ||
.get('/api/admin/events') | ||
.expect(res => { | ||
t.true(res.body.events[0].createdBy === user.email); | ||
}) | ||
.then(destroy); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,36 @@ | ||
'use strict'; | ||
|
||
const { test } = require('ava'); | ||
const { setupApp } = require('./../../helpers/test-helper'); | ||
|
||
test.todo('e2e client feature'); | ||
test.serial('returns three feature toggles', async t => { | ||
const { request, destroy } = await setupApp('feature_api_client'); | ||
return request | ||
.get('/api/client/features') | ||
.expect('Content-Type', /json/) | ||
.expect(200) | ||
.expect(res => { | ||
t.true(res.body.features.length === 3); | ||
}) | ||
.then(destroy); | ||
}); | ||
|
||
test.serial('gets a feature by name', async t => { | ||
t.plan(0); | ||
const { request, destroy } = await setupApp('feature_api_client'); | ||
return request | ||
.get('/api/client/features/featureX') | ||
.expect('Content-Type', /json/) | ||
.expect(200) | ||
.then(destroy); | ||
}); | ||
|
||
test.serial('cant get feature that dose not exist', async t => { | ||
t.plan(0); | ||
const { request, destroy } = await setupApp('feature_api_client'); | ||
return request | ||
.get('/api/client/features/myfeature') | ||
.expect('Content-Type', /json/) | ||
.expect(404) | ||
.then(destroy); | ||
}); |
Oops, something went wrong.