Merge branch 'private-doorkeeper' into develop
# Conflicts: # app/assets/javascripts/app/controllers/api.coffee
This commit is contained in:
commit
972fb75dfb
12 changed files with 507 additions and 26 deletions
1
Gemfile
1
Gemfile
|
@ -28,6 +28,7 @@ end
|
||||||
|
|
||||||
gem 'autoprefixer-rails'
|
gem 'autoprefixer-rails'
|
||||||
|
|
||||||
|
gem 'doorkeeper'
|
||||||
gem 'oauth2'
|
gem 'oauth2'
|
||||||
|
|
||||||
gem 'omniauth'
|
gem 'omniauth'
|
||||||
|
|
|
@ -82,6 +82,8 @@ GEM
|
||||||
docile (1.1.5)
|
docile (1.1.5)
|
||||||
domain_name (0.5.20160826)
|
domain_name (0.5.20160826)
|
||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
|
doorkeeper (4.2.0)
|
||||||
|
railties (>= 4.2)
|
||||||
eco (1.0.0)
|
eco (1.0.0)
|
||||||
coffee-script
|
coffee-script
|
||||||
eco-source
|
eco-source
|
||||||
|
@ -366,6 +368,7 @@ DEPENDENCIES
|
||||||
daemons
|
daemons
|
||||||
delayed_job_active_record
|
delayed_job_active_record
|
||||||
diffy
|
diffy
|
||||||
|
doorkeeper
|
||||||
eco
|
eco
|
||||||
em-websocket
|
em-websocket
|
||||||
email_verifier
|
email_verifier
|
||||||
|
|
|
@ -78,14 +78,15 @@ class App.ControllerTable extends App.Controller
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
console.log('checkboxClick', e.target)
|
console.log('checkboxClick', e.target)
|
||||||
|
|
||||||
callbackHeader = (header) ->
|
callbackHeader = (headers) ->
|
||||||
console.log('current header is', header)
|
console.log('current header is', headers)
|
||||||
# add new header item
|
# add new header item
|
||||||
attribute =
|
attribute =
|
||||||
name: 'some name'
|
name: 'some name'
|
||||||
display: 'Some Name'
|
display: 'Some Name'
|
||||||
header.push attribute
|
headers.push attribute
|
||||||
console.log('new header is', header)
|
console.log('new header is', headers)
|
||||||
|
headers
|
||||||
|
|
||||||
callbackAttributes = (value, object, attribute, header, refObject) ->
|
callbackAttributes = (value, object, attribute, header, refObject) ->
|
||||||
console.log('data of item col', value, object, attribute, header, refObject)
|
console.log('data of item col', value, object, attribute, header, refObject)
|
||||||
|
|
|
@ -34,20 +34,47 @@ class Index extends App.ControllerSubContent
|
||||||
App.Setting.unsubscribe(@subscribeApplicationId)
|
App.Setting.unsubscribe(@subscribeApplicationId)
|
||||||
|
|
||||||
table = =>
|
table = =>
|
||||||
|
|
||||||
|
callbackHeader = (headers) ->
|
||||||
|
attribute =
|
||||||
|
name: 'view'
|
||||||
|
display: 'View'
|
||||||
|
headers.splice(3, 0, attribute)
|
||||||
|
attribute =
|
||||||
|
name: 'token'
|
||||||
|
display: 'Token'
|
||||||
|
headers.splice(4, 0, attribute)
|
||||||
|
headers
|
||||||
|
|
||||||
|
callbackViewAttributes = (value, object, attribute, header, refObject) ->
|
||||||
|
value = 'X'
|
||||||
|
value
|
||||||
|
|
||||||
|
callbackTokenAttributes = (value, object, attribute, header, refObject) ->
|
||||||
|
value = 'X'
|
||||||
|
value
|
||||||
|
|
||||||
new App.ControllerTable(
|
new App.ControllerTable(
|
||||||
el: @$('.js-appList')
|
el: @$('.js-appList')
|
||||||
model: App.Application
|
model: App.Application
|
||||||
tableId: 'applications'
|
tableId: 'applications'
|
||||||
objects: App.Application.all()
|
objects: App.Application.all()
|
||||||
bindRow:
|
bindRow:
|
||||||
events:
|
events:
|
||||||
'click': @appEdit
|
'click': @appEdit
|
||||||
|
bindCol:
|
||||||
|
view:
|
||||||
|
events:
|
||||||
|
'click': @appView
|
||||||
|
token:
|
||||||
|
events:
|
||||||
|
'click': @appToken
|
||||||
|
callbackHeader: [callbackHeader]
|
||||||
|
callbackAttributes:
|
||||||
|
view: [callbackViewAttributes]
|
||||||
|
token: [callbackTokenAttributes]
|
||||||
)
|
)
|
||||||
table()
|
table()
|
||||||
#App.Application.fetchFull(
|
|
||||||
# table
|
|
||||||
# clear: true
|
|
||||||
#)
|
|
||||||
@subscribeApplicationId = App.Application.subscribe(table, initFetch: true, clear: true)
|
@subscribeApplicationId = App.Application.subscribe(table, initFetch: true, clear: true)
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,6 +109,18 @@ class Index extends App.ControllerSubContent
|
||||||
value = @PasswordAccess.prop('checked')
|
value = @PasswordAccess.prop('checked')
|
||||||
App.Setting.set('api_password_access', value)
|
App.Setting.set('api_password_access', value)
|
||||||
|
|
||||||
|
appToken: (id, e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
new ViewAppTokenModal(
|
||||||
|
app: App.Application.find(id)
|
||||||
|
)
|
||||||
|
|
||||||
|
appView: (id, e) ->
|
||||||
|
e.preventDefault()
|
||||||
|
new ViewAppModal(
|
||||||
|
app: App.Application.find(id)
|
||||||
|
)
|
||||||
|
|
||||||
appNew: (e) ->
|
appNew: (e) ->
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
new App.ControllerGenericNew(
|
new App.ControllerGenericNew(
|
||||||
|
@ -107,4 +146,51 @@ class Index extends App.ControllerSubContent
|
||||||
container: @el.closest('.content')
|
container: @el.closest('.content')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class ViewAppModal extends App.ControllerModal
|
||||||
|
headPrefix: 'App'
|
||||||
|
buttonSubmit: false
|
||||||
|
buttonCancel: true
|
||||||
|
shown: true
|
||||||
|
small: true
|
||||||
|
events:
|
||||||
|
'click .js-select': 'selectAll'
|
||||||
|
|
||||||
|
constructor: (params) ->
|
||||||
|
@head = params.app.name
|
||||||
|
super
|
||||||
|
|
||||||
|
content: ->
|
||||||
|
"AppID: <input class=\"js-select\" type=\"text\" value=\"#{@app.uid}\">
|
||||||
|
<br>
|
||||||
|
Secret: <input class=\"js-select\" type=\"text\" value=\"#{@app.secret}\">"
|
||||||
|
|
||||||
|
class ViewAppTokenModal extends App.ControllerModal
|
||||||
|
headPrefix: 'Generate Token'
|
||||||
|
buttonSubmit: 'Generate Token'
|
||||||
|
buttonCancel: true
|
||||||
|
shown: true
|
||||||
|
small: true
|
||||||
|
events:
|
||||||
|
'click .js-select': 'selectAll'
|
||||||
|
|
||||||
|
constructor: (params) ->
|
||||||
|
@head = params.app.name
|
||||||
|
super
|
||||||
|
|
||||||
|
content: ->
|
||||||
|
"#{App.i18n.translateContent('Generate Access Token for |%s|', App.Session.get().displayNameLong())}"
|
||||||
|
|
||||||
|
onSubmit: =>
|
||||||
|
@ajax(
|
||||||
|
id: 'application_token'
|
||||||
|
type: 'POST'
|
||||||
|
url: "#{@apiPath}/applications/token"
|
||||||
|
processData: true
|
||||||
|
data: JSON.stringify(id: @app.id)
|
||||||
|
success: (data, status, xhr) =>
|
||||||
|
@contentInline = "#{App.i18n.translateContent('New Access Token is')}: <input class=\"js-select\" type=\"text\" value=\"#{data.token}\">"
|
||||||
|
@update()
|
||||||
|
@$('.js-submit').remove()
|
||||||
|
)
|
||||||
|
|
||||||
App.Config.set('API', { prio: 1200, name: 'API', parent: '#system', target: '#system/api', controller: Index, permission: ['admin.api'] }, 'NavBarAdmin')
|
App.Config.set('API', { prio: 1200, name: 'API', parent: '#system', target: '#system/api', controller: Index, permission: ['admin.api'] }, 'NavBarAdmin')
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
class App.Application extends App.Model
|
class App.Application extends App.Model
|
||||||
@configure 'Application', 'name', 'scopes', 'redirect_uri'
|
@configure 'Application', 'name', 'redirect_uri'
|
||||||
@extend Spine.Model.Ajax
|
@extend Spine.Model.Ajax
|
||||||
@url: @apiPath + '/applications'
|
@url: @apiPath + '/applications'
|
||||||
|
|
||||||
@configure_attributes = [
|
@configure_attributes = [
|
||||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
|
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
|
||||||
{ name: 'redirect_uri', display: 'Redirect URI', tag: 'textarea', limit: 250, null: false, note: 'Use one line per URI' },
|
{ name: 'redirect_uri', display: 'Callback URL', tag: 'textarea', limit: 250, null: false, note: 'Use one line per URI' },
|
||||||
{ name: 'scopes', display: 'Scopes', tag: 'input', note: 'Scopes define the access for' },
|
{ name: 'clients', display: 'Clients', tag: 'input', readonly: 1 },
|
||||||
{ name: 'clients', display: 'Clients', tag: 'input', readonly: 1 },
|
|
||||||
{ name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
|
{ name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
|
||||||
{ name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
|
{ name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
|
||||||
]
|
]
|
||||||
@configure_overview = [
|
@configure_overview = [
|
||||||
'name', 'scopes', 'clients'
|
'name', 'redirect_uri', 'clients'
|
||||||
]
|
]
|
||||||
@configure_delete = true
|
@configure_delete = true
|
||||||
|
|
|
@ -51,6 +51,7 @@ curl -u <%= @S('email') %>:some_password <%= @C('http_type') %>://<%= @C('fqdn')
|
||||||
|
|
||||||
<button class="btn js-appNew"><%- @T('New Application') %></button>
|
<button class="btn js-appNew"><%- @T('New Application') %></button>
|
||||||
|
|
||||||
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
@ -59,7 +60,7 @@ OAuth URLs are:
|
||||||
<table class="settings-list" style="width: 100%;">
|
<table class="settings-list" style="width: 100%;">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th width="40%"><%- @T('Title') %>
|
<th width="40%"><%- @T('Action') %>
|
||||||
<th width="60%"><%- @T('URL') %>
|
<th width="60%"><%- @T('URL') %>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -69,9 +70,6 @@ OAuth URLs are:
|
||||||
<tr>
|
<tr>
|
||||||
<td><%- @T('Getting an Access Token') %>
|
<td><%- @T('Getting an Access Token') %>
|
||||||
<td><%= @C('http_type') %>://<%= @C('fqdn') %>/oauth/token
|
<td><%= @C('http_type') %>://<%= @C('fqdn') %>/oauth/token
|
||||||
<tr>
|
|
||||||
<td><%- @T('Revoking Access') %>
|
|
||||||
<td><%= @C('http_type') %>://<%= @C('fqdn') %>/oauth/applications
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -301,7 +301,6 @@ class ApplicationController < ActionController::Base
|
||||||
return authentication_check_prerequesits(user, 'token_auth', auth_param) if user
|
return authentication_check_prerequesits(user, 'token_auth', auth_param) if user
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
|
||||||
# check oauth2 token based authentication
|
# check oauth2 token based authentication
|
||||||
token = Doorkeeper::OAuth::Token.from_bearer_authorization(request)
|
token = Doorkeeper::OAuth::Token.from_bearer_authorization(request)
|
||||||
if token
|
if token
|
||||||
|
@ -309,19 +308,23 @@ class ApplicationController < ActionController::Base
|
||||||
logger.debug "oauth2 token auth check '#{token}'"
|
logger.debug "oauth2 token auth check '#{token}'"
|
||||||
access_token = Doorkeeper::AccessToken.by_token(token)
|
access_token = Doorkeeper::AccessToken.by_token(token)
|
||||||
|
|
||||||
|
if !access_token
|
||||||
|
raise Exceptions::NotAuthorized, 'Invalid token!'
|
||||||
|
end
|
||||||
|
|
||||||
# check expire
|
# check expire
|
||||||
if access_token.expires_in && (access_token.created_at + access_token.expires_in) < Time.zone.now
|
if access_token.expires_in && (access_token.created_at + access_token.expires_in) < Time.zone.now
|
||||||
raise Exceptions::NotAuthorized, 'OAuth2 token is expired!'
|
raise Exceptions::NotAuthorized, 'OAuth2 token is expired!'
|
||||||
end
|
end
|
||||||
|
|
||||||
if access_token.scopes.empty?
|
# if access_token.scopes.empty?
|
||||||
raise Exceptions::NotAuthorized, 'OAuth2 scope missing for token!'
|
# raise Exceptions::NotAuthorized, 'OAuth2 scope missing for token!'
|
||||||
end
|
# end
|
||||||
|
|
||||||
user = User.find(access_token.resource_owner_id)
|
user = User.find(access_token.resource_owner_id)
|
||||||
return authentication_check_prerequesits(user, 'token_auth', auth_param) if user
|
return authentication_check_prerequesits(user, 'token_auth', auth_param) if user
|
||||||
end
|
end
|
||||||
=end
|
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
72
app/controllers/applications_controller.rb
Normal file
72
app/controllers/applications_controller.rb
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
class ApplicationsController < ApplicationController
|
||||||
|
before_action { authentication_check(permission: 'admin.api') }
|
||||||
|
|
||||||
|
def index
|
||||||
|
all = Doorkeeper::Application.all
|
||||||
|
if params[:full]
|
||||||
|
assets = {}
|
||||||
|
item_ids = []
|
||||||
|
all.each { |item|
|
||||||
|
item_ids.push item.id
|
||||||
|
if !assets[:Application]
|
||||||
|
assets[:Application] = {}
|
||||||
|
end
|
||||||
|
application = item.attributes
|
||||||
|
application[:clients] = Doorkeeper::AccessToken.where(application_id: item.id).count
|
||||||
|
assets[:Application][item.id] = application
|
||||||
|
}
|
||||||
|
render json: {
|
||||||
|
record_ids: item_ids,
|
||||||
|
assets: assets,
|
||||||
|
}, status: :ok
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
render json: all, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def token
|
||||||
|
access_token = Doorkeeper::AccessToken.create!(application_id: params[:id], resource_owner_id: current_user.id)
|
||||||
|
render json: { token: access_token.token }, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
application = Doorkeeper::Application.find(params[:id])
|
||||||
|
render json: application, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
application = Doorkeeper::Application.new(clean_params)
|
||||||
|
application.save!
|
||||||
|
render json: application, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
application = Doorkeeper::Application.find(params[:id])
|
||||||
|
application.update_attributes!(clean_params)
|
||||||
|
render json: application, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
application = Doorkeeper::Application.find(params[:id])
|
||||||
|
application.destroy!
|
||||||
|
render json: {}, status: :ok
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def clean_params
|
||||||
|
params_data = params.permit! #.to_h
|
||||||
|
params_data.delete('application')
|
||||||
|
params_data.delete('action')
|
||||||
|
params_data.delete('controller')
|
||||||
|
params_data.delete('id')
|
||||||
|
params_data.delete('uid')
|
||||||
|
params_data.delete('secret')
|
||||||
|
params_data.delete('created_at')
|
||||||
|
params_data.delete('updated_at')
|
||||||
|
params_data
|
||||||
|
end
|
||||||
|
end
|
112
config/initializers/doorkeeper.rb
Normal file
112
config/initializers/doorkeeper.rb
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
Doorkeeper.configure do
|
||||||
|
# Change the ORM that doorkeeper will use (needs plugins)
|
||||||
|
orm :active_record
|
||||||
|
|
||||||
|
# This block will be called to check whether the resource owner is authenticated or not.
|
||||||
|
resource_owner_authenticator do
|
||||||
|
# fail "Please configure doorkeeper resource_owner_authenticator block located in #{__FILE__}"
|
||||||
|
# Put your resource owner authentication logic here.
|
||||||
|
# Example implementation:
|
||||||
|
User.find_by_id(session[:user_id]) || redirect_to(new_user_session_url)
|
||||||
|
end
|
||||||
|
|
||||||
|
# If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below.
|
||||||
|
# admin_authenticator do
|
||||||
|
# # Put your admin authentication logic here.
|
||||||
|
# # Example implementation:
|
||||||
|
# Admin.find_by_id(session[:admin_id]) || redirect_to(new_admin_session_url)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Authorization Code expiration time (default 10 minutes).
|
||||||
|
# authorization_code_expires_in 10.minutes
|
||||||
|
|
||||||
|
# Access token expiration time (default 2 hours).
|
||||||
|
# If you want to disable expiration, set this to nil.
|
||||||
|
# access_token_expires_in 2.hours
|
||||||
|
|
||||||
|
# Assign a custom TTL for implicit grants.
|
||||||
|
# custom_access_token_expires_in do |oauth_client|
|
||||||
|
# oauth_client.application.additional_settings.implicit_oauth_expiration
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Use a custom class for generating the access token.
|
||||||
|
# https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator
|
||||||
|
# access_token_generator '::Doorkeeper::JWT'
|
||||||
|
|
||||||
|
# The controller Doorkeeper::ApplicationController inherits from.
|
||||||
|
# Defaults to ActionController::Base.
|
||||||
|
# https://github.com/doorkeeper-gem/doorkeeper#custom-base-controller
|
||||||
|
# base_controller 'ApplicationController'
|
||||||
|
|
||||||
|
# Reuse access token for the same resource owner within an application (disabled by default)
|
||||||
|
# Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383
|
||||||
|
# reuse_access_token
|
||||||
|
|
||||||
|
# Issue access tokens with refresh token (disabled by default)
|
||||||
|
# use_refresh_token
|
||||||
|
|
||||||
|
# Provide support for an owner to be assigned to each registered application (disabled by default)
|
||||||
|
# Optional parameter confirmation: true (default false) if you want to enforce ownership of
|
||||||
|
# a registered application
|
||||||
|
# Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support
|
||||||
|
# enable_application_owner confirmation: false
|
||||||
|
|
||||||
|
# Define access token scopes for your provider
|
||||||
|
# For more information go to
|
||||||
|
# https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes
|
||||||
|
# default_scopes :public
|
||||||
|
# optional_scopes :write, :update
|
||||||
|
|
||||||
|
# Change the way client credentials are retrieved from the request object.
|
||||||
|
# By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
|
||||||
|
# falls back to the `:client_id` and `:client_secret` params from the `params` object.
|
||||||
|
# Check out the wiki for more information on customization
|
||||||
|
# client_credentials :from_basic, :from_params
|
||||||
|
|
||||||
|
# Change the way access token is authenticated from the request object.
|
||||||
|
# By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
|
||||||
|
# falls back to the `:access_token` or `:bearer_token` params from the `params` object.
|
||||||
|
# Check out the wiki for more information on customization
|
||||||
|
# access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param
|
||||||
|
|
||||||
|
# Change the native redirect uri for client apps
|
||||||
|
# When clients register with the following redirect uri, they won't be redirected to any server and the authorization code will be displayed within the provider
|
||||||
|
# The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL
|
||||||
|
# (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
|
||||||
|
#
|
||||||
|
# native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob'
|
||||||
|
|
||||||
|
# Forces the usage of the HTTPS protocol in non-native redirect uris (enabled
|
||||||
|
# by default in non-development environments). OAuth2 delegates security in
|
||||||
|
# communication to the HTTPS protocol so it is wise to keep this enabled.
|
||||||
|
#
|
||||||
|
# force_ssl_in_redirect_uri !Rails.env.development?
|
||||||
|
|
||||||
|
# Specify what grant flows are enabled in array of Strings. The valid
|
||||||
|
# strings and the flows they enable are:
|
||||||
|
#
|
||||||
|
# "authorization_code" => Authorization Code Grant Flow
|
||||||
|
# "implicit" => Implicit Grant Flow
|
||||||
|
# "password" => Resource Owner Password Credentials Grant Flow
|
||||||
|
# "client_credentials" => Client Credentials Grant Flow
|
||||||
|
#
|
||||||
|
# If not specified, Doorkeeper enables authorization_code and
|
||||||
|
# client_credentials.
|
||||||
|
#
|
||||||
|
# implicit and password grant flows have risks that you should understand
|
||||||
|
# before enabling:
|
||||||
|
# http://tools.ietf.org/html/rfc6819#section-4.4.2
|
||||||
|
# http://tools.ietf.org/html/rfc6819#section-4.4.3
|
||||||
|
#
|
||||||
|
# grant_flows %w(authorization_code client_credentials)
|
||||||
|
|
||||||
|
# Under some circumstances you might want to have applications auto-approved,
|
||||||
|
# so that the user skips the authorization step.
|
||||||
|
# For example if dealing with a trusted application.
|
||||||
|
# skip_authorization do |resource_owner, client|
|
||||||
|
# client.superapp? or resource_owner.admin?
|
||||||
|
# end
|
||||||
|
|
||||||
|
# WWW-Authenticate Realm (default "Doorkeeper").
|
||||||
|
# realm "Doorkeeper"
|
||||||
|
end
|
124
config/locales/doorkeeper.en.yml
Normal file
124
config/locales/doorkeeper.en.yml
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
en:
|
||||||
|
activerecord:
|
||||||
|
attributes:
|
||||||
|
doorkeeper/application:
|
||||||
|
name: 'Name'
|
||||||
|
redirect_uri: 'Redirect URI'
|
||||||
|
errors:
|
||||||
|
models:
|
||||||
|
doorkeeper/application:
|
||||||
|
attributes:
|
||||||
|
redirect_uri:
|
||||||
|
fragment_present: 'cannot contain a fragment.'
|
||||||
|
invalid_uri: 'must be a valid URI.'
|
||||||
|
relative_uri: 'must be an absolute URI.'
|
||||||
|
secured_uri: 'must be an HTTPS/SSL URI.'
|
||||||
|
|
||||||
|
doorkeeper:
|
||||||
|
applications:
|
||||||
|
confirmations:
|
||||||
|
destroy: 'Are you sure?'
|
||||||
|
buttons:
|
||||||
|
edit: 'Edit'
|
||||||
|
destroy: 'Destroy'
|
||||||
|
submit: 'Submit'
|
||||||
|
cancel: 'Cancel'
|
||||||
|
authorize: 'Authorize'
|
||||||
|
form:
|
||||||
|
error: 'Whoops! Check your form for possible errors'
|
||||||
|
help:
|
||||||
|
redirect_uri: 'Use one line per URI'
|
||||||
|
native_redirect_uri: 'Use %{native_redirect_uri} for local tests'
|
||||||
|
scopes: 'Separate scopes with spaces. Leave blank to use the default scopes.'
|
||||||
|
edit:
|
||||||
|
title: 'Edit application'
|
||||||
|
index:
|
||||||
|
title: 'Your applications'
|
||||||
|
new: 'New Application'
|
||||||
|
name: 'Name'
|
||||||
|
callback_url: 'Callback URL'
|
||||||
|
new:
|
||||||
|
title: 'New Application'
|
||||||
|
show:
|
||||||
|
title: 'Application: %{name}'
|
||||||
|
application_id: 'Application Id'
|
||||||
|
secret: 'Secret'
|
||||||
|
scopes: 'Scopes'
|
||||||
|
callback_urls: 'Callback urls'
|
||||||
|
actions: 'Actions'
|
||||||
|
|
||||||
|
authorizations:
|
||||||
|
buttons:
|
||||||
|
authorize: 'Authorize'
|
||||||
|
deny: 'Deny'
|
||||||
|
error:
|
||||||
|
title: 'An error has occurred'
|
||||||
|
new:
|
||||||
|
title: 'Authorization required'
|
||||||
|
prompt: 'Authorize %{client_name} to use your account?'
|
||||||
|
able_to: 'This application will be able to'
|
||||||
|
show:
|
||||||
|
title: 'Authorization code'
|
||||||
|
|
||||||
|
authorized_applications:
|
||||||
|
confirmations:
|
||||||
|
revoke: 'Are you sure?'
|
||||||
|
buttons:
|
||||||
|
revoke: 'Revoke'
|
||||||
|
index:
|
||||||
|
title: 'Your authorized applications'
|
||||||
|
application: 'Application'
|
||||||
|
created_at: 'Created At'
|
||||||
|
date_format: '%Y-%m-%d %H:%M:%S'
|
||||||
|
|
||||||
|
errors:
|
||||||
|
messages:
|
||||||
|
# Common error messages
|
||||||
|
invalid_request: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
|
||||||
|
invalid_redirect_uri: 'The redirect uri included is not valid.'
|
||||||
|
unauthorized_client: 'The client is not authorized to perform this request using this method.'
|
||||||
|
access_denied: 'The resource owner or authorization server denied the request.'
|
||||||
|
invalid_scope: 'The requested scope is invalid, unknown, or malformed.'
|
||||||
|
server_error: 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.'
|
||||||
|
temporarily_unavailable: 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.'
|
||||||
|
|
||||||
|
#configuration error messages
|
||||||
|
credential_flow_not_configured: 'Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.'
|
||||||
|
resource_owner_authenticator_not_configured: 'Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfiged.'
|
||||||
|
|
||||||
|
# Access grant errors
|
||||||
|
unsupported_response_type: 'The authorization server does not support this response type.'
|
||||||
|
|
||||||
|
# Access token errors
|
||||||
|
invalid_client: 'Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method.'
|
||||||
|
invalid_grant: 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.'
|
||||||
|
unsupported_grant_type: 'The authorization grant type is not supported by the authorization server.'
|
||||||
|
|
||||||
|
# Password Access token errors
|
||||||
|
invalid_resource_owner: 'The provided resource owner credentials are not valid, or resource owner cannot be found'
|
||||||
|
|
||||||
|
invalid_token:
|
||||||
|
revoked: "The access token was revoked"
|
||||||
|
expired: "The access token expired"
|
||||||
|
unknown: "The access token is invalid"
|
||||||
|
|
||||||
|
flash:
|
||||||
|
applications:
|
||||||
|
create:
|
||||||
|
notice: 'Application created.'
|
||||||
|
destroy:
|
||||||
|
notice: 'Application deleted.'
|
||||||
|
update:
|
||||||
|
notice: 'Application updated.'
|
||||||
|
authorized_applications:
|
||||||
|
destroy:
|
||||||
|
notice: 'Application revoked.'
|
||||||
|
|
||||||
|
layouts:
|
||||||
|
admin:
|
||||||
|
nav:
|
||||||
|
oauth2_provider: 'OAuth2 Provider'
|
||||||
|
applications: 'Applications'
|
||||||
|
home: 'Home'
|
||||||
|
application:
|
||||||
|
title: 'OAuth authorization required'
|
14
config/routes/applications.rb
Normal file
14
config/routes/applications.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
Zammad::Application.routes.draw do
|
||||||
|
api_path = Rails.configuration.api_path
|
||||||
|
|
||||||
|
match api_path + '/applications', to: 'applications#index', via: :get
|
||||||
|
match api_path + '/applications/:id', to: 'applications#show', via: :get
|
||||||
|
match api_path + '/applications', to: 'applications#create', via: :post
|
||||||
|
match api_path + '/applications/:id', to: 'applications#update', via: :put
|
||||||
|
match api_path + '/applications/token', to: 'applications#token', via: :post
|
||||||
|
|
||||||
|
# oauth2 provider routes
|
||||||
|
use_doorkeeper do
|
||||||
|
skip_controllers :applications, :authorized_applications
|
||||||
|
end
|
||||||
|
end
|
68
db/migrate/20161101131409_create_doorkeeper_tables.rb
Normal file
68
db/migrate/20161101131409_create_doorkeeper_tables.rb
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
class CreateDoorkeeperTables < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :oauth_applications do |t|
|
||||||
|
t.string :name, null: false
|
||||||
|
t.string :uid, null: false
|
||||||
|
t.string :secret, null: false
|
||||||
|
t.text :redirect_uri, null: false
|
||||||
|
t.string :scopes, null: false, default: ''
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :oauth_applications, :uid, unique: true
|
||||||
|
|
||||||
|
create_table :oauth_access_grants do |t|
|
||||||
|
t.integer :resource_owner_id, null: false
|
||||||
|
t.references :application, null: false
|
||||||
|
t.string :token, null: false
|
||||||
|
t.integer :expires_in, null: false
|
||||||
|
t.text :redirect_uri, null: false
|
||||||
|
t.datetime :created_at, null: false
|
||||||
|
t.datetime :revoked_at
|
||||||
|
t.string :scopes
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :oauth_access_grants, :token, unique: true
|
||||||
|
add_foreign_key(
|
||||||
|
:oauth_access_grants,
|
||||||
|
:oauth_applications,
|
||||||
|
column: :application_id
|
||||||
|
)
|
||||||
|
|
||||||
|
create_table :oauth_access_tokens do |t|
|
||||||
|
t.integer :resource_owner_id
|
||||||
|
t.references :application
|
||||||
|
|
||||||
|
# If you use a custom token generator you may need to change this column
|
||||||
|
# from string to text, so that it accepts tokens larger than 255
|
||||||
|
# characters. More info on custom token generators in:
|
||||||
|
# https://github.com/doorkeeper-gem/doorkeeper/tree/v3.0.0.rc1#custom-access-token-generator
|
||||||
|
#
|
||||||
|
# t.text :token, null: false
|
||||||
|
t.string :token, null: false
|
||||||
|
|
||||||
|
t.string :refresh_token
|
||||||
|
t.integer :expires_in
|
||||||
|
t.datetime :revoked_at
|
||||||
|
t.datetime :created_at, null: false
|
||||||
|
t.string :scopes
|
||||||
|
|
||||||
|
# If there is a previous_refresh_token column,
|
||||||
|
# refresh tokens will be revoked after a related access token is used.
|
||||||
|
# If there is no previous_refresh_token column,
|
||||||
|
# previous tokens are revoked as soon as a new access token is created.
|
||||||
|
# Comment out this line if you'd rather have refresh tokens
|
||||||
|
# instantly revoked.
|
||||||
|
t.string :previous_refresh_token, null: false, default: ''
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :oauth_access_tokens, :token, unique: true
|
||||||
|
add_index :oauth_access_tokens, :resource_owner_id
|
||||||
|
add_index :oauth_access_tokens, :refresh_token, unique: true
|
||||||
|
add_foreign_key(
|
||||||
|
:oauth_access_tokens,
|
||||||
|
:oauth_applications,
|
||||||
|
column: :application_id
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue