summaryrefslogtreecommitdiffstats
path: root/test/system/oauth_provider_test.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/system/oauth_provider_test.rb')
-rw-r--r--test/system/oauth_provider_test.rb131
1 files changed, 131 insertions, 0 deletions
diff --git a/test/system/oauth_provider_test.rb b/test/system/oauth_provider_test.rb
new file mode 100644
index 000000000..897af72c0
--- /dev/null
+++ b/test/system/oauth_provider_test.rb
@@ -0,0 +1,131 @@
+# frozen_string_literal: true
+
+require_relative '../application_system_test_case'
+require 'oauth2'
+require 'webrick'
+
+class OauthProviderSystemTest < ApplicationSystemTestCase
+ fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
+ :trackers, :projects_trackers, :enabled_modules, :issue_statuses, :issues,
+ :enumerations, :custom_fields, :custom_values, :custom_fields_trackers,
+ :watchers, :journals, :journal_details, :versions,
+ :workflows
+
+ test 'application creation and authorization' do
+ #
+ # admin creates the application, granting permissions and generating a uuid
+ # and secret.
+ #
+ log_user 'admin', 'admin'
+ with_settings rest_api_enabled: 1 do
+ visit '/admin'
+ within 'div#admin-menu ul' do
+ click_link 'Applications'
+ end
+ click_link 'New Application'
+ fill_in 'Name', with: 'Oauth Test'
+
+ # as per https://tools.ietf.org/html/rfc8252#section-7.3, the port can be
+ # anything when the redirect URI's host is 127.0.0.1.
+ fill_in 'Redirect URI', with: 'http://127.0.0.1'
+
+ check 'View Issues'
+ click_button 'Create'
+ end
+
+ assert_text "Application created"
+
+ assert app = Doorkeeper::Application.find_by_name('Oauth Test')
+
+ find 'h2', visible: true, text: /Oauth Test/
+ find 'p code', visible: true, text: app.uid
+ find 'p strong', visible: true, text: /will not be shown again/
+ find 'p code', visible: true, text: /View Issues/
+
+ # scrape the clear text secret from the page
+ app_secret = all(:css, 'p code')[1].text
+
+ click_link 'Sign out'
+
+ #
+ # regular user authorizes the application
+ #
+ client = OAuth2::Client.new(app.uid, app_secret, site: "http://127.0.0.1:#{test_port}/")
+
+ # set up a dummy http listener to handle the redirect
+ port = rand 10000..20000
+ redirect_uri = "http://127.0.0.1:#{port}"
+ # the request handler below will set this to the auth token
+ token = nil
+
+ # launches webrick, listening for the redirect with the auth code.
+ launch_client_app(port: port) do |req, res|
+ # get access code from code url param
+ if code = req.query['code'].presence
+ # exchange it for token
+ token = client.auth_code.get_token(code, redirect_uri: redirect_uri)
+ res.body = "<html><body><p>Authorization succeeded, you may close this window now.</p></body></html>"
+ end
+ end
+
+ log_user 'jsmith', 'jsmith'
+ with_settings rest_api_enabled: 1 do
+ visit '/my/account'
+ click_link 'Authorized applications'
+ find 'p.nodata', visible: true
+
+ # an oauth client would send the user to this url to request permission
+ url = client.auth_code.authorize_url redirect_uri: redirect_uri, scope: 'view_issues view_project'
+ uri = URI.parse url
+ visit uri.path + '?' + uri.query
+
+ find 'h2', visible: true, text: 'Authorization required'
+ find 'p', visible: true, text: /Authorize Oauth Test/
+ find '.oauth-permissions', visible: true, text: /View Issues/
+ find '.oauth-permissions', visible: true, text: /View project/
+
+ click_button 'Authorize'
+
+ assert grant = app.access_grants.last
+ assert_equal 'view_issues view_project', grant.scopes.to_s
+
+ # check for output defined above in the request handler
+ find 'p', visible: true, text: /Authorization succeeded/
+ assert token.present?
+
+ visit '/my/account'
+ click_link 'Authorized applications'
+ find 'td', visible: true, text: /Oauth Test/
+ click_link 'Sign out'
+
+ # Now, use the token for some API requests
+ assert_raise(RestClient::Unauthorized) do
+ RestClient.get "http://localhost:#{test_port}/projects/onlinestore/issues.json"
+ end
+
+ headers = { 'Authorization' => "Bearer #{token.token}" }
+ r = RestClient.get "http://localhost:#{test_port}/projects/onlinestore/issues.json", headers
+ issues = JSON.parse(r.body)['issues']
+ assert issues.any?
+
+ # time entries access is not part of the granted scopes
+ assert_raise(RestClient::Forbidden) do
+ RestClient.get "http://localhost:#{test_port}/projects/onlinestore/time_entries.json", headers
+ end
+ end
+ end
+
+ private
+
+ def launch_client_app(port: 12345, path: '/', &block)
+ server = WEBrick::HTTPServer.new Port: port
+ trap('INT') { server.shutdown }
+ server.mount_proc(path, block)
+ Thread.new { server.start }
+ port
+ end
+
+ def test_port
+ Capybara.current_session.server.port
+ end
+end