Skip to content

Commit

Permalink
Merge pull request #556 from Sing-Li/gitlab-oauth
Browse files Browse the repository at this point in the history
initial implementation of oauth2 client support for gitlab server flow  #512
  • Loading branch information
engelgabriel committed Aug 23, 2015
2 parents fab6d29 + 8d8fd83 commit 945e2fe
Show file tree
Hide file tree
Showing 20 changed files with 233 additions and 7 deletions.
1 change: 1 addition & 0 deletions .meteor/packages
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,4 @@ raix:[email protected]
jalik:ufs
jalik:ufs-gridfs
monbro:mongodb-mapreduce-aggregation
accounts-gitlab
2 changes: 2 additions & 0 deletions .meteor/versions
7 changes: 3 additions & 4 deletions client/views/login/services.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ Template.loginServices.helpers
authServices = _.pluck ServiceConfiguration.configurations.find({}, { service: 1 }).fetch(), 'service'

authServices.sort()

authServices.forEach (service) ->
switch service
when 'meteor-developer'
Expand All @@ -14,6 +13,9 @@ Template.loginServices.helpers
when 'github'
serviceName = 'GitHub'
icon = 'github-circled'
when 'gitlab'
serviceName = 'Gitlab'
icon = 'git-squared' # need to replace this with proper logo
else
serviceName = _.capitalize service
icon = service
Expand Down Expand Up @@ -49,13 +51,10 @@ Template.loginServices.events
FlowRouter.go 'index'
else
loginWithService = "loginWith" + (if this.service is 'meteor-developer' then 'MeteorDeveloperAccount' else _.capitalize(this.service))

serviceConfig = {}

Meteor[loginWithService] serviceConfig, (error) ->
loadingIcon.addClass 'hidden'
serviceIcon.removeClass 'hidden'

if error
console.log JSON.stringify(error), error.message
toastr.error error.message
Expand Down
1 change: 1 addition & 0 deletions packages/accounts-gitlab/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.build*
3 changes: 3 additions & 0 deletions packages/accounts-gitlab/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# accounts-gitlab

