distinguish between 2 legged and 3 legged oauth && other authorization improvements
Dieser Commit ist enthalten in:
Ursprung
4f195c704a
Commit
b9f8cc61b2
6 geänderte Dateien mit 147 neuen und 93 gelöschten Zeilen
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Laden …
In neuem Issue referenzieren