Skip to content

Commit

Permalink
Merge pull request #83 from mulesoft/oauth2-grants
Browse files Browse the repository at this point in the history
Enable addition OAuth 2.0 grant flows
  • Loading branch information
blakeembrey committed Nov 14, 2014
2 parents 5719878 + a476695 commit 806aa78
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 30 deletions.
34 changes: 34 additions & 0 deletions app/scripts/client/auth_strategies/oauth2/credentials_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,40 @@
grant_type: 'authorization_code',
redirect_uri: RAML.Settings.oauth2RedirectUri
};
},

clientCredentialsParameters: function () {
return {
client_id: credentials.clientId,
client_secret: credentials.clientSecret,
grant_type: 'client_credentials'
};
},

resourceOwnerParameters: function () {
var params = {
username: credentials.username,
password: credentials.password,
grant_type: 'password'
};

if (!credentials.clientSecret) {
params.client_id = credentials.clientId;
}

return params;
},

resourceOwnerHeaders: function () {
if (!credentials.clientSecret) {
return {};
}

var authorization = btoa(credentials.clientId + ':' + credentials.clientSecret);

return {
'Authorization': 'Bearer ' + authorization
};
}
};
};
Expand Down
47 changes: 34 additions & 13 deletions app/scripts/client/auth_strategies/oauth2/grant.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
(function() {
'use strict';

var GRANTS = [ 'code', 'token' ], IMPLICIT_GRANT = 'token';
var Oauth2 = RAML.Client.AuthStrategies.Oauth2;

function grantTypeFrom(settings) {
var authorizationGrants = settings.authorizationGrants || [];
var filtered = authorizationGrants.filter(function(grant) { return grant === IMPLICIT_GRANT; });
var specifiedGrant = filtered[0] || authorizationGrants[0];

if (!GRANTS.some(function(grant) { return grant === specifiedGrant; })) {
throw new Error('Unknown grant type: ' + specifiedGrant);
}

return specifiedGrant;
}
var grants = {
code: true,
token: true,
owner: true,
credentials: true
};

var Grant = {
create: function(settings, credentials) {
var type = grantTypeFrom(settings);
var type = credentials.grantType.type;
var credentialsManager = Oauth2.credentialsManager(credentials, type);

if (!grants[type]) {
throw new Error('Unknown grant type: ' + type);
}

var className = type.charAt(0).toUpperCase() + type.slice(1);

return new this[className](settings, credentialsManager);
}
};
Expand All @@ -47,5 +46,27 @@
return Oauth2.requestAuthorization(this.settings, this.credentialsManager);
};

Grant.Owner = function(settings, credentialsManager) {
this.settings = settings;
this.credentialsManager = credentialsManager;
};

Grant.Owner.prototype.request = function() {
var requestToken = Oauth2.requestOwnerToken(this.settings, this.credentialsManager);

return requestToken();
};

Grant.Credentials = function(settings, credentialsManager) {
this.settings = settings;
this.credentialsManager = credentialsManager;
};

Grant.Credentials.prototype.request = function() {
var requestToken = Oauth2.requestCredentialsToken(this.settings, this.credentialsManager);

return requestToken();
};

Oauth2.Grant = Grant;
})();
37 changes: 30 additions & 7 deletions app/scripts/client/auth_strategies/oauth2/request_access_token.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,44 @@
return undefined;
}

function extract(data) {
var method = accessTokenFromString;

if (typeof data === 'object') {
method = accessTokenFromObject;
}

return method(data);
}

RAML.Client.AuthStrategies.Oauth2.requestAccessToken = function(settings, credentialsManager) {
return function(code) {
var request = RAML.Client.Request.create(settings.accessTokenUri, 'post');

request.data(credentialsManager.accessTokenParameters(code));

return $.ajax(request.toOptions()).then(function(data) {
var extract = accessTokenFromString;
return $.ajax(request.toOptions()).then(extract);
};
};

RAML.Client.AuthStrategies.Oauth2.requestCredentialsToken = function(settings, credentialsManager) {
return function() {
var request = RAML.Client.Request.create(settings.accessTokenUri, 'post');

request.data(credentialsManager.clientCredentialsParameters());

return $.ajax(request.toOptions()).then(extract);
};
};

RAML.Client.AuthStrategies.Oauth2.requestOwnerToken = function(settings, credentialsManager) {
return function() {
var request = RAML.Client.Request.create(settings.accessTokenUri, 'post');

if (typeof data === 'object') {
extract = accessTokenFromObject;
}
request.headers(credentialsManager.resourceOwnerHeaders());
request.data(credentialsManager.resourceOwnerParameters());

return extract(data);
});
return $.ajax(request.toOptions()).then(extract);
};
};
})();
32 changes: 32 additions & 0 deletions app/scripts/directives/oauth2.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,43 @@