A login service for Gitlab. Courtesy of the [Rocket.Chat](https://rocket.chat/) open source communications platform. See the [project page](https://www.meteor.com/accounts) on Meteor Accounts for more details.
19 changes: 19 additions & 0 deletions packages/accounts-gitlab/gitlab.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Accounts.oauth.registerService('gitlab');

if (Meteor.isClient) {
Meteor.loginWithGitlab = function(options, callback) {
// support a callback without options
if (! callback && typeof options === "function") {
callback = options;
options = null;
}

var credentialRequestCompleteCallback = Accounts.oauth.credentialRequestCompleteHandler(callback);
Gitlab.requestCredential(options, credentialRequestCompleteCallback);
};
} else {
Accounts.addAutopublishFields({
forLoggedInUser: ['services.gitlab'],
forOtherUsers: ['services.gitlab.username']
});
}
3 changes: 3 additions & 0 deletions packages/accounts-gitlab/gitlab_login_button.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions packages/accounts-gitlab/package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Package.describe({
summary: "Login service for Gitlab accounts",
version: "1.0.5-plugins.0"
});

Package.onUse(function(api) {
api.use('accounts-base', ['client', 'server']);
// Export Accounts (etc) to packages using this one.
api.imply('accounts-base', ['client', 'server']);
api.use('accounts-oauth', ['client', 'server']);
api.use('gitlab', ['client', 'server']);

api.addFiles('gitlab_login_button.css', 'client');

api.addFiles("gitlab.js");
});
1 change: 1 addition & 0 deletions packages/gitlab/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.build*
7 changes: 7 additions & 0 deletions packages/gitlab/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# gitlab

An implementation of the GitLab OAuth2 flow. It works with your own private GitLab server instance.

This software is supplied courtesy of the [Rocket.Chat](https://rocket.chat/) open source communications platform.

See the [project page](https://www.meteor.com/accounts) on Meteor Accounts for more details.
38 changes: 38 additions & 0 deletions packages/gitlab/gitlab_client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Request Gitlab credentials for the user
// @param options {optional}
// @param credentialRequestCompleteCallback {Function} Callback function to call on
// completion. Takes one argument, credentialToken on success, or Error on
// error.
Gitlab.requestCredential = function (options, credentialRequestCompleteCallback) {
// support both (options, callback) and (callback).
if (!credentialRequestCompleteCallback && typeof options === 'function') {
credentialRequestCompleteCallback = options;
options = {};
}

var config = ServiceConfiguration.configurations.findOne({service: 'gitlab'});
if (!config) {
credentialRequestCompleteCallback && credentialRequestCompleteCallback(
new ServiceConfiguration.ConfigError());
return;
}

var credentialToken = Random.secret();
var loginStyle = OAuth._loginStyle('gitlab', config, options);

var loginUrl =
Gitlab.ServerURL + '/oauth/authorize' +
'?client_id=' + config.clientId +
'&redirect_uri=' + OAuth._redirectUri('gitlab', config) +
'&response_type=code' +
'&state=' + OAuth._stateParam(loginStyle, credentialToken, options.redirectUrl);

OAuth.launchLogin({
loginService: "gitlab",
loginStyle: loginStyle,
loginUrl: loginUrl,
credentialRequestCompleteCallback: credentialRequestCompleteCallback,
credentialToken: credentialToken,
popupOptions: {width: 900, height: 450}
});
};
3 changes: 3 additions & 0 deletions packages/gitlab/gitlab_common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Gitlab = {};

Gitlab.ServerURL = 'http://corei3:3000'; // this needs to be configured from Settings
14 changes: 14 additions & 0 deletions packages/gitlab/gitlab_configure.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<template name="configureLoginServiceDialogForGitlab">
<p>
First, you'll need to get a Gitlab Client ID. Follow these steps:
</p>
<ol>
<li>
Visit <a href="http://corei3:3000/oauth/applications/new" target="blank">http://corei3:3000/oauth/applications/new</a>
</li>

<li>
Set Authorization callback URL to: <span class="url">{{siteUrl}}_oauth/gitlab</span>
</li>
</ol>
</template>
12 changes: 12 additions & 0 deletions packages/gitlab/gitlab_configure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Template.configureLoginServiceDialogForGitlab.helpers({
siteUrl: function () {
return Meteor.absoluteUrl();
}
});

Template.configureLoginServiceDialogForGitlab.fields = function () {
return [
{property: 'clientId', label: 'Client ID'},
{property: 'secret', label: 'Client Secret'}
];
};
77 changes: 77 additions & 0 deletions packages/gitlab/gitlab_server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
OAuth.registerService('gitlab', 2, null, function(query) {

var accessToken = getAccessToken(query);
console.log('at: ' + accessToken);
var identity = getIdentity(accessToken);
console.log('id: ' + JSON.stringify(identity));
var primaryEmail = identity.email;
console.log('primay: ' + JSON.stringify(primaryEmail));

return {
serviceData: {
id: identity.id,
accessToken: OAuth.sealSecret(accessToken),
email: identity.email || '',
username: identity.username,
emails: [identity.email]
},
options: {profile: {name: identity.username}}
};
});


var userAgent = "Meteor";
if (Meteor.release)
userAgent += "/" + Meteor.release;

var getAccessToken = function (query) {
var config = ServiceConfiguration.configurations.findOne({service: 'gitlab'});
if (!config)
throw new ServiceConfiguration.ConfigError();


var response;
try {
response = HTTP.post(
Gitlab.ServerURL + "/oauth/token", {
headers: {
Accept: 'application/json',
"User-Agent": userAgent
},
params: {
code: query.code,
client_id: config.clientId,
client_secret: OAuth.openSecret(config.secret),
redirect_uri: OAuth._redirectUri('gitlab', config),
grant_type: 'authorization_code',
state: query.state
}
});
} catch (err) {
throw _.extend(new Error("Failed to complete OAuth handshake with Gitlab. " + err.message),
{response: err.response});
}
if (response.data.error) { // if the http response was a json object with an error attribute
throw new Error("Failed to complete OAuth handshake with Gitlab. " + response.data.error);
} else {
return response.data.access_token;
}
};

var getIdentity = function (accessToken) {
try {
return HTTP.get(
Gitlab.ServerURL + "/api/v3/user", {
headers: {"User-Agent": userAgent}, // http://doc.gitlab.com/ce/api/users.html#Current-user
params: {access_token: accessToken}
}).data;
} catch (err) {
throw _.extend(new Error("Failed to fetch identity from Gitlab. " + err.message),
{response: err.response});
}
};


Gitlab.retrieveCredential = function(credentialToken, credentialSecret) {
return OAuth.retrieveCredential(credentialToken, credentialSecret);
};
23 changes: 23 additions & 0 deletions packages/gitlab/package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Package.describe({
summary: "Gitlab OAuth flow",
version: "1.1.4-plugins.0"
});

Package.onUse(function(api) {
api.use('oauth2', ['client', 'server']);
api.use('oauth', ['client', 'server']);
api.use('http', ['server']);
api.use('underscore', 'client');
api.use('templating', 'client');
api.use('random', 'client');
api.use('service-configuration', ['client', 'server']);

api.export('Gitlab');

api.addFiles(
['gitlab_configure.html', 'gitlab_configure.js'],
'client');

api.addFiles(['gitlab_common.js','gitlab_server.js'], 'server');
api.addFiles(['gitlab_common.js','gitlab_client.js'], 'client');
});
4 changes: 4 additions & 0 deletions packages/rocketchat-lib/settings/server/startup.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ Meteor.startup ->
RocketChat.settings.add 'Accounts_Github', false, { type: 'boolean', group: 'Accounts' }
RocketChat.settings.add 'Accounts_Github_id', '', { type: 'string', group: 'Accounts' }
RocketChat.settings.add 'Accounts_Github_secret', '', { type: 'string', group: 'Accounts' }
RocketChat.settings.add 'Accounts_Gitlab', false, { type: 'boolean', group: 'Accounts' }
RocketChat.settings.add 'Accounts_Gitlab_id', '', { type: 'string', group: 'Accounts' }
RocketChat.settings.add 'Accounts_Gitlab_secret', '', { type: 'string', group: 'Accounts' }

RocketChat.settings.add 'Accounts_Linkedin', false, { type: 'boolean', group: 'Accounts' }
RocketChat.settings.add 'Accounts_Linkedin_id', '', { type: 'string', group: 'Accounts' }
RocketChat.settings.add 'Accounts_Linkedin_secret', '', { type: 'string', group: 'Accounts' }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ updateServices = ->
'facebook': 'Facebook'
'google': 'Google'
'github': 'Github'
'gitlab': 'Gitlab'
'linkedin': 'Linkedin'
'meteor-developer': 'Meteor'
'twitter': 'Twitter'
Expand Down
4 changes: 2 additions & 2 deletions server/configuration/accounts_meld.coffee
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
orig_updateOrCreateUserFromExternalService = Accounts.updateOrCreateUserFromExternalService
Accounts.updateOrCreateUserFromExternalService = (serviceName, serviceData, options) ->
if serviceName not in ['facebook', 'github', 'google', 'meteor-developer', 'linkedin', 'twitter']
if serviceName not in ['facebook', 'github', 'gitlab', 'google', 'meteor-developer', 'linkedin', 'twitter']
return

if serviceName is 'meteor-developer'
Expand All @@ -17,7 +17,7 @@ Accounts.updateOrCreateUserFromExternalService = (serviceName, serviceData, opti
serviceData.email = serviceData.emailAddress

if serviceData.email

# Remove not verified users that have same email
notVerifiedUser = Meteor.users.remove({emails: {$elemMatch: {address: serviceData.email, verified: false}}})

Expand Down
4 changes: 3 additions & 1 deletion server/lib/accounts.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ Accounts.onCreateUser (options, user) ->
serviceName = 'google'
else if user.services?.github?
serviceName = 'github'
else if user.services?.gitlab?
serviceName = 'gitlab'
else if user.services?['meteor-developer']?
serviceName = 'meteor-developer'
else if user.services?.twitter?
serviceName = 'twitter'

if serviceName in ['facebook', 'google', 'meteor-developer', 'github', 'twitter']
if serviceName in ['facebook', 'google', 'meteor-developer', 'github', 'gitlab', 'twitter']
if not user?.name? or user.name is ''
if options.profile?.name?
user.name = options.profile?.name
Expand Down

0 comments on commit 945e2fe

Please sign in to comment.