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