import calendar import urlparse import re import time_util import struct import base64 # Also defined in saml2.saml but can't import from there XSI_NAMESPACE = 'http://www.w3.org/2001/XMLSchema-instance' XSI_NIL = '{%s}nil' % XSI_NAMESPACE # --------------------------------------------------------- class NotValid(Exception): pass class OutsideCardinality(Exception): pass class MustValueError(ValueError): pass class ShouldValueError(ValueError): pass # --------------------- validators ------------------------------------- # NCNAME = re.compile("(?P[a-zA-Z_](\w|[_.-])*)") def valid_ncname(name): match = NCNAME.match(name) if not match: raise NotValid("NCName") return True def valid_id(oid): valid_ncname(oid) def valid_any_uri(item): """very simplistic, ...""" try: part = urlparse.urlparse(item) except Exception: raise NotValid("AnyURI") if part[0] == "urn" and part[1] == "": # A urn return True # elif part[1] == "localhost" or part[1] == "127.0.0.1": # raise NotValid("AnyURI") return True def valid_date_time(item): try: time_util.str_to_time(item) except Exception: raise NotValid("dateTime") return True def valid_url(url): try: _ = urlparse.urlparse(url) except Exception: raise NotValid("URL") # if part[1] == "localhost" or part[1] == "127.0.0.1": # raise NotValid("URL") return True def validate_on_or_after(not_on_or_after, slack): if not_on_or_after: now = time_util.utc_now() nooa = calendar.timegm(time_util.str_to_time(not_on_or_after)) if now > nooa + slack: raise Exception("Can't use it, it's too old %d > %d" % (nooa, now)) return nooa else: return False def validate_before(not_before, slack): if not_before: now = time_util.utc_now() nbefore = calendar.timegm(time_util.str_to_time(not_before)) if nbefore > now + slack: raise Exception("Can't use it yet %d <= %d" % (nbefore, now)) return True def valid_address(address): if not (valid_ipv4(address) or valid_ipv6(address)): raise NotValid("address") return True def valid_ipv4(address): parts = address.split(".") if len(parts) != 4: return False for item in parts: try: if not 0 <= int(item) <= 255: raise NotValid("ipv4") except ValueError: return False return True # IPV6_PATTERN = re.compile(r""" ^ \s* # Leading whitespace (?!.*::.*::) # Only a single wildcard allowed (?:(?!:)|:(?=:)) # Colon iff it would be part of a wildcard (?: # Repeat 6 times: [0-9a-f]{0,4} # A group of at most four hexadecimal digits (?:(?<=::)|(? vlen: raise NotValid( "Class '%s' instance cardinality error: %s" % ( class_name, "less then min (%s<%s)" % (vlen, _cmin))) if _cmax is not None and vlen > _cmax: raise NotValid( "Class '%s' instance cardinality error: %s" % ( class_name, "more then max (%s>%s)" % (vlen, _cmax))) if _list: for val in value: # That it is the right class is handled elsewhere _valid_instance(instance, val) else: _valid_instance(instance, value) else: if _cmin: raise NotValid( "Class '%s' instance cardinality error: %s" % ( class_name, "too few values on %s" % name)) # if not _has_val: # if class_name != "RequestedAttribute": # # Not allow unless xsi:nil="true" # assert instance.extension_attributes # assert instance.extension_attributes[XSI_NIL] == "true" return True def valid_domain_name(dns_name): m = re.match( "^[a-z0-9]+([-.]{ 1 }[a-z0-9]+).[a-z]{2,5}(:[0-9]{1,5})?(\/.)?$", dns_name, "ix") if not m: raise ValueError("Not a proper domain name")