(function() {
RAML.Directives.oauth2 = function() {

var GRANT_TYPES = [
{ name: 'Implicit', type: 'token' },
{ name: 'Authorization Code', type: 'code' },
{ name: 'Client Credentials', type: 'credentials' },
{ name: 'Resource Owner Password Credentials', type: 'owner' }
];

var controller = function($scope) {
var authorizationGrants = $scope.scheme.settings.authorizationGrants;

$scope.grantTypes = GRANT_TYPES.filter(function (grant) {
return authorizationGrants.indexOf(grant.type) > -1;
});

$scope.credentials = {
clientId: '',
clientSecret: '',
username: '',
password: '',
grantType: $scope.grantTypes[0]
};

$scope.$watch('credentials.grantType.type', function (type) {
$scope.hasClientSecret = type !== 'token';
$scope.hasOwnerCredentials = type === 'owner';
$scope.requiresClientSecret = $scope.hasClientSecret && type !== 'owner';
});
};

return {
restrict: 'E',
templateUrl: 'views/oauth2.tmpl.html',
replace: true,
controller: controller,
scope: {
scheme: '=',
credentials: '='
}
};
Expand Down
3 changes: 2 additions & 1 deletion app/styles/forms.less
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ input.warning {
outline: 0;
}

.required {
.required:before {
content: "* ";
color: @warning;
}

Expand Down
33 changes: 29 additions & 4 deletions app/views/oauth2.tmpl.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,36 @@
<fieldset class="labelled-inline" role="oauth2">
<div class="control-group">
<label for="clientId">Client ID</label>
<input type="text" name="clientId" ng-model='credentials.clientId'/>
<label for="grantType">Grant Type</label>
<select
name="grantType"
ng-model="credentials.grantType"
ng-options="grant.name for grant in grantTypes">
</select>
</div>

<div class="control-group">
<label for="clientSecret">Client Secret</label>
<input type="password" name="clientSecret" ng-model='credentials.clientSecret'/>
<label for="clientId" class="required">Client ID</label>

<input type="text" name="clientId" ng-model="credentials.clientId" required>
</div>

<div class="control-group" ng-if="hasClientSecret">
<label for="clientSecret" ng-class="{ required: requiresClientSecret }">
Client Secret
</label>

<input type="password" name="clientSecret" ng-model="credentials.clientSecret" ng-required="requiresClientSecret">
</div>

<div class="control-group" ng-if="hasOwnerCredentials">
<label for="username" class="required">Username</label>

<input type="text" name="username" ng-model="credentials.username" required>
</div>

<div class="control-group" ng-if="hasOwnerCredentials">
<label for="password" class="required">Password</label>

<input type="password" name="password" ng-model="credentials.password" required>
</div>
</fieldset>
3 changes: 1 addition & 2 deletions app/views/parameter_fields.tmpl.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
<div class="parameter-field" ng-repeat="definition in parameter.definitions" ng-show="parameter.isSelected(definition)">
<div repeatable="definition.repeat" repeatable-model="parameters.values[parameterName]">
<div class="control-group">
<label for="{{parameterName}}">
<span class="required" ng-if="definition.required">*</span>
<label for="{{parameterName}}" ng-class="{ required: definition.required }">
{{definition.displayName}}
</label>
<parameter-field name='parameterName' model='repeatableModel[$index]' definition='definition' ></parameter-field>
Expand Down
6 changes: 3 additions & 3 deletions app/views/security_schemes.tmpl.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ <h2>Authentication</h2>
<toggle-item heading="Anonymous"></toggle-item>
<toggle-item ng-repeat="(name, scheme) in schemes" heading="{{name}}">
<div ng-switch="scheme.type">
<basic-auth ng-switch-when="Basic Authentication" credentials='keychain[name]'></basic-auth>
<oauth1 ng-switch-when="OAuth 1.0" credentials='keychain[name]'></oauth1>
<oauth2 ng-switch-when="OAuth 2.0" credentials='keychain[name]'></oauth2>
<basic-auth ng-switch-when="Basic Authentication" scheme="scheme" credentials="keychain[name]"></basic-auth>
<oauth1 ng-switch-when="OAuth 1.0" scheme="scheme" credentials="keychain[name]"></oauth1>
<oauth2 ng-switch-when="OAuth 2.0" scheme="scheme" credentials="keychain[name]"></oauth2>
</div>
</toggle-item>
</toggle>
Expand Down
4 changes: 4 additions & 0 deletions spec/unit/client/auth_strategies/grant_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ describe("RAML.Client.AuthStrategies.Oauth2.Grant", function() {
beforeEach(function() {
tokenSpy = spyOn(RAML.Client.AuthStrategies.Oauth2.Grant, 'Token');
settings = { authorizationGrants: ['token'] };
credentials.grantType = { type: 'token' };
RAML.Client.AuthStrategies.Oauth2.Grant.create(settings, credentials);
});

Expand All @@ -36,6 +37,7 @@ describe("RAML.Client.AuthStrategies.Oauth2.Grant", function() {
beforeEach(function() {
codeSpy = spyOn(RAML.Client.AuthStrategies.Oauth2.Grant, 'Code');
settings = { authorizationGrants: ['code'] };
credentials.grantType = { type: 'code' };
RAML.Client.AuthStrategies.Oauth2.Grant.create(settings, credentials);
});

Expand All @@ -51,6 +53,7 @@ describe("RAML.Client.AuthStrategies.Oauth2.Grant", function() {
describe("with an unknown authorizationGrant", function() {
beforeEach(function() {
settings = { authorizationGrants: ['unknown'] };
credentials.grantType = { type: 'unknown' };
});

it("throws", function() {
Expand All @@ -63,6 +66,7 @@ describe("RAML.Client.AuthStrategies.Oauth2.Grant", function() {
describe("when no authorizationGrant is present", function() {
beforeEach(function() {
settings = {};
credentials.grantType = {};
});

it("throws", function() {
Expand Down

0 comments on commit 806aa78

Please sign in to comment.