-
-
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.
closes: #233
- Loading branch information
ivaosthu
committed
Jan 17, 2018
1 parent
323320b
commit 04e94b2
Showing
6 changed files
with
250 additions
and
2 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 |
---|---|---|
@@ -1,3 +1,71 @@ | ||
# Securing Unleash | ||
# Secure Unleash | ||
The Unleash API is split in two different paths: `/api/client` and `/api/admin`. | ||
This makes it easy to have different authentication strategy for the admin interface and the client-api used by the applications integrating with Unleash. | ||
|
||
TODO: write about how to secure `/api/client` and `/api/admin` | ||
## General settings | ||
Unleash uses an encrypted cookie to maintain a user session. This allows users to be logged in across instances of Unleash. To protect this cookie you should specify the `secret` option when starting unleash.- | ||
|
||
## Securing the Admin API | ||
In order to secure the Admin API you have to tell Unleash that you are using a custom admin authentication and implement your authentication logic as a preHook. You should also set the secret option to a protected secret in your system. | ||
|
||
```javascript | ||
const unleash = require('unleash-server'); | ||
const myCustomAdminAuth = require('./auth-hook'); | ||
|
||
unleash.start({ | ||
databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', | ||
secret: 'super-duper-secret', | ||
adminAuthentication: 'custom', | ||
preRouterHook: myCustomAdminAuth | ||
}).then(unleash => { | ||
console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); | ||
}); | ||
|
||
``` | ||
|
||
Examples on custom authentication hooks: | ||
- [google-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/google-auth-hook.js) | ||
- [basic-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/basic-auth-hook.js) | ||
|
||
|
||
## Securing the Client API | ||
A common way to support client access is to use pre shared secrets. This can be solved by having clients send a shared key in a http header with every client requests to the Unleash API. All official Unleash clients should support this. | ||
|
||
In the [Java client](https://github.com/Unleash/unleash-client-java#custom-http-headers) this looks like: | ||
|
||
```java | ||
UnleashConfig unleashConfig = UnleashConfig.builder() | ||
.appName("my-app") | ||
.instanceId("my-instance-1") | ||
.unleashAPI(unleashAPI) | ||
.customHttpHeader("Authorization", "12312Random") | ||
.build(); | ||
``` | ||
|
||
On the unleash server side you need to implement a preRouterHook hook which verifies that all calls to `/api/client` includes this pre shared key in the defined header. This could look something like this: | ||
|
||
```javascript | ||
const unleash = require('unleash-server'); | ||
const sharedSecret = '12312Random'; | ||
|
||
unleash.start({ | ||
databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', | ||
enableLegacyRoutes: false, | ||
preRouterHook: (app) => { | ||
app.use('/api/client', (req, res, next) => { | ||
if(req.headers.authorization !== sharedSecret) { | ||
res.sendStatus(401); | ||
} else { | ||
next() | ||
} | ||
}); | ||
} | ||
}).then(unleash => { | ||
console.log(`Unleash started on http://localhost:${unleash.app.get('port')}`); | ||
}); | ||
``` | ||
|
||
[client-auth-unleash.js](https://github.com/Unleash/unleash/blob/master/examples/client-auth-unleash.js) | ||
|
||
|
||
PS! Remember to disable legacy route with by setting the `enableLegacyRoutes` option to false. This will require all your clients to be on v3.x. |
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,30 @@ | ||
'use strict'; | ||
|
||
const auth = require('basic-auth'); | ||
const { User } = require('../lib/server-impl.js'); | ||
|
||
function basicAuthentication(app) { | ||
app.use('/api/admin/', (req, res, next) => { | ||
const credentials = auth(req); | ||
|
||
if (credentials) { | ||
// you will need to do some verification of credentials here. | ||
const user = new User({ email: `${credentials.name}@domain.com` }); | ||
req.user = user; | ||
next(); | ||
} else { | ||
return res | ||
.status('401') | ||
.set({ 'WWW-Authenticate': 'Basic realm="example"' }) | ||
.end('access denied'); | ||
} | ||
}); | ||
|
||
app.use((req, res, next) => { | ||
// Updates active sessions every hour | ||
req.session.nowInHours = Math.floor(Date.now() / 3600e3); | ||
next(); | ||
}); | ||
} | ||
|
||
module.exports = basicAuthentication; |
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,19 @@ | ||
'use strict'; | ||
|
||
// const unleash = require('unleash-server'); | ||
const unleash = require('../lib/server-impl.js'); | ||
|
||
const basicAuth = require('./basic-auth-hook'); | ||
|
||
unleash | ||
.start({ | ||
databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', | ||
secret: 'super-duper-secret', | ||
adminAuthentication: 'custom', | ||
preRouterHook: basicAuth, | ||
}) | ||
.then(server => { | ||
console.log( | ||
`Unleash started on http://localhost:${server.app.get('port')}` | ||
); | ||
}); |
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,27 @@ | ||
'use strict'; | ||
|
||
// const unleash = require('unleash-server'); | ||
const unleash = require('../lib/server-impl.js'); | ||
|
||
// You typically will not hard-code this value in your code! | ||
const sharedSecret = '12312Random'; | ||
|
||
unleash | ||
.start({ | ||
databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', | ||
enableLegacyRoutes: false, | ||
preRouterHook: app => { | ||
app.use('/api/client', (req, res, next) => { | ||
if (req.headers.authorization === sharedSecret) { | ||
next(); | ||
} else { | ||
res.sendStatus(401); | ||
} | ||
}); | ||
}, | ||
}) | ||
.then(server => { | ||
console.log( | ||
`Unleash started on http://localhost:${server.app.get('port')}` | ||
); | ||
}); |
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,85 @@ | ||
'use strict'; | ||
|
||
/** | ||
* Google OAath 2.0 | ||
* | ||
* You should read Using OAuth 2.0 to Access Google APIs: | ||
* https://developers.google.com/identity/protocols/OAuth2 | ||
* | ||
* This example assumes that all users authenticating via | ||
* google should have access. You would proably limit access | ||
* to users you trust. | ||
* | ||
* The implementation assumes the following environement variables: | ||
* | ||
* - GOOGLE_CLIENT_ID | ||
* - GOOGLE_CLIENT_SECRET | ||
* - GOOGLE_CALLBACK_URL | ||
*/ | ||
|
||
// const { User, AuthenticationRequired } = require('unleash-server'); | ||
const { User, AuthenticationRequired } = require('../lib/server-impl.js'); | ||
|
||
const passport = require('passport'); | ||
const GoogleOAuth2Strategy = require('passport-google-auth').Strategy; | ||
|
||
passport.use( | ||
new GoogleOAuth2Strategy( | ||
{ | ||
clientId: process.env.GOOGLE_CLIENT_ID, | ||
clientSecret: process.env.GOOGLE_CLIENT_SECRET, | ||
callbackURL: process.env.GOOGLE_CALLBACK_URL, | ||
}, | ||
|
||
(accessToken, refreshToken, profile, done) => { | ||
done( | ||
null, | ||
new User({ | ||
name: profile.displayName, | ||
email: profile.emails[0].value, | ||
}) | ||
); | ||
} | ||
) | ||
); | ||
|
||
function enableGoogleOauth(app) { | ||
app.use(passport.initialize()); | ||
app.use(passport.session()); | ||
|
||
passport.serializeUser((user, done) => done(null, user)); | ||
passport.deserializeUser((user, done) => done(null, user)); | ||
app.get('/api/admin/login', passport.authenticate('google')); | ||
|
||
app.get( | ||
'/api/auth/callback', | ||
passport.authenticate('google', { | ||
failureRedirect: '/api/admin/error-login', | ||
}), | ||
(req, res) => { | ||
// Successful authentication, redirect to your app. | ||
res.redirect('/'); | ||
} | ||
); | ||
|
||
app.use('/api/admin/', (req, res, next) => { | ||
if (req.user) { | ||
next(); | ||
} else { | ||
// Instruct unleash-frontend to pop-up auth dialog | ||
return res | ||
.status('401') | ||
.json( | ||
new AuthenticationRequired({ | ||
path: '/api/admin/login', | ||
type: 'custom', | ||
message: `You have to identify yourself in order to use Unleash. | ||
Click the button and follow the instructions.`, | ||
}) | ||
) | ||
.end(); | ||
} | ||
}); | ||
} | ||
|
||
module.exports = enableGoogleOauth; |
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,19 @@ | ||
'use strict'; | ||
|
||
// const unleash = require('unleash-server'); | ||
const unleash = require('../lib/server-impl.js'); | ||
|
||
const enableGoogleOauth = require('./google-auth-hook'); | ||
|
||
unleash | ||
.start({ | ||
databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', | ||
secret: 'super-duper-secret', | ||
adminAuthentication: 'custom', | ||
preRouterHook: enableGoogleOauth, | ||
}) | ||
.then(server => { | ||
console.log( | ||
`Unleash started on http://localhost:${server.app.get('port')}` | ||
); | ||
}); |