@@ -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,11 @@ 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 (
235
+ oauth2_settings .ALLOWED_SCHEMES ,
236
+ "allowed origin" ,
237
+ allow_hostname_wildcard = oauth2_settings .ALLOW_REDIRECT_URI_WILDCARDS ,
238
+ )
231
239
for uri in allowed_origins :
232
240
validator (uri )
233
241
@@ -782,35 +790,43 @@ def redirect_to_uri_allowed(uri, allowed_uris):
782
790
for allowed_uri in allowed_uris :
783
791
parsed_allowed_uri = urlparse (allowed_uri )
784
792
793
+ if parsed_allowed_uri .scheme != parsed_uri .scheme :
794
+ # match failed, continue
795
+ continue
796
+
797
+ """ check hostname """
798
+ if oauth2_settings .ALLOW_REDIRECT_URI_WILDCARDS and parsed_allowed_uri .hostname .startswith ("*" ):
799
+ """ wildcard hostname """
800
+ if not parsed_uri .hostname .endswith (parsed_allowed_uri .hostname [1 :]):
801
+ continue
802
+ elif parsed_allowed_uri .hostname != parsed_uri .hostname :
803
+ continue
804
+
785
805
# From RFC 8252 (Section 7.3)
806
+ # https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
786
807
#
787
808
# Loopback redirect URIs use the "http" scheme
788
809
# [...]
789
810
# The authorization server MUST allow any port to be specified at the
790
811
# time of the request for loopback IP redirect URIs, to accommodate
791
812
# clients that obtain an available ephemeral port from the operating
792
813
# system at the time of the request.
814
+ allowed_uri_is_loopback = parsed_allowed_uri .scheme == "http" and parsed_allowed_uri .hostname in [
815
+ "127.0.0.1" ,
816
+ "::1" ,
817
+ ]
818
+ """ check port """
819
+ if not allowed_uri_is_loopback and parsed_allowed_uri .port != parsed_uri .port :
820
+ continue
793
821
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
822
+ """ check path """
823
+ if parsed_allowed_uri .path != parsed_uri .path :
824
+ continue
812
825
813
- return False
826
+ """ check querystring """
827
+ aqs_set = set (parse_qsl (parsed_allowed_uri .query ))
828
+ if not aqs_set .issubset (uqs_set ):
829
+ continue # circuit break
814
830
815
831
816
832
def is_origin_allowed (origin , allowed_origins ):
@@ -833,4 +849,5 @@ def is_origin_allowed(origin, allowed_origins):
833
849
and parsed_allowed_origin .netloc == parsed_origin .netloc
834
850
):
835
851
return True
852
+
836
853
return False
0 commit comments