From cd9112052d1f2e2fdf36dd4cf5edfe77381ea8fd Mon Sep 17 00:00:00 2001 From: Jan Schulz-Hofen Date: Tue, 10 Jan 2017 16:50:01 +0100 Subject: [PATCH 3/6] Add OAuth2 provider capability using doorkeeper gem --- Gemfile | 2 + app/controllers/application_controller.rb | 6 ++ app/views/my/account.html.erb | 1 + config/initializers/doorkeeper.rb | 21 +++++++ config/routes.rb | 4 ++ .../20170107092155_create_doorkeeper_tables.rb | 67 +++++++++++++++++++++ lib/redmine.rb | 4 ++ public/images/application_view_tile.png | Bin 0 -> 465 bytes public/stylesheets/application.css | 1 + test/unit/lib/redmine/i18n_test.rb | 4 +- 10 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 config/initializers/doorkeeper.rb create mode 100644 db/migrate/20170107092155_create_doorkeeper_tables.rb create mode 100755 public/images/application_view_tile.png diff --git a/Gemfile b/Gemfile index 6b046ab..16c69f5 100644 --- a/Gemfile +++ b/Gemfile @@ -15,6 +15,8 @@ gem "protected_attributes" gem "actionpack-xml_parser" gem "roadie-rails" gem "mimemagic" +gem "doorkeeper", "~>4.2.0" +gem "doorkeeper-i18n", "~>4.0.0" gem "nokogiri", "~> 1.6.8" diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index dcc693f..3fa0d2e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -112,6 +112,12 @@ class ApplicationController < ActionController::Base if (key = api_key_from_request) # Use API key user = User.find_by_api_key(key) + elsif access_token = Doorkeeper.authenticate(request) + if access_token.accessible? + user = User.active.find_by_id(access_token.resource_owner_id) + else + doorkeeper_render_error + end elsif request.authorization.to_s =~ /\ABasic /i # HTTP Basic, either username/password or API key/random authenticate_with_http_basic do |username, password| diff --git a/app/views/my/account.html.erb b/app/views/my/account.html.erb index 44c75f2..0aed358 100644 --- a/app/views/my/account.html.erb +++ b/app/views/my/account.html.erb @@ -1,6 +1,7 @@
<%= additional_emails_link(@user) %> <%= link_to(l(:button_change_password), {:action => 'password'}, :class => 'icon icon-passwd') if @user.change_password_allowed? %> +<%= link_to(t('doorkeeper.applications.index.title'), oauth_authorized_applications_path, :class => 'icon icon-applications') if Setting.rest_api_enabled? %> <%= call_hook(:view_my_account_contextual, :user => @user)%>
diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb new file mode 100644 index 0000000..b300cd5 --- /dev/null +++ b/config/initializers/doorkeeper.rb @@ -0,0 +1,21 @@ +Doorkeeper.configure do + use_refresh_token + reuse_access_token + realm Redmine::Info.app_name + default_scopes :public + + resource_owner_authenticator do + if Setting.rest_api_enabled? + User.active.find_by_id(session[:user_id]) || redirect_to(signin_path(:back_url => request.original_url)) + else + render(:text => 'Forbidden', :status => 403) + end + end + + admin_authenticator do + if !Setting.rest_api_enabled? || !User.active.where(admin: true).find_by_id(session[:user_id]) + render(:text => 'Forbidden', :status => 403) + end + end + +end diff --git a/config/routes.rb b/config/routes.rb index d4a13bd..bc2af07 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -16,6 +16,10 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Rails.application.routes.draw do + + use_doorkeeper + + root :to => 'welcome#index' root :to => 'welcome#index', :as => 'home' match 'login', :to => 'account#login', :as => 'signin', :via => [:get, :post] diff --git a/db/migrate/20170107092155_create_doorkeeper_tables.rb b/db/migrate/20170107092155_create_doorkeeper_tables.rb new file mode 100644 index 0000000..9c5bedd --- /dev/null +++ b/db/migrate/20170107092155_create_doorkeeper_tables.rb @@ -0,0 +1,67 @@ +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.text :scopes, null: false + 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.text :scopes + end + + add_index :oauth_access_grants, :token, unique: true + add_foreign_key( + :oauth_access_grants, + :oauth_applications, + column: :application_id + ) + add_foreign_key( + :oauth_access_grants, + :users, + column: :resource_owner_id + ) + + create_table :oauth_access_tokens do |t| + t.integer :resource_owner_id + t.references :application + + t.string :token, null: false + + t.string :refresh_token + t.integer :expires_in + t.datetime :revoked_at + t.datetime :created_at, null: false + t.text :scopes + + 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 + ) + add_foreign_key( + :oauth_access_tokens, + :users, + column: :resource_owner_id + ) + end +end diff --git a/lib/redmine.rb b/lib/redmine.rb index e3ff60f..92c80d9 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -245,6 +245,10 @@ Redmine::MenuManager.map :admin_menu do |menu| :html => {:class => 'icon icon-server-authentication'} menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true, :html => {:class => 'icon icon-plugins'} + menu.push :applications, {:controller => 'doorkeeper/applications', :action => 'index'}, :last => true, + :if => Proc.new { Setting.rest_api_enabled? }, + :caption => :'doorkeeper.layouts.admin.nav.applications', + :html => {:class => 'icon icon-applications'} menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true, :html => {:class => 'icon icon-help'} end diff --git a/public/images/application_view_tile.png b/public/images/application_view_tile.png new file mode 100755 index 0000000000000000000000000000000000000000..3bc0bd32fceb21d70368f7842a00a53d6369ba48 GIT binary patch literal 465 zcmV;?0WSWDP)zJNu3H-P zO&@UpeyZQXi7jKe-Hk?r-sue;aDce_XqkvXP+W#F_*ot`jB?BS93Uw71|U^ZjLH`yP%FO7U<6!nLCG} z$SDlW