See super class satosa.frontends.base.FrontendModule#register_endpoints

        Endpoints have the format

        {base}/{backend}/{co_name}/{binding path}

        For example the HTTP-Redirect binding request path will have the
        format

        {base}/{backend}/{co_name}/sso/redirect

        :type providers: list[str]
        :rtype list[(str, ((satosa.context.Context, Any) ->
                    satosa.response.Response, Any))] |
               list[(str, (satosa.context.Context) ->
                    satosa.response.Response)]
        :param backend_names: A list of backend names
        :return: A list of url and endpoint function pairs

def _register_endpoints(self, backend_names):
        """
        See super class satosa.frontends.base.FrontendModule#register_endpoints

        Endpoints have the format

        {base}/{backend}/{co_name}/{binding path}

        For example the HTTP-Redirect binding request path will have the
        format

        {base}/{backend}/{co_name}/sso/redirect

        :type providers: list[str]
        :rtype list[(str, ((satosa.context.Context, Any) ->
                    satosa.response.Response, Any))] |
               list[(str, (satosa.context.Context) ->
                    satosa.response.Response)]
        :param backend_names: A list of backend names
        :return: A list of url and endpoint function pairs
        """
        # Create a regex pattern that will match any of the CO names. We
        # escape special characters like '+' and '.' that are valid
        # characters in an URL encoded string.
        co_names = self._co_names_from_config()
        url_encoded_co_names = [re.escape(quote_plus(name)) for name in
                                co_names]
        co_name_pattern = "|".join(url_encoded_co_names)

        # Create a regex pattern that will match any of the backend names.
        backend_url_pattern = "|^".join(backend_names)
        logger.debug("Input backend names are {}".format(backend_names))
        logger.debug("Created backend regex '{}'".format(backend_url_pattern))

        # Hold a list of tuples containing URL regex patterns and the callables
        # that handle them.
        url_to_callable_mappings = []

        # Loop over IdP endpoint categories, e.g., single_sign_on_service.
        for endpoint_category in self.endpoints:
            logger.debug("Examining endpoint category {}".format(
                                    endpoint_category))

            # For each endpoint category loop of the bindings and their
            # assigned endpoints.
            for binding, endpoint in self.endpoints[endpoint_category].items():
                logger.debug("Found binding {} and endpoint {}".format(binding,
                             endpoint))

                # Parse out the path from the endpoint.
                endpoint_path = urlparse(endpoint).path
                logger.debug("Using path {}".format(endpoint_path))

                # Use the backend URL pattern and the endpoint path to create
                # a regex that will match and that includes a pattern for
                # matching the URL encoded CO name.
                regex_pattern = "(^{})/({})/{}".format(
                                backend_url_pattern,
                                co_name_pattern,
                                endpoint_path)
                logger.debug("Created URL regex {}".format(regex_pattern))

                # Map the regex pattern to a callable.
                the_callable = functools.partial(self.handle_authn_request,
                                                 binding_in=binding)
                logger.debug("Created callable {}".format(the_callable))

                mapping = (regex_pattern, the_callable)
                url_to_callable_mappings.append(mapping)
                logger.debug("Adding mapping {}".format(mapping))

        return url_to_callable_mappings