X-Git-Url: https://git.openstreetmap.org./rails.git/blobdiff_plain/37f8f8a28caea936b53271c9f9de36cdbaf15d0e..694d45cd31c65e06a342ae3d038af563c5dc7731:/app/controllers/api_controller.rb diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index 579af27cf..050c455cd 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -3,6 +3,48 @@ class ApiController < ApplicationController private + ## + # Set allowed request formats if no explicit format has been + # requested via a URL suffix. Allowed formats are taken from + # any HTTP Accept header with XML as the default. + def set_request_formats + unless params[:format] + accept_header = request.headers["HTTP_ACCEPT"] + + if accept_header + # Some clients (such asJOSM) send Accept headers which cannot be + # parse by Rails, for example: + # + # Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2 + # + # where both "*" and ".2" as a quality do not adhere to the syntax + # described in RFC 7231, section 5.3.1, etc. + # + # As a workaround, and for back compatibility, default to XML format. + mimetypes = begin + Mime::Type.parse(accept_header) + rescue Mime::Type::InvalidMimeType + Array(Mime[:xml]) + end + + # Allow XML and JSON formats, and treat an all formats wildcard + # as XML for backwards compatibility - all other formats are discarded + # which will result in a 406 Not Acceptable response being sent + formats = mimetypes.map do |mime| + if mime.symbol == :xml || mime == "*/*" then :xml + elsif mime.symbol == :json then :json + end + end + else + # Default to XML if no accept header was sent - this includes + # the unit tests which don't set one by default + formats = Array(:xml) + end + + request.formats = formats.compact + end + end + def authorize(realm = "Web Password", errormessage = "Couldn't authenticate you") # make the current_user object from any auth sources we have setup_user_auth @@ -12,12 +54,23 @@ class ApiController < ApplicationController # no auth, the user does not exist or the password was wrong response.headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\"" render :plain => errormessage, :status => :unauthorized - return false + false + end + end + + def current_ability + # Use capabilities from the oauth token if it exists and is a valid access token + if doorkeeper_token&.accessible? + ApiAbility.new(nil).merge(ApiCapability.new(doorkeeper_token)) + elsif Authenticator.new(self, [:token]).allow? + ApiAbility.new(nil).merge(ApiCapability.new(current_token)) + else + ApiAbility.new(current_user) end end def deny_access(_exception) - if current_token + if doorkeeper_token || current_token set_locale report_error t("oauth.permissions.missing"), :forbidden elsif current_user @@ -42,8 +95,12 @@ class ApiController < ApplicationController # is optional. def setup_user_auth # try and setup using OAuth - unless Authenticator.new(self, [:token]).allow? - username, passwd = get_auth_data # parse from headers + if doorkeeper_token&.accessible? + self.current_user = User.find(doorkeeper_token.resource_owner_id) + elsif Authenticator.new(self, [:token]).allow? + # self.current_user setup by OAuth + else + username, passwd = auth_data # parse from headers # authenticate per-scheme self.current_user = if username.nil? nil # no authentication provided - perhaps first connect (client should retry after 401)