3939 r'\[?[A-F0-9]*:[A-F0-9:]+\]?)' # ...or ipv6
4040 r'(?::\d+)?' # optional port
4141 r'(?:/?|[/?]\S+)$' , re .IGNORECASE )
42+ url_regex_single_label_domain = re .compile (
43+ r'^(?:[a-z0-9\.\-]*)://' # scheme is validated separately
44+ r'(?:(?:[A-Z0-9_](?:[A-Z0-9-_]{0,61}[A-Z0-9_])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain...
45+ r'(?:[A-Z0-9_](?:[A-Z0-9-_]{0,61}[A-Z0-9_]))|' # single-label-domain
46+ r'localhost|' # localhost...
47+ r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4
48+ r'\[?[A-F0-9]*:[A-F0-9:]+\]?)' # ...or ipv6
49+ r'(?::\d+)?' # optional port
50+ r'(?:/?|[/?]\S+)$' , re .IGNORECASE )
4251url_schemes = ['http' , 'https' , 'ftp' , 'ftps' ]
4352
4453
45- def validate_url (url ):
54+ def validate_url (url , allow_single_label_domain = False ):
4655 """
4756 Auxiliary method to validate an urllib
4857 :param url: An url to be validated
@@ -54,8 +63,12 @@ def validate_url(url):
5463 scheme = url .split ('://' )[0 ].lower ()
5564 if scheme not in url_schemes :
5665 return False
57- if not bool (url_regex .search (url )):
58- return False
66+ if allow_single_label_domain :
67+ if not bool (url_regex_single_label_domain .search (url )):
68+ return False
69+ else :
70+ if not bool (url_regex .search (url )):
71+ return False
5972 return True
6073
6174
@@ -353,17 +366,18 @@ def check_idp_settings(self, settings):
353366 if not settings .get ('idp' ):
354367 errors .append ('idp_not_found' )
355368 else :
369+ allow_single_domain_urls = self ._get_allow_single_label_domain (settings )
356370 idp = settings ['idp' ]
357371 if not idp .get ('entityId' ):
358372 errors .append ('idp_entityId_not_found' )
359373
360374 if not idp .get ('singleSignOnService' , {}).get ('url' ):
361375 errors .append ('idp_sso_not_found' )
362- elif not validate_url (idp ['singleSignOnService' ]['url' ]):
376+ elif not validate_url (idp ['singleSignOnService' ]['url' ], allow_single_domain_urls ):
363377 errors .append ('idp_sso_url_invalid' )
364378
365379 slo_url = idp .get ('singleLogoutService' , {}).get ('url' )
366- if slo_url and not validate_url (slo_url ):
380+ if slo_url and not validate_url (slo_url , allow_single_domain_urls ):
367381 errors .append ('idp_slo_url_invalid' )
368382
369383 if 'security' in settings :
@@ -407,6 +421,7 @@ def check_sp_settings(self, settings):
407421 if not settings .get ('sp' ):
408422 errors .append ('sp_not_found' )
409423 else :
424+ allow_single_domain_urls = self ._get_allow_single_label_domain (settings )
410425 # check_sp_certs uses self.__sp so I add it
411426 old_sp = self .__sp
412427 self .__sp = settings ['sp' ]
@@ -419,7 +434,7 @@ def check_sp_settings(self, settings):
419434
420435 if not sp .get ('assertionConsumerService' , {}).get ('url' ):
421436 errors .append ('sp_acs_not_found' )
422- elif not validate_url (sp ['assertionConsumerService' ]['url' ]):
437+ elif not validate_url (sp ['assertionConsumerService' ]['url' ], allow_single_domain_urls ):
423438 errors .append ('sp_acs_url_invalid' )
424439
425440 if sp .get ('attributeConsumingService' ):
@@ -448,7 +463,7 @@ def check_sp_settings(self, settings):
448463 errors .append ('sp_attributeConsumingService_serviceDescription_type_invalid' )
449464
450465 slo_url = sp .get ('singleLogoutService' , {}).get ('url' )
451- if slo_url and not validate_url (slo_url ):
466+ if slo_url and not validate_url (slo_url , allow_single_domain_urls ):
452467 errors .append ('sp_sls_url_invalid' )
453468
454469 if 'signMetadata' in security and isinstance (security ['signMetadata' ], dict ):
@@ -833,3 +848,7 @@ def is_debug_active(self):
833848 :rtype: boolean
834849 """
835850 return self .__debug
851+
852+ def _get_allow_single_label_domain (self , settings ):
853+ security = settings .get ('security' , {})
854+ return 'allowSingleLabelDomains' in security .keys () and security ['allowSingleLabelDomains' ]
0 commit comments