3131 r'\[?[A-F0-9]*:[A-F0-9:]+\]?)' # ...or ipv6
3232 r'(?::\d+)?' # optional port
3333 r'(?:/?|[/?]\S+)$' , re .IGNORECASE )
34+ url_regex_single_label_domain = re .compile (
35+ r'^(?:[a-z0-9\.\-]*)://' # scheme is validated separately
36+ r'(?:(?:[A-Z0-9_](?:[A-Z0-9-_]{0,61}[A-Z0-9_])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # domain...
37+ r'(?:[A-Z0-9_](?:[A-Z0-9-_]{0,61}[A-Z0-9_]))|' # single-label-domain
38+ r'localhost|' # localhost...
39+ r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4
40+ r'\[?[A-F0-9]*:[A-F0-9:]+\]?)' # ...or ipv6
41+ r'(?::\d+)?' # optional port
42+ r'(?:/?|[/?]\S+)$' , re .IGNORECASE )
3443url_schemes = ['http' , 'https' , 'ftp' , 'ftps' ]
3544
3645
37- def validate_url (url ):
46+ def validate_url (url , allow_single_label_domain = False ):
3847 """
3948 Auxiliary method to validate an urllib
4049 :param url: An url to be validated
4150 :type url: string
51+ :param allow_single_label_domain: In order to allow or not single label domain
52+ :type url: bool
4253 :returns: True if the url is valid
4354 :rtype: bool
4455 """
4556
4657 scheme = url .split ('://' )[0 ].lower ()
4758 if scheme not in url_schemes :
4859 return False
49- if not bool (url_regex .search (url )):
50- return False
60+ if allow_single_label_domain :
61+ if not bool (url_regex_single_label_domain .search (url )):
62+ return False
63+ else :
64+ if not bool (url_regex .search (url )):
65+ return False
5166 return True
5267
5368
@@ -351,17 +366,18 @@ def check_idp_settings(self, settings):
351366 if not settings .get ('idp' ):
352367 errors .append ('idp_not_found' )
353368 else :
369+ allow_single_domain_urls = self ._get_allow_single_label_domain (settings )
354370 idp = settings ['idp' ]
355371 if not idp .get ('entityId' ):
356372 errors .append ('idp_entityId_not_found' )
357373
358374 if not idp .get ('singleSignOnService' , {}).get ('url' ):
359375 errors .append ('idp_sso_not_found' )
360- elif not validate_url (idp ['singleSignOnService' ]['url' ]):
376+ elif not validate_url (idp ['singleSignOnService' ]['url' ], allow_single_domain_urls ):
361377 errors .append ('idp_sso_url_invalid' )
362378
363379 slo_url = idp .get ('singleLogoutService' , {}).get ('url' )
364- if slo_url and not validate_url (slo_url ):
380+ if slo_url and not validate_url (slo_url , allow_single_domain_urls ):
365381 errors .append ('idp_slo_url_invalid' )
366382
367383 if 'security' in settings :
@@ -408,6 +424,7 @@ def check_sp_settings(self, settings):
408424 if not settings .get ('sp' ):
409425 errors .append ('sp_not_found' )
410426 else :
427+ allow_single_domain_urls = self ._get_allow_single_label_domain (settings )
411428 # check_sp_certs uses self.__sp so I add it
412429 old_sp = self .__sp
413430 self .__sp = settings ['sp' ]
@@ -420,7 +437,7 @@ def check_sp_settings(self, settings):
420437
421438 if not sp .get ('assertionConsumerService' , {}).get ('url' ):
422439 errors .append ('sp_acs_not_found' )
423- elif not validate_url (sp ['assertionConsumerService' ]['url' ]):
440+ elif not validate_url (sp ['assertionConsumerService' ]['url' ], allow_single_domain_urls ):
424441 errors .append ('sp_acs_url_invalid' )
425442
426443 if sp .get ('attributeConsumingService' ):
@@ -449,7 +466,7 @@ def check_sp_settings(self, settings):
449466 errors .append ('sp_attributeConsumingService_serviceDescription_type_invalid' )
450467
451468 slo_url = sp .get ('singleLogoutService' , {}).get ('url' )
452- if slo_url and not validate_url (slo_url ):
469+ if slo_url and not validate_url (slo_url , allow_single_domain_urls ):
453470 errors .append ('sp_sls_url_invalid' )
454471
455472 if 'signMetadata' in security and isinstance (security ['signMetadata' ], dict ):
@@ -840,3 +857,7 @@ def is_debug_active(self):
840857 :rtype: boolean
841858 """
842859 return self .__debug
860+
861+ def _get_allow_single_label_domain (self , settings ):
862+ security = settings .get ('security' , {})
863+ return 'allowSingleLabelDomains' in security .keys () and security ['allowSingleLabelDomains' ]
0 commit comments