Skip to content

Commit

Permalink
add DigitalOcean provider (hapijs#312)
Browse files Browse the repository at this point in the history
* add digitalocean provider

* add DigitalOcean to provider documentation

* remove unused options from DigitalOcean provider

* add DigitalOcean to supported provides in Readme
  • Loading branch information
marcuspoehls authored and ldesplat committed May 9, 2017
1 parent 3f64290 commit d80b6f9
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 1 deletion.
21 changes: 21 additions & 0 deletions Providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,27 @@ credentials.profile = {
};
```

### DigitalOcean

[Provider Documentation](https://developers.digitalocean.com/documentation/oauth)

- `scope`: defaults to `read` scope
- `config`: not applicable
- `auth`: https://cloud.digitalocean.com/v1/oauth/authorize
- `token`: https://cloud.digitalocean.com/v1/oauth/token

The default profile response will look like this:

```javascript
credentials.profile = {
id: profile.account.uuid,
email: profile.account.email,
status: profile.account.status,
dropletLimit: profile.account.droplet_limit,
raw: profile.account
};
```

### Discord

[Provider Documentation](https://discordapp.com/developers/docs/topics/oauth2)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Lead Maintainer: [Lois Desplat](https://github.com/ldesplat)

[![Build Status](https://secure.travis-ci.org/hapijs/bell.png)](http://travis-ci.org/hapijs/bell)

**bell** ships with built-in support for authentication using `Facebook`, `GitHub`, `Google`, `Google Plus`, `Instagram`, `LinkedIn`, `Slack`, `Twitter`, `Yahoo`, `Foursquare`, `VK`, `ArcGIS Online`, `Windows Live`, `Nest`, `Phabricator`, `BitBucket`, `Dropbox`, `Reddit`, `Tumblr`, `Twitch`, `Salesforce`, `Pinterest`, `Discord`, and `Okta`. It also supports any compliant `OAuth 1.0a` and `OAuth 2.0` based login services with a simple configuration object.
**bell** ships with built-in support for authentication using `Facebook`, `GitHub`, `Google`, `Google Plus`, `Instagram`, `LinkedIn`, `Slack`, `Twitter`, `Yahoo`, `Foursquare`, `VK`, `ArcGIS Online`, `Windows Live`, `Nest`, `Phabricator`, `BitBucket`, `Dropbox`, `Reddit`, `Tumblr`, `Twitch`, `Salesforce`, `Pinterest`, `Discord`, `DigitalOcean`, and `Okta`. It also supports any compliant `OAuth 1.0a` and `OAuth 2.0` based login services with a simple configuration object.

## Documentation

Expand Down
31 changes: 31 additions & 0 deletions lib/providers/digitalocean.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';

exports = module.exports = function () {

const digitalOceanUrl = 'https://cloud.digitalocean.com/v1/oauth';
const digitalOceanUserUrl = 'https://api.digitalocean.com/v2/account';

return {
protocol: 'oauth2',
useParamsAuth: true,
auth: digitalOceanUrl + '/authorize',
token: digitalOceanUrl + '/token',
profile: function (credentials, params, get, callback) {

get(digitalOceanUserUrl, null, (profile) => {

const account = profile.account;

credentials.profile = {
id: account.uuid,
email: account.email,
status: account.status,
dropletLimit: account.droplet_limit,
raw: account
};

return callback();
});
}
};
};
1 change: 1 addition & 0 deletions lib/providers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ exports = module.exports = {
auth0: require('./auth0'),
azuread: require('./azuread'),
bitbucket: require('./bitbucket'),
digitalocean: require('./digitalocean'),
discord: require('./discord'),
dropbox: require('./dropbox'),
facebook: require('./facebook'),
Expand Down
176 changes: 176 additions & 0 deletions test/providers/digitalocean.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
'use strict';

// Load modules

const Bell = require('../../');
const Code = require('code');
const Hapi = require('hapi');
const Hoek = require('hoek');
const Lab = require('lab');
const Mock = require('../mock');


// Test shortcuts

const lab = exports.lab = Lab.script();
const describe = lab.describe;
const it = lab.it;
const expect = Code.expect;


describe('digitalocean', () => {

it('authenticates with mock', { parallel: false }, (done) => {

const mock = new Mock.V2();
mock.start((provider) => {

const server = new Hapi.Server();
server.connection({ host: 'localhost', port: 80 });
server.register(Bell, (err) => {

expect(err).to.not.exist();

const custom = Bell.providers.digitalocean();
Hoek.merge(custom, provider);

const data = {
account: {
uuid: '1234',
email: 'stevesmith@test.com',
status: 'active',
droplet_limit: 3
}
};

Mock.override('https://api.digitalocean.com/v2/account', data);

server.auth.strategy('custom', 'bell', {
password: 'cookie_encryption_password_secure',
isSecure: false,
clientId: 'digitalocean',
clientSecret: 'secret',
provider: custom
});

server.route({
method: '*',
path: '/login',
config: {
auth: 'custom',
handler: function (request, reply) {

reply(request.auth.credentials);
}
}
});

server.inject('/login', (res) => {

const cookie = res.headers['set-cookie'][0].split(';')[0] + ';';
mock.server.inject(res.headers.location, (mockRes) => {

server.inject({ url: mockRes.headers.location, headers: { cookie } }, (response) => {

Mock.clear();
expect(response.result).to.equal({
provider: 'custom',
token: '456',
expiresIn: 3600,
secret: 'secret',
query: {},
profile: {

id: data.account.uuid,
email: data.account.email,
status: data.account.status,
dropletLimit: data.account.droplet_limit,
raw: data.account
}
});

mock.stop(done);
});
});
});
});
});
});

it('authenticates with mock when user has no email set', { parallel: false }, (done) => {

const mock = new Mock.V2();
mock.start((provider) => {

const server = new Hapi.Server();
server.connection({ host: 'localhost', port: 80 });
server.register(Bell, (err) => {

expect(err).to.not.exist();

const custom = Bell.providers.digitalocean();
Hoek.merge(custom, provider);

const data = {
account: {
uuid: '1234',
status: 'active',
dropletLimit: 3
}
};

Mock.override('https://api.digitalocean.com/v2/account', data);

server.auth.strategy('custom', 'bell', {
password: 'cookie_encryption_password_secure',
isSecure: false,
clientId: 'digitalocean',
clientSecret: 'secret',
provider: custom
});

server.route({
method: '*',
path: '/login',
config: {
auth: 'custom',
handler: function (request, reply) {

reply(request.auth.credentials);

}
}
});

server.inject('/login', (res) => {

const cookie = res.headers['set-cookie'][0].split(';')[0] + ';';
mock.server.inject(res.headers.location, (mockRes) => {

server.inject({ url: mockRes.headers.location, headers: { cookie } }, (response) => {

Mock.clear();
expect(response.result).to.equal({
provider: 'custom',
token: '456',
expiresIn: 3600,
secret: 'secret',
query: {},
profile: {

id: data.account.uuid,
email: undefined,
status: data.account.status,
dropletLimit: data.account.droplet_limit,
raw: data.account
}
});

mock.stop(done);
});
});
});
});
});
});
});

0 comments on commit d80b6f9

Please sign in to comment.