@@ -213,7 +213,11 @@ def clean(self):
213
213
214
214
if redirect_uris :
215
215
validator = AllowedURIValidator (
216
- allowed_schemes , name = "redirect uri" , allow_path = True , allow_query = True
216
+ allowed_schemes ,
217
+ name = "redirect uri" ,
218
+ allow_path = True ,
219
+ allow_query = True ,
220
+ allow_hostname_wildcard = oauth2_settings .ALLOW_REDIRECT_URI_WILDCARDS ,
217
221
)
218
222
for uri in redirect_uris :
219
223
validator (uri )
@@ -227,7 +231,7 @@ def clean(self):
227
231
allowed_origins = self .allowed_origins .strip ().split ()
228
232
if allowed_origins :
229
233
# oauthlib allows only https scheme for CORS
230
- validator = AllowedURIValidator (oauth2_settings .ALLOWED_SCHEMES , "allowed origin" )
234
+ validator = AllowedURIValidator (oauth2_settings .ALLOWED_SCHEMES , "allowed origin" , allow_hostname_wildcard = oauth2_settings . ALLOW_REDIRECT_URI_WILDCARDS )
231
235
for uri in allowed_origins :
232
236
validator (uri )
233
237
@@ -782,35 +786,43 @@ def redirect_to_uri_allowed(uri, allowed_uris):
782
786
for allowed_uri in allowed_uris :
783
787
parsed_allowed_uri = urlparse (allowed_uri )
784
788
789
+ if parsed_allowed_uri .scheme != parsed_uri .scheme :
790
+ # match failed, continue
791
+ continue
792
+
793
+ """ check hostname """
794
+ if oauth2_settings .ALLOW_REDIRECT_URI_WILDCARDS and parsed_allowed_uri .hostname .startswith ("*" ):
795
+ """ wildcard hostname """
796
+ if not parsed_uri .hostname .endswith (parsed_allowed_uri .hostname [1 :]):
797
+ continue
798
+ elif parsed_allowed_uri .hostname != parsed_uri .hostname :
799
+ continue
800
+
785
801
# From RFC 8252 (Section 7.3)
802
+ # https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
786
803
#
787
804
# Loopback redirect URIs use the "http" scheme
788
805
# [...]
789
806
# The authorization server MUST allow any port to be specified at the
790
807
# time of the request for loopback IP redirect URIs, to accommodate
791
808
# clients that obtain an available ephemeral port from the operating
792
809
# system at the time of the request.
810
+ allowed_uri_is_loopback = parsed_allowed_uri .scheme == "http" and parsed_allowed_uri .hostname in [
811
+ "127.0.0.1" ,
812
+ "::1" ,
813
+ ]
814
+ """ check port """
815
+ if not allowed_uri_is_loopback and parsed_allowed_uri .port != parsed_uri .port :
816
+ continue
793
817
794
- allowed_uri_is_loopback = (
795
- parsed_allowed_uri .scheme == "http"
796
- and parsed_allowed_uri .hostname in ["127.0.0.1" , "::1" ]
797
- and parsed_allowed_uri .port is None
798
- )
799
- if (
800
- allowed_uri_is_loopback
801
- and parsed_allowed_uri .scheme == parsed_uri .scheme
802
- and parsed_allowed_uri .hostname == parsed_uri .hostname
803
- and parsed_allowed_uri .path == parsed_uri .path
804
- ) or (
805
- parsed_allowed_uri .scheme == parsed_uri .scheme
806
- and parsed_allowed_uri .netloc == parsed_uri .netloc
807
- and parsed_allowed_uri .path == parsed_uri .path
808
- ):
809
- aqs_set = set (parse_qsl (parsed_allowed_uri .query ))
810
- if aqs_set .issubset (uqs_set ):
811
- return True
818
+ """ check path """
819
+ if parsed_allowed_uri .path != parsed_uri .path :
820
+ continue
812
821
813
- return False
822
+ """ check querystring """
823
+ aqs_set = set (parse_qsl (parsed_allowed_uri .query ))
824
+ if not aqs_set .issubset (uqs_set ):
825
+ continue # circuit break
814
826
815
827
816
828
def is_origin_allowed (origin , allowed_origins ):
@@ -833,4 +845,5 @@ def is_origin_allowed(origin, allowed_origins):
833
845
and parsed_allowed_origin .netloc == parsed_origin .netloc
834
846
):
835
847
return True
848
+
836
849
return False
0 commit comments