diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 38059333c1e0..138e35d3b0bb 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -574,8 +574,10 @@ jQuery(document).ready(function($) { var header = 'X-CSRF-Token', token = csrf_meta_tag.attr('content'); - request.setRequestHeader[header] = token; + request.setRequestHeader(header, token); } + + request.setRequestHeader('X-Authentication-Scheme', "Session"); }); // ajaxStop gets called when ALL Requests finish, so we won't need a counter as in PT $(document).ajaxStop(function () { diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d28ab13110fb..56e49671bbce 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -186,7 +186,17 @@ def require_login end respond_to do |format| format.any(:html, :atom) { redirect_to signin_path(:back_url => url) } - format.any(:xml, :js, :json) { head :unauthorized, "Reason" => "login needed" } + + authentication_scheme = if request.headers["X-Authentication-Scheme"] == "Session" + 'Session' + else + 'Basic' + end + format.any(:xml, :js, :json) { + head :unauthorized, + "Reason" => "login needed", + 'WWW-Authenticate' => authentication_scheme + ' realm="OpenProject API"' + } end return false end diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index f4d8f6d88f41..e5c4a1398a55 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -2,4 +2,4 @@ * `#1209` Fix adding watcher to issue * `#1034` Create changelog and document format - +* `#1301` Ajax call when logged out should open a popup window diff --git a/test/integration/api_test/http_accept_auth_test.rb b/test/integration/api_test/http_accept_auth_test.rb new file mode 100644 index 000000000000..097a42407537 --- /dev/null +++ b/test/integration/api_test/http_accept_auth_test.rb @@ -0,0 +1,43 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# +# Copyright (C) 2012-2013 the OpenProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +require File.expand_path('../../../test_helper', __FILE__) + +class ApiTest::HttpAcceptAuthTest < ActionDispatch::IntegrationTest + fixtures :all + + def setup + Setting.rest_api_enabled = '1' + Setting.login_required = '1' + end + + def teardown + Setting.rest_api_enabled = '0' + Setting.login_required = '0' + end + + # Using the NewsController because it's a simple API. + context "get /news" do + setup do + project = Project.find('onlinestore') + EnabledModule.create(:project => project, :name => 'news') + end + + context "in :xml format" do + should_send_correct_authentication_scheme_when_header_authentication_scheme_is_session(:get, "/api/v1/projects/onlinestore/news.xml") + end + + context "in :json format" do + should_send_correct_authentication_scheme_when_header_authentication_scheme_is_session(:get, "/api/v1/projects/onlinestore/news.json") + end + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 9c67c0da63de..25ebf60ccdd3 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -285,6 +285,43 @@ def self.should_allow_api_authentication(http_method, url, parameters={}, option should_allow_key_based_auth(http_method, url, parameters, options) end + # Test that a request allows the username and password for HTTP BASIC + # + # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete) + # @param [String] url the request url + # @param [optional, Hash] options additional options + # @option options [Symbol] :success_code Successful response code (:success) + # @option options [Symbol] :failure_code Failure response code (:unauthorized) + def self.should_send_correct_authentication_scheme_when_header_authentication_scheme_is_session(http_method, url, options = {}, parameters = {}) + success_code = options[:success_code] || :success + failure_code = options[:failure_code] || :unauthorized + + context "should not send www authenticate when header accept auth is session #{http_method} #{url}" do + context "without credentials" do + setup do + send(http_method, url, parameters, { "X-Authentication-Scheme" => "Session" }) + end + + should respond_with failure_code + should_respond_with_content_type_based_on_url(url) + should "include correct www_authenticate_header" do + # the 3.0.9 implementation of head leads to Www as the method capitalizes each + # word split by a hyphen. + # this is fixed in 3.1.0 http://apidock.com/rails/v3.1.0/ActionController/Head/head + # remove this switch once on 3.1.0 + if ::Rails::VERSION::MAJOR == 3 && ::Rails::VERSION::MINOR == 0 + assert @controller.response.headers.has_key?('Www-Authenticate') + assert_equal 'Session realm="OpenProject API"', @controller.response.headers['Www-Authenticate'] + else + assert @controller.response.headers.has_key?('WWW-Authenticate') + assert_equal 'Session realm="OpenProject API"', @controller.response.headers['WWW-Authenticate'] + end + end + end + end + + end + # Test that a request allows the username and password for HTTP BASIC # # @param [Symbol] http_method the HTTP method for request (:get, :post, :put, :delete) @@ -333,6 +370,17 @@ def self.should_allow_http_basic_auth_with_username_and_password(http_method, ur should respond_with failure_code should_respond_with_content_type_based_on_url(url) + should "include_www_authenticate_header" do + # the 3.0.9 implementation of head leads to Www as the method capitalizes each + # word split by a hyphen. + # this is fixed in 3.1.0 http://apidock.com/rails/v3.1.0/ActionController/Head/head + # remove this switch once on 3.1.0 + if ::Rails::VERSION::MAJOR == 3 && ::Rails::VERSION::MINOR == 0 + assert @controller.response.headers.has_key?('Www-Authenticate') + else + assert @controller.response.headers.has_key?('WWW-Authenticate') + end + end end end