Project

General

Profile

Feature #24808 » 0003-oauth-Add-OAuth2-provider-capability-using-doorkeepe.patch

Jens Krämer, 2020-07-21 13:05

View differences:

Gemfile
18 18
gem "rbpdf", "~> 1.20.0"
19 19
gem 'addressable'
20 20
gem 'rubyzip', (RUBY_VERSION < '2.4' ? '~> 1.3.0' : '~> 2.3.0')
21
gem "doorkeeper", "~> 4.4.0"
22
gem "doorkeeper-i18n", "~> 4.0"
21 23

  
22 24
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
23 25
gem 'tzinfo-data', platforms: [:mingw, :x64_mingw, :mswin]
app/controllers/application_controller.rb
123 123
      if (key = api_key_from_request)
124 124
        # Use API key
125 125
        user = User.find_by_api_key(key)
126
      elsif access_token = Doorkeeper.authenticate(request)
127
        # Oauth
128
        if access_token.accessible?
129
          user = User.active.find_by_id(access_token.resource_owner_id)
130
        else
131
          doorkeeper_render_error
132
        end
126 133
      elsif /\ABasic /i.match?(request.authorization.to_s)
127 134
        # HTTP Basic, either username/password or API key/random
128 135
        authenticate_with_http_basic do |username, password|
app/views/my/account.html.erb
1 1
<div class="contextual">
2 2
<%= additional_emails_link(@user) %>
3 3
<%= link_to(l(:button_change_password), {:action => 'password'}, :class => 'icon icon-passwd') if @user.change_password_allowed? %>
4
<%= link_to(t('doorkeeper.applications.index.title'), oauth_authorized_applications_path, :class => 'icon icon-applications') if Setting.rest_api_enabled? %>
4 5
<%= call_hook(:view_my_account_contextual, :user => @user)%>
5 6
</div>
6 7

  
config/initializers/doorkeeper.rb
1
Doorkeeper.configure do
2
  use_refresh_token
3
  reuse_access_token
4
  realm           Redmine::Info.app_name
5
  default_scopes  :public
6

  
7
  resource_owner_authenticator do
8
    if Setting.rest_api_enabled?
9
      User.active.find_by_id(session[:user_id]) || redirect_to(signin_path(:back_url => request.original_url))
10
    else
11
      render(:text => 'Forbidden', :status => 403)
12
    end
13
  end
14

  
15
  admin_authenticator do
16
    if !Setting.rest_api_enabled? || !User.active.where(admin: true).find_by_id(session[:user_id])
17
      render(:text => 'Forbidden', :status => 403)
18
    end
19
  end
20

  
21
end
config/routes.rb
18 18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 19

  
20 20
Rails.application.routes.draw do
21

  
22
  use_doorkeeper
23

  
24
  root :to => 'welcome#index'
21 25
  root :to => 'welcome#index', :as => 'home'
22 26

  
23 27
  match 'login', :to => 'account#login', :as => 'signin', :via => [:get, :post]
db/migrate/20170107092155_create_doorkeeper_tables.rb
1
class CreateDoorkeeperTables < ActiveRecord::Migration[4.2]
2
  def change
3
    create_table :oauth_applications do |t|
4
      t.string  :name,         null: false
5
      t.string  :uid,          null: false
6
      t.string  :secret,       null: false
7
      t.text    :redirect_uri, null: false
8
      t.text    :scopes,       null: false
9
      t.boolean :confidential, null: false, default: true
10
      t.timestamps             null: false
11
    end
12

  
13
    add_index :oauth_applications, :uid, unique: true
14

  
15
    create_table :oauth_access_grants do |t|
16
      t.integer  :resource_owner_id, null: false
17
      t.references :application,     null: false
18
      t.string   :token,             null: false
19
      t.integer  :expires_in,        null: false
20
      t.text     :redirect_uri,      null: false
21
      t.datetime :created_at,        null: false
22
      t.datetime :revoked_at
23
      t.text     :scopes
24
    end
25

  
26
    add_index :oauth_access_grants, :token, unique: true
27
    add_foreign_key(
28
      :oauth_access_grants,
29
      :oauth_applications,
30
      column: :application_id
31
    )
32
    add_foreign_key(
33
      :oauth_access_grants,
34
      :users,
35
      column: :resource_owner_id
36
    )
37

  
38
    create_table :oauth_access_tokens do |t|
39
      t.integer  :resource_owner_id
40
      t.references :application
41

  
42
      t.string   :token,                  null: false
43

  
44
      t.string   :refresh_token
45
      t.integer  :expires_in
46
      t.datetime :revoked_at
47
      t.datetime :created_at,             null: false
48
      t.text     :scopes
49

  
50
      t.string   :previous_refresh_token, null: false, default: ""
51
    end
52

  
53
    add_index :oauth_access_tokens, :token, unique: true
54
    add_index :oauth_access_tokens, :resource_owner_id
55
    add_index :oauth_access_tokens, :refresh_token, unique: true
56

  
57
    add_foreign_key(
58
      :oauth_access_tokens,
59
      :oauth_applications,
60
      column: :application_id
61
    )
62
    add_foreign_key(
63
      :oauth_access_tokens,
64
      :users,
65
      column: :resource_owner_id
66
    )
67
  end
68
end
lib/redmine.rb
267 267
            :html => {:class => 'icon icon-settings'}
268 268
  menu.push :ldap_authentication, {:controller => 'auth_sources', :action => 'index'},
269 269
            :html => {:class => 'icon icon-server-authentication'}
270
  menu.push :applications, {:controller => 'doorkeeper/applications', :action => 'index'},
271
            :if => Proc.new { Setting.rest_api_enabled? },
272
            :caption => :'doorkeeper.layouts.admin.nav.applications',
273
            :html => {:class => 'icon icon-applications'}
270 274
  menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true,
271 275
            :html => {:class => 'icon icon-plugins'}
272 276
  menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true,
public/stylesheets/application.css
1544 1544
.icon-workflows { background-image: url(../images/ticket_go.png); }
1545 1545
.icon-custom-fields { background-image: url(../images/textfield.png); }
1546 1546
.icon-plugins { background-image: url(../images/plugin.png); }
1547
.icon-applications { background-image: url(../images/application_view_tile.png); }
1547 1548
.icon-news { background-image: url(../images/news.png); }
1548 1549
.icon-issue-closed { background-image: url(../images/ticket_checked.png); }
1549 1550
.icon-issue-note { background-image: url(../images/ticket_note.png); }
test/unit/lib/redmine/i18n_test.rb
185 185
  def test_languages_options
186 186
    options = languages_options
187 187
    assert options.is_a?(Array)
188
    assert_equal valid_languages.size, options.size
188
    assert_equal valid_languages.select {|locale| ::I18n.exists?(:general_lang_name, locale)}.size, options.size
189 189
    assert_nil options.detect {|option| !option.is_a?(Array)}
190 190
    assert_nil options.detect {|option| option.size != 2}
191 191
    assert_nil options.detect {|option| !option.first.is_a?(String) || !option.last.is_a?(String)}
......
205 205

  
206 206
  def test_locales_validness
207 207
    lang_files_count = Dir["#{Rails.root}/config/locales/*.yml"].size
208
    assert_equal lang_files_count, valid_languages.size
208
    assert_equal lang_files_count, valid_languages.select {|locale| ::I18n.exists?(:general_lang_name, locale)}.size
209 209
    valid_languages.each do |lang|
210 210
      assert set_language_if_valid(lang)
211 211
    end
(14-14/24)