lib/rodauth/features/oauth_authorize_base.rb in rodauth-oauth-1.0.0 vs lib/rodauth/features/oauth_authorize_base.rb in rodauth-oauth-1.1.0

- old
+ new

@@ -1,7 +1,8 @@ # frozen_string_literal: true +require "ipaddr" require "rodauth/oauth" module Rodauth Feature.define(:oauth_authorize_base, :OauthAuthorizeBase) do depends :oauth_base @@ -69,11 +70,12 @@ redirect_authorize_error("client_id") unless oauth_application redirect_uris = oauth_application[oauth_applications_redirect_uri_column].split(" ") if (redirect_uri = param_or_nil("redirect_uri")) - redirect_authorize_error("redirect_uri") unless redirect_uris.include?(redirect_uri) + normalized_redirect_uri = normalize_redirect_uri_for_comparison(redirect_uri) + redirect_authorize_error("redirect_uri") unless redirect_uris.include?(normalized_redirect_uri) elsif redirect_uris.size > 1 redirect_authorize_error("redirect_uri") end redirect_response_error("unsupported_response_type") unless check_valid_response_type? @@ -208,8 +210,29 @@ else __insert_and_return__(ds, oauth_grants_id_column, create_params) end end create_params[oauth_grants_code_column] + end + + def normalize_redirect_uri_for_comparison(redirect_uri) + uri = URI(redirect_uri) + + return redirect_uri unless uri.scheme == "http" && uri.port + + hostname = uri.hostname + + # https://www.rfc-editor.org/rfc/rfc8252#section-7.3 + # ignore (potentially ephemeral) port number for native clients per RFC8252 + begin + ip = IPAddr.new(hostname) + uri.port = nil if ip.loopback? + rescue IPAddr::InvalidAddressError + # https://www.rfc-editor.org/rfc/rfc8252#section-8.3 + # Although the use of localhost is NOT RECOMMENDED, it is still allowed. + uri.port = nil if hostname == "localhost" + end + + uri.to_s end end end