1
0
Fork 0

distinguish between 2 legged and 3 legged oauth && other authorization improvements

Dieser Commit ist enthalten in:
Angus McLeod 2019-06-07 13:09:31 +10:00
Ursprung 4f195c704a
Commit b9f8cc61b2
6 geänderte Dateien mit 147 neuen und 93 gelöschten Zeilen

Datei anzeigen

@ -7,16 +7,16 @@ export default Ember.Controller.extend({
queryParams: ['refresh_list'],
loadingSubscriptions: false,
notAuthorized: Ember.computed.not('api.authorized'),
authorizationTypes: ['oauth', 'basic'],
isOauth: Ember.computed.equal('api.authType', 'oauth'),
isBasicAuth: Ember.computed.equal('api.authType', 'basic'),
endpointMethods: ['GET', 'PUT', 'POST', 'PATCH', 'DELETE'],
showRemove: Ember.computed.not('isNew'),
showRedirectUri: Ember.computed.and('threeLeggedOauth', 'api.name'),
responseIcon: null,
@computed('saveDisabled', 'api.authType', 'api.authUrl', 'api.clientId', 'api.clientSecret')
authDisabled(saveDisabled, authType, authUrl, clientId, clientSecret) {
return saveDisabled || !authType || !authUrl || !clientId || !clientSecret;
@computed('saveDisabled', 'api.authType', 'api.authUrl', 'api.tokenUrl', 'api.clientId', 'api.clientSecret', 'threeLeggedOauth')
authDisabled(saveDisabled, authType, authUrl, tokenUrl, clientId, clientSecret, threeLeggedOauth) {
if (saveDisabled || !authType || !tokenUrl || !clientId || !clientSecret) return true;
if (threeLeggedOauth) return !authUrl;
return false;
},
@computed('api.name', 'api.authType')
@ -24,6 +24,17 @@ export default Ember.Controller.extend({
return !name || !authType;
},
authorizationTypes: ['basic', 'oauth_2', 'oauth_3'],
isBasicAuth: Ember.computed.equal('api.authType', 'basic'),
@computed('api.authType')
isOauth(authType) {
return authType && authType.indexOf('oauth') > -1;
},
twoLeggedOauth: Ember.computed.equal('api.authType', 'oauth_2'),
threeLeggedOauth: Ember.computed.equal('api.authType', 'oauth_3'),
actions: {
addParam() {
this.get('api.authParams').pushObject({});
@ -43,23 +54,40 @@ export default Ember.Controller.extend({
authorize() {
const api = this.get('api');
const { authType, authUrl, authParams } = api;
const { name, authType, authUrl, authParams } = api;
if (authType !== 'oauth') return;
this.set('authErrorMessage', '');
let query = '?';
if (authType === 'oauth_2') {
this.set('authorizing', true);
ajax(`/admin/wizards/apis/${name.underscore()}/authorize`).catch(popupAjaxError)
.then(result => {
if (result.success) {
this.set('api', CustomWizardApi.create(result.api));
} else if (result.failed && result.message) {
this.set('authErrorMessage', result.message);
} else {
this.set('authErrorMessage', 'Authorization Failed');
}
setTimeout(() => {
this.set('authErrorMessage', '');
}, 6000);
}).finally(() => this.set('authorizing', false));
} else if (authType === 'oauth_3') {
let query = '?';
query += `client_id=${api.clientId}`;
query += `&redirect_uri=${encodeURIComponent(api.redirectUri)}`;
query += `&response_type=code`;
query += `client_id=${api.clientId}`;
query += `&redirect_uri=${encodeURIComponent(api.redirectUri)}`;
query += `&response_type=code`;
if (authParams) {
authParams.forEach(p => {
query += `&${p.key}=${encodeURIComponent(p.value)}`;
});
if (authParams) {
authParams.forEach(p => {
query += `&${p.key}=${encodeURIComponent(p.value)}`;
});
}
window.location.href = authUrl + query;
}
window.location.href = authUrl + query;
},
save() {
@ -88,10 +116,12 @@ export default Ember.Controller.extend({
let requiredParams;
if (authType === 'oauth') {
requiredParams = ['authUrl', 'tokenUrl', 'clientId', 'clientSecret'];
} else if (authType === 'basic') {
if (authType === 'basic') {
requiredParams = ['username', 'password'];
} else if (authType === 'oauth_2') {
requiredParams = ['tokenUrl', 'clientId', 'clientSecret'];
} else if (authType === 'oauth_3') {
requiredParams = ['authUrl', 'tokenUrl', 'clientId', 'clientSecret'];
}
for (let rp of requiredParams) {

Datei anzeigen

@ -49,6 +49,13 @@
<div class="wizard-api-header">
<div class="buttons">
{{#if isOauth}}
{{#if authorizing}}
{{loading-spinner size="small"}}
{{else}}
{{#if authErrorMessage}}
<span>{{authErrorMessage}}</span>
{{/if}}
{{/if}}
{{d-button label="admin.wizard.api.auth.btn"
action="authorize"
disabled=authDisabled
@ -68,17 +75,15 @@
{{i18n 'admin.wizard.api.auth.settings'}}
</div>
{{#if isOauth}}
{{#if api.name}}
<div class="control-group redirect-uri">
<div class="control-label">
<label>{{i18n 'admin.wizard.api.auth.redirect_uri'}}</label>
<div class="controls">
{{api.redirectUri}}
</div>
{{#if showRedirectUri}}
<div class="control-group redirect-uri">
<div class="control-label">
<label>{{i18n 'admin.wizard.api.auth.redirect_uri'}}</label>
<div class="controls">
{{api.redirectUri}}
</div>
</div>
{{/if}}
</div>
{{/if}}
<div class="control-group auth-type">
@ -89,12 +94,14 @@
</div>
{{#if isOauth}}
<div class="control-group">
<label>{{i18n 'admin.wizard.api.auth.url'}}</label>
<div class="controls">
{{input value=api.authUrl}}
{{#if threeLeggedOauth}}
<div class="control-group">
<label>{{i18n 'admin.wizard.api.auth.url'}}</label>
<div class="controls">
{{input value=api.authUrl}}
</div>
</div>
</div>
{{/if}}
<div class="control-group">
<label>{{i18n 'admin.wizard.api.auth.token_url'}}</label>
@ -165,12 +172,14 @@
{{i18n 'admin.wizard.api.status.label'}}
</div>
<div class="control-group">
<label>{{i18n 'admin.wizard.api.status.code'}}</label>
<div class="controls">
{{api.code}}
{{#if threeLeggedOauth}}
<div class="control-group">
<label>{{i18n 'admin.wizard.api.status.code'}}</label>
<div class="controls">
{{api.code}}
</div>
</div>
</div>
{{/if}}
<div class="control-group">
<label>{{i18n 'admin.wizard.api.status.access_token'}}</label>
@ -179,12 +188,14 @@
</div>
</div>
<div class="control-group">
<label>{{i18n 'admin.wizard.api.status.refresh_token'}}</label>
<div class="controls">
{{api.refreshToken}}
{{#if threeLeggedOauth}}
<div class="control-group">
<label>{{i18n 'admin.wizard.api.status.refresh_token'}}</label>
<div class="controls">
{{api.refreshToken}}
</div>
</div>
</div>
{{/if}}
<div class="control-group">
<label>{{i18n 'admin.wizard.api.status.expires_at'}}</label>

Datei anzeigen

@ -63,6 +63,21 @@ class CustomWizard::ApiController < ::ApplicationController
render json: success_json
end
def authorize
result = CustomWizard::Api::Authorization.get_token(api_params[:name])
if result['error']
render json: failed_json.merge(message: result['error_description'] || result['error'])
else
render json: success_json.merge(
api: CustomWizard::ApiSerializer.new(
CustomWizard::Api.get(api_params[:name]),
root: false
)
)
end
end
def clearlogs
CustomWizard::Api::LogEntry.clear(api_params[:name])
render json: success_json

Datei anzeigen

@ -1,7 +1,7 @@
module Jobs
class RefreshApiAccessToken < Jobs::Base
def execute(args)
CustomWizard::Api::Authorization.refresh_token(args[:name])
CustomWizard::Api::Authorization.get_token(args[:name], refresh: true)
end
end
end

Datei anzeigen

@ -77,71 +77,68 @@ class CustomWizard::Api::Authorization
end
end
def self.get_token(name)
def self.get_token(name, opts = {})
authorization = CustomWizard::Api::Authorization.get(name)
type = authorization.auth_type
body = {
client_id: authorization.client_id,
client_secret: authorization.client_secret,
code: authorization.code,
grant_type: 'authorization_code',
redirect_uri: Discourse.base_url + "/admin/wizards/apis/#{name}/redirect"
}
body = {}
result = Excon.post(
if opts[:refresh] && type === 'oauth_3'
body['grant_type'] = 'refresh_token'
elsif type === 'oauth_2'
body['grant_type'] = 'client_credentials'
elsif type === 'oauth_3'
body['grant_type'] = 'authorization_code'
end
unless opts[:refresh]
body['client_id'] = authorization.client_id
body['client_secret'] = authorization.client_secret
end
if type === 'oauth_3'
body['code'] = authorization.code
body['redirect_uri'] = Discourse.base_url + "/admin/wizards/apis/#{name}/redirect"
end
connection = Excon.new(
authorization.token_url,
:headers => {
"Content-Type" => "application/x-www-form-urlencoded"
},
:body => URI.encode_www_form(body)
:method => 'GET',
:query => URI.encode_www_form(body)
)
self.handle_token_result(name, result)
end
def self.refresh_token(name)
authorization = CustomWizard::Api::Authorization.get(name)
body = {
grant_type: 'refresh_token',
refresh_token: authorization.refresh_token
}
authorization_string = authorization.client_id + ':' + authorization.client_secret
result = Excon.post(
authorization.token_url,
:headers => {
"Content-Type" => "application/x-www-form-urlencoded",
"Authorization" => "Basic #{Base64.strict_encode64(authorization_string)}"
},
:body => URI.encode_www_form(body)
)
result = connection.request()
self.handle_token_result(name, result)
end
def self.handle_token_result(name, result)
data = JSON.parse(result.body)
result_data = JSON.parse(result.body)
return false if (data['error'])
if result_data['error']
return result_data
end
access_token = data['access_token']
refresh_token = data['refresh_token']
expires_at = Time.now + data['expires_in'].seconds
refresh_at = expires_at.to_time - 2.hours
data = {}
opts = {
name: name
}
data['access_token'] = result_data['access_token']
data['refresh_token'] = result_data['refresh_token'] if result_data['refresh_token']
data['token_type'] = result_data['token_type'] if result_data['token_type']
Jobs.enqueue_at(refresh_at, :refresh_api_access_token, opts)
if result_data['expires_in']
data['token_expires_at'] = Time.now + result_data['expires_in'].seconds
data['token_refresh_at'] = data['token_expires_at'].to_time - 10.minutes
CustomWizard::Api::Authorization.set(name,
access_token: access_token,
refresh_token: refresh_token,
token_expires_at: expires_at,
token_refresh_at: refresh_at
)
opts = {
name: name
}
Jobs.enqueue_at(data['token_refresh_at'], :refresh_api_access_token, opts)
end
CustomWizard::Api::Authorization.set(name, data)
end
end

Datei anzeigen

@ -74,6 +74,7 @@ after_initialize do
delete 'admin/wizards/apis/:name' => 'api#remove'
delete 'admin/wizards/apis/logs/:name' => 'api#clearlogs'
get 'admin/wizards/apis/:name/redirect' => 'api#redirect'
get 'admin/wizards/apis/:name/authorize' => 'api#authorize'
end
end