Exemple #1
0
    def __init__(self, option_name, rule):
        """
        Args:
            option_name (str): Name of the config option this rule belongs to
            rule (dict): The rule as specified in the config
        """

        action = rule["action"]
        user_id = rule.get("user_id", "*")
        room_id = rule.get("room_id", "*")
        alias = rule.get("alias", "*")

        if action in ("allow", "deny"):
            self.action = action
        else:
            raise ConfigError("%s rules can only have action of 'allow'"
                              " or 'deny'" % (option_name, ))

        self._alias_matches_all = alias == "*"

        try:
            self._user_id_regex = glob_to_regex(user_id)
            self._alias_regex = glob_to_regex(alias)
            self._room_id_regex = glob_to_regex(room_id)
        except Exception as e:
            raise ConfigError("Failed to parse glob into regex: %s", e)
Exemple #2
0
    def __init__(self, option_name, rule):
        """
        Args:
            option_name (str): Name of the config option this rule belongs to
            rule (dict): The rule as specified in the config
        """

        action = rule["action"]
        user_id = rule.get("user_id", "*")
        room_id = rule.get("room_id", "*")
        alias = rule.get("alias", "*")

        if action in ("allow", "deny"):
            self.action = action
        else:
            raise ConfigError(
                "%s rules can only have action of 'allow'"
                " or 'deny'" % (option_name,)
            )

        self._alias_matches_all = alias == "*"

        try:
            self._user_id_regex = glob_to_regex(user_id)
            self._alias_regex = glob_to_regex(alias)
            self._room_id_regex = glob_to_regex(room_id)
        except Exception as e:
            raise ConfigError("Failed to parse glob into regex: %s", e)
Exemple #3
0
def _acl_entry_matches(server_name: str, acl_entry: str) -> Match:
    if not isinstance(acl_entry, str):
        logger.warning("Ignoring non-str ACL entry '%s' (is %s)", acl_entry,
                       type(acl_entry))
        return False
    regex = glob_to_regex(acl_entry)
    return regex.match(server_name)
def _acl_entry_matches(server_name, acl_entry):
    if not isinstance(acl_entry, six.string_types):
        logger.warn("Ignoring non-str ACL entry '%s' (is %s)", acl_entry,
                    type(acl_entry))
        return False
    regex = glob_to_regex(acl_entry)
    return regex.match(server_name)
Exemple #5
0
    def __init__(self, rule):
        action = rule["action"]
        user_id = rule["user_id"]
        alias = rule["alias"]

        if action in ("allow", "deny"):
            self.action = action
        else:
            raise ConfigError(
                "alias_creation_rules rules can only have action of 'allow'"
                " or 'deny'"
            )

        try:
            self._user_id_regex = glob_to_regex(user_id)
            self._alias_regex = glob_to_regex(alias)
        except Exception as e:
            raise ConfigError("Failed to parse glob into regex: %s", e)
Exemple #6
0
    def test_multi_wildcard(self):
        """patterns with multiple wildcards in a row should match"""
        pat = glob_to_regex("**baz")
        self.assertTrue(pat.match("agsgsbaz"), "** should match any string")
        self.assertTrue(pat.match("baz"), "** should match the empty string")
        self.assertEqual(pat.pattern, r"\A.{0,}baz\Z")

        pat = glob_to_regex("*?baz")
        self.assertTrue(pat.match("agsgsbaz"), "*? should match any string")
        self.assertTrue(pat.match("abaz"), "*? should match a single char")
        self.assertFalse(pat.match("baz"), "*? should not match the empty string")
        self.assertEqual(pat.pattern, r"\A.{1,}baz\Z")

        pat = glob_to_regex("a?*?*?baz")
        self.assertTrue(pat.match("a g baz"), "?*?*? should match 3 chars")
        self.assertFalse(pat.match("a..baz"), "?*?*? should not match 2 chars")
        self.assertTrue(pat.match("a.gg.baz"), "?*?*? should match 4 chars")
        self.assertEqual(pat.pattern, r"\Aa.{3,}baz\Z")
Exemple #7
0
 def test_literal_match(self):
     """patterns without wildcards should match"""
     pat = glob_to_regex("foobaz")
     self.assertTrue(
         pat.match("FoobaZ"), "patterns should match and be case-insensitive"
     )
     self.assertFalse(
         pat.match("x foobaz"), "pattern should not match at word boundaries"
     )
Exemple #8
0
    def test_wildcard_match(self):
        pat = glob_to_regex("f?o*baz")

        self.assertTrue(
            pat.match("FoobarbaZ"),
            "* should match string and pattern should be case-insensitive",
        )
        self.assertTrue(pat.match("foobaz"), "* should match 0 characters")
        self.assertFalse(pat.match("fooxaz"), "the character after * must match")
        self.assertFalse(pat.match("fobbaz"), "? should not match 0 characters")
        self.assertFalse(pat.match("fiiobaz"), "? should not match 2 characters")
Exemple #9
0
def _glob_matches(glob: str, value: str, word_boundary: bool = False) -> bool:
    """Tests if value matches glob.

    Args:
        glob
        value: String to test against glob.
        word_boundary: Whether to match against word boundaries or entire
            string. Defaults to False.
    """

    try:
        r = regex_cache.get((glob, True, word_boundary), None)
        if not r:
            r = glob_to_regex(glob, word_boundary)
            regex_cache[(glob, True, word_boundary)] = r
        return bool(r.search(value))
    except re.error:
        logger.warning("Failed to parse glob to regex: %r", glob)
        return False
Exemple #10
0
    def read_config(self, config: dict, config_dir_path: str, **kwargs):

        acme_config = config.get("acme", None)
        if acme_config is None:
            acme_config = {}

        self.acme_enabled = acme_config.get("enabled", False)

        if self.acme_enabled:
            logger.warning(ACME_SUPPORT_ENABLED_WARN)

        # hyperlink complains on py2 if this is not a Unicode
        self.acme_url = str(
            acme_config.get("url",
                            "https://acme-v01.api.letsencrypt.org/directory"))
        self.acme_port = acme_config.get("port", 80)
        self.acme_bind_addresses = acme_config.get("bind_addresses",
                                                   ["::", "0.0.0.0"])
        self.acme_reprovision_threshold = acme_config.get(
            "reprovision_threshold", 30)
        self.acme_domain = acme_config.get("domain", config.get("server_name"))

        self.acme_account_key_file = self.abspath(
            acme_config.get("account_key_file",
                            config_dir_path + "/client.key"))

        self.tls_certificate_file = self.abspath(
            config.get("tls_certificate_path"))
        self.tls_private_key_file = self.abspath(
            config.get("tls_private_key_path"))

        if self.root.server.has_tls_listener():
            if not self.tls_certificate_file:
                raise ConfigError(
                    "tls_certificate_path must be specified if TLS-enabled listeners are "
                    "configured.")
            if not self.tls_private_key_file:
                raise ConfigError(
                    "tls_private_key_path must be specified if TLS-enabled listeners are "
                    "configured.")

        self._original_tls_fingerprints = config.get("tls_fingerprints", [])

        if self._original_tls_fingerprints is None:
            self._original_tls_fingerprints = []

        self.tls_fingerprints = list(self._original_tls_fingerprints)

        # Whether to verify certificates on outbound federation traffic
        self.federation_verify_certificates = config.get(
            "federation_verify_certificates", True)

        # Minimum TLS version to use for outbound federation traffic
        self.federation_client_minimum_tls_version = str(
            config.get("federation_client_minimum_tls_version", 1))

        if self.federation_client_minimum_tls_version not in [
                "1", "1.1", "1.2", "1.3"
        ]:
            raise ConfigError(
                "federation_client_minimum_tls_version must be one of: 1, 1.1, 1.2, 1.3"
            )

        # Prevent people shooting themselves in the foot here by setting it to
        # the biggest number blindly
        if self.federation_client_minimum_tls_version == "1.3":
            if getattr(SSL, "OP_NO_TLSv1_3", None) is None:
                raise ConfigError(
                    ("federation_client_minimum_tls_version cannot be 1.3, "
                     "your OpenSSL does not support it"))

        # Whitelist of domains to not verify certificates for
        fed_whitelist_entries = config.get(
            "federation_certificate_verification_whitelist", [])
        if fed_whitelist_entries is None:
            fed_whitelist_entries = []

        # Support globs (*) in whitelist values
        self.federation_certificate_verification_whitelist = [
        ]  # type: List[str]
        for entry in fed_whitelist_entries:
            try:
                entry_regex = glob_to_regex(
                    entry.encode("ascii").decode("ascii"))
            except UnicodeEncodeError:
                raise ConfigError(
                    "IDNA domain names are not allowed in the "
                    "federation_certificate_verification_whitelist: %s" %
                    (entry, ))

            # Convert globs to regex
            self.federation_certificate_verification_whitelist.append(
                entry_regex)

        # List of custom certificate authorities for federation traffic validation
        custom_ca_list = config.get("federation_custom_ca_list", None)

        # Read in and parse custom CA certificates
        self.federation_ca_trust_root = None
        if custom_ca_list is not None:
            if len(custom_ca_list) == 0:
                # A trustroot cannot be generated without any CA certificates.
                # Raise an error if this option has been specified without any
                # corresponding certificates.
                raise ConfigError(
                    "federation_custom_ca_list specified without "
                    "any certificate files")

            certs = []
            for ca_file in custom_ca_list:
                logger.debug("Reading custom CA certificate file: %s", ca_file)
                content = self.read_file(ca_file, "federation_custom_ca_list")

                # Parse the CA certificates
                try:
                    cert_base = Certificate.loadPEM(content)
                    certs.append(cert_base)
                except Exception as e:
                    raise ConfigError(
                        "Error parsing custom CA certificate file %s: %s" %
                        (ca_file, e))

            self.federation_ca_trust_root = trustRootFromCertificates(certs)

        # This config option applies to non-federation HTTP clients
        # (e.g. for talking to recaptcha, identity servers, and such)
        # It should never be used in production, and is intended for
        # use only when running tests.
        self.use_insecure_ssl_client_just_for_testing_do_not_use = config.get(
            "use_insecure_ssl_client_just_for_testing_do_not_use")

        self.tls_certificate = None
        self.tls_private_key = None
Exemple #11
0
 def __init__(self, entity, action, reason, kind):
     self.entity = entity
     self.regex = glob_to_regex(entity)
     self.action = recommendation_to_stable(action)
     self.reason = reason
     self.kind = rule_type_to_stable(kind)
Exemple #12
0
    def read_config(self, config):

        acme_config = config.get("acme", None)
        if acme_config is None:
            acme_config = {}

        self.acme_enabled = acme_config.get("enabled", False)

        # hyperlink complains on py2 if this is not a Unicode
        self.acme_url = six.text_type(acme_config.get(
            "url", u"https://acme-v01.api.letsencrypt.org/directory"
        ))
        self.acme_port = acme_config.get("port", 80)
        self.acme_bind_addresses = acme_config.get("bind_addresses", ['::', '0.0.0.0'])
        self.acme_reprovision_threshold = acme_config.get("reprovision_threshold", 30)
        self.acme_domain = acme_config.get("domain", config.get("server_name"))

        self.tls_certificate_file = self.abspath(config.get("tls_certificate_path"))
        self.tls_private_key_file = self.abspath(config.get("tls_private_key_path"))

        if self.has_tls_listener():
            if not self.tls_certificate_file:
                raise ConfigError(
                    "tls_certificate_path must be specified if TLS-enabled listeners are "
                    "configured."
                )
            if not self.tls_private_key_file:
                raise ConfigError(
                    "tls_private_key_path must be specified if TLS-enabled listeners are "
                    "configured."
                )

        self._original_tls_fingerprints = config.get("tls_fingerprints", [])

        if self._original_tls_fingerprints is None:
            self._original_tls_fingerprints = []

        self.tls_fingerprints = list(self._original_tls_fingerprints)

        # Whether to verify certificates on outbound federation traffic
        self.federation_verify_certificates = config.get(
            "federation_verify_certificates", True,
        )

        # Whitelist of domains to not verify certificates for
        fed_whitelist_entries = config.get(
            "federation_certificate_verification_whitelist", [],
        )

        # Support globs (*) in whitelist values
        self.federation_certificate_verification_whitelist = []
        for entry in fed_whitelist_entries:
            # Convert globs to regex
            entry_regex = glob_to_regex(entry)
            self.federation_certificate_verification_whitelist.append(entry_regex)

        # List of custom certificate authorities for federation traffic validation
        custom_ca_list = config.get(
            "federation_custom_ca_list", None,
        )

        # Read in and parse custom CA certificates
        self.federation_ca_trust_root = None
        if custom_ca_list is not None:
            if len(custom_ca_list) == 0:
                # A trustroot cannot be generated without any CA certificates.
                # Raise an error if this option has been specified without any
                # corresponding certificates.
                raise ConfigError("federation_custom_ca_list specified without "
                                  "any certificate files")

            certs = []
            for ca_file in custom_ca_list:
                logger.debug("Reading custom CA certificate file: %s", ca_file)
                content = self.read_file(ca_file, "federation_custom_ca_list")

                # Parse the CA certificates
                try:
                    cert_base = Certificate.loadPEM(content)
                    certs.append(cert_base)
                except Exception as e:
                    raise ConfigError("Error parsing custom CA certificate file %s: %s"
                                      % (ca_file, e))

            self.federation_ca_trust_root = trustRootFromCertificates(certs)

        # This config option applies to non-federation HTTP clients
        # (e.g. for talking to recaptcha, identity servers, and such)
        # It should never be used in production, and is intended for
        # use only when running tests.
        self.use_insecure_ssl_client_just_for_testing_do_not_use = config.get(
            "use_insecure_ssl_client_just_for_testing_do_not_use"
        )

        self.tls_certificate = None
        self.tls_private_key = None
Exemple #13
0
    def read_config(self, config: dict, config_dir_path: str, **kwargs):

        self.tls_certificate_file = self.abspath(config.get("tls_certificate_path"))
        self.tls_private_key_file = self.abspath(config.get("tls_private_key_path"))

        if self.root.server.has_tls_listener():
            if not self.tls_certificate_file:
                raise ConfigError(
                    "tls_certificate_path must be specified if TLS-enabled listeners are "
                    "configured."
                )
            if not self.tls_private_key_file:
                raise ConfigError(
                    "tls_private_key_path must be specified if TLS-enabled listeners are "
                    "configured."
                )

        # Whether to verify certificates on outbound federation traffic
        self.federation_verify_certificates = config.get(
            "federation_verify_certificates", True
        )

        # Minimum TLS version to use for outbound federation traffic
        self.federation_client_minimum_tls_version = str(
            config.get("federation_client_minimum_tls_version", 1)
        )

        if self.federation_client_minimum_tls_version not in ["1", "1.1", "1.2", "1.3"]:
            raise ConfigError(
                "federation_client_minimum_tls_version must be one of: 1, 1.1, 1.2, 1.3"
            )

        # Prevent people shooting themselves in the foot here by setting it to
        # the biggest number blindly
        if self.federation_client_minimum_tls_version == "1.3":
            if getattr(SSL, "OP_NO_TLSv1_3", None) is None:
                raise ConfigError(
                    "federation_client_minimum_tls_version cannot be 1.3, "
                    "your OpenSSL does not support it"
                )

        # Whitelist of domains to not verify certificates for
        fed_whitelist_entries = config.get(
            "federation_certificate_verification_whitelist", []
        )
        if fed_whitelist_entries is None:
            fed_whitelist_entries = []

        # Support globs (*) in whitelist values
        self.federation_certificate_verification_whitelist: List[Pattern] = []
        for entry in fed_whitelist_entries:
            try:
                entry_regex = glob_to_regex(entry.encode("ascii").decode("ascii"))
            except UnicodeEncodeError:
                raise ConfigError(
                    "IDNA domain names are not allowed in the "
                    "federation_certificate_verification_whitelist: %s" % (entry,)
                )

            # Convert globs to regex
            self.federation_certificate_verification_whitelist.append(entry_regex)

        # List of custom certificate authorities for federation traffic validation
        custom_ca_list = config.get("federation_custom_ca_list", None)

        # Read in and parse custom CA certificates
        self.federation_ca_trust_root = None
        if custom_ca_list is not None:
            if len(custom_ca_list) == 0:
                # A trustroot cannot be generated without any CA certificates.
                # Raise an error if this option has been specified without any
                # corresponding certificates.
                raise ConfigError(
                    "federation_custom_ca_list specified without "
                    "any certificate files"
                )

            certs = []
            for ca_file in custom_ca_list:
                logger.debug("Reading custom CA certificate file: %s", ca_file)
                content = self.read_file(ca_file, "federation_custom_ca_list")

                # Parse the CA certificates
                try:
                    cert_base = Certificate.loadPEM(content)
                    certs.append(cert_base)
                except Exception as e:
                    raise ConfigError(
                        "Error parsing custom CA certificate file %s: %s" % (ca_file, e)
                    )

            self.federation_ca_trust_root = trustRootFromCertificates(certs)

        # This config option applies to non-federation HTTP clients
        # (e.g. for talking to recaptcha, identity servers, and such)
        # It should never be used in production, and is intended for
        # use only when running tests.
        self.use_insecure_ssl_client_just_for_testing_do_not_use = config.get(
            "use_insecure_ssl_client_just_for_testing_do_not_use"
        )

        self.tls_certificate: Optional[crypto.X509] = None
        self.tls_private_key: Optional[crypto.PKey] = None
def _acl_entry_matches(server_name, acl_entry):
    if not isinstance(acl_entry, six.string_types):
        logger.warn("Ignoring non-str ACL entry '%s' (is %s)", acl_entry, type(acl_entry))
        return False
    regex = glob_to_regex(acl_entry)
    return regex.match(server_name)
Exemple #15
0
    def read_config(self, config):

        acme_config = config.get("acme", None)
        if acme_config is None:
            acme_config = {}

        self.acme_enabled = acme_config.get("enabled", False)

        # hyperlink complains on py2 if this is not a Unicode
        self.acme_url = six.text_type(acme_config.get(
            "url", u"https://acme-v01.api.letsencrypt.org/directory"
        ))
        self.acme_port = acme_config.get("port", 80)
        self.acme_bind_addresses = acme_config.get("bind_addresses", ['::', '0.0.0.0'])
        self.acme_reprovision_threshold = acme_config.get("reprovision_threshold", 30)
        self.acme_domain = acme_config.get("domain", config.get("server_name"))

        self.tls_certificate_file = self.abspath(config.get("tls_certificate_path"))
        self.tls_private_key_file = self.abspath(config.get("tls_private_key_path"))

        if self.has_tls_listener():
            if not self.tls_certificate_file:
                raise ConfigError(
                    "tls_certificate_path must be specified if TLS-enabled listeners are "
                    "configured."
                )
            if not self.tls_private_key_file:
                raise ConfigError(
                    "tls_private_key_path must be specified if TLS-enabled listeners are "
                    "configured."
                )

        self._original_tls_fingerprints = config.get("tls_fingerprints", [])

        if self._original_tls_fingerprints is None:
            self._original_tls_fingerprints = []

        self.tls_fingerprints = list(self._original_tls_fingerprints)

        # Whether to verify certificates on outbound federation traffic
        self.federation_verify_certificates = config.get(
            "federation_verify_certificates", False,
        )

        # Whitelist of domains to not verify certificates for
        fed_whitelist_entries = config.get(
            "federation_certificate_verification_whitelist", [],
        )

        # Support globs (*) in whitelist values
        self.federation_certificate_verification_whitelist = []
        for entry in fed_whitelist_entries:
            # Convert globs to regex
            entry_regex = glob_to_regex(entry)
            self.federation_certificate_verification_whitelist.append(entry_regex)

        # List of custom certificate authorities for federation traffic validation
        custom_ca_list = config.get(
            "federation_custom_ca_list", None,
        )

        # Read in and parse custom CA certificates
        self.federation_ca_trust_root = None
        if custom_ca_list is not None:
            if len(custom_ca_list) == 0:
                # A trustroot cannot be generated without any CA certificates.
                # Raise an error if this option has been specified without any
                # corresponding certificates.
                raise ConfigError("federation_custom_ca_list specified without "
                                  "any certificate files")

            certs = []
            for ca_file in custom_ca_list:
                logger.debug("Reading custom CA certificate file: %s", ca_file)
                content = self.read_file(ca_file)

                # Parse the CA certificates
                try:
                    cert_base = Certificate.loadPEM(content)
                    certs.append(cert_base)
                except Exception as e:
                    raise ConfigError("Error parsing custom CA certificate file %s: %s"
                                      % (ca_file, e))

            self.federation_ca_trust_root = trustRootFromCertificates(certs)

        # This config option applies to non-federation HTTP clients
        # (e.g. for talking to recaptcha, identity servers, and such)
        # It should never be used in production, and is intended for
        # use only when running tests.
        self.use_insecure_ssl_client_just_for_testing_do_not_use = config.get(
            "use_insecure_ssl_client_just_for_testing_do_not_use"
        )

        self.tls_certificate = None
        self.tls_private_key = None