예제 #1
0
파일: authn.py 프로젝트: ranade1/hue
    def __call__(self, cookie=None, policy_url=None, logo_url=None,
                 query="", **kwargs):
        """
        Put up the login form
        """
        if cookie:
            headers = [cookie]
        else:
            headers = []

        resp = Response(headers=headers)

        argv = {"login": "",
                "password": "",
                "action": "verify",
                "policy_url": policy_url,
                "logo_url": logo_url,
                "query": query}
        logger.info("do_authentication argv: %s" % argv)
        mte = self.template_lookup.get_template(self.mako_template)
        resp.message = mte.render(**argv)
        return resp
예제 #2
0
파일: authn.py 프로젝트: 5monkeys/pysaml2
    def __call__(self, cookie=None, policy_url=None, logo_url=None,
                 query="", **kwargs):
        """
        Put up the login form
        """
        if cookie:
            headers = [cookie]
        else:
            headers = []

        resp = Response(headers=headers)

        argv = {"login": "",
                "password": "",
                "action": "verify",
                "policy_url": policy_url,
                "logo_url": logo_url,
                "query": query}
        logger.info("do_authentication argv: %s" % argv)
        mte = self.template_lookup.get_template(self.mako_template)
        resp.message = mte.render(**argv)
        return resp
예제 #3
0
    def do(self, request, binding, relay_state=""):
        _req = IDP.parse_artifact_resolve(request, binding)

        msg = IDP.create_artifact_response(_req, _req.artifact.text)

        hinfo = IDP.apply_binding(BINDING_SOAP,
                                  "%s" % msg,
                                  "",
                                  "",
                                  response=True)

        resp = Response(hinfo["data"], headers=hinfo["headers"])
        return resp(self.environ, self.start_response)
예제 #4
0
def finish_logout(environ, start_response, cache):
    logger.info("[logout done] environ: %s", environ)
    logger.info("[logout done] remaining subjects: %s",
                cache.uid2user.values())

    # remove cookie and stored info
    cookie = cache.delete_cookie(environ)

    resp = Response('You are now logged out of this service',
                    headers=[
                        cookie,
                    ])
    return resp(environ, start_response)
예제 #5
0
    def do(self,
           query,
           binding_in,
           relay_state="",
           encrypt_cert=None,
           **kwargs):
        log.debug("Query: " + str(query))
        log.debug("Inbound binding: " + str(binding_in))
        log.debug("Relay state: " + str(relay_state))
        log.debug("Encrypt_cert: " + str(encrypt_cert))
        log.debug("Kwargs: " + str(kwargs))

        try:
            resp_args = self.verify_request(query, binding_in)
        except Exception as excp:
            log.exception("SSO request verification failed.")
            return ServiceError("Request verification failed.")

        # Get user data
        try:
            userid = self.cache.uid2user[kwargs["uid"]]
            identity = self.userinfodb[userid]
            log.debug("Identity: " + str(identity))
        except Exception as excp:
            log.exception("Identity attributes retrieval failed")
            return ServiceError("Exception occurred")

        try:
            method = self.authn_broker.pick()[0]
            resp_args["authn"] = dict(blockchain=method)
            resp = self.create_authn_response(
                identity,
                userid=userid,
                encrypt_cert_assertion=encrypt_cert,
                **resp_args)
        except Exception as excp:
            log.exception("User data retrieval failed")
            return ServiceError("Exception occurred")

        kwargs = {}

        binding_out = resp_args['binding']
        destination = resp_args['destination']

        http_args = self.apply_binding(binding_out,
                                       "%s" % resp,
                                       destination,
                                       relay_state,
                                       response=True,
                                       **kwargs)
        return Response(http_args)
예제 #6
0
파일: saml2.py 프로젝트: borgand/SATOSA
    def construct_authn_response(self, idp, state, identity, name_id, authn, resp_args, relay_state,
                                 sign_response=True):
        """
        Constructs an auth response

        :type idp: saml.server.Server
        :type state: satosa.state.State
        :type identity: dict[str, str]
        :type name_id: saml2.saml.NameID
        :type authn: dict[str, str]
        :type resp_args: dict[str, str]
        :type relay_state: str
        :type sign_response: bool

        :param idp: The saml frontend idp server
        :param state: The current state
        :param identity: Information about an user (The ava attributes)
        :param name_id: The name id
        :param authn: auth info
        :param resp_args: response arguments
        :param relay_state: the relay state
        :param sign_response: Flag for signing the response or not
        :return: The constructed response
        """

        _resp = idp.create_authn_response(identity,
                                          name_id=name_id,
                                          authn=authn,
                                          sign_response=sign_response,
                                          **resp_args)

        http_args = idp.apply_binding(
            resp_args["binding"], "%s" % _resp, resp_args["destination"],
            relay_state, response=True)

        satosa_logging(LOGGER, logging.DEBUG, "HTTPargs: %s" % http_args, state)

        resp = None
        if http_args["data"]:
            resp = Response(http_args["data"], headers=http_args["headers"])
        else:
            for header in http_args["headers"]:
                if header[0] == "Location":
                    resp = Redirect(header[1])

        if not resp:
            msg = "Don't know how to return response"
            satosa_logging(LOGGER, logging.ERROR, msg, state)
            resp = ServiceError(msg)

        return resp
예제 #7
0
파일: sp.py 프로젝트: vivekdhayaal/pysaml2
def main(environ, start_response, sp):
    user = CACHE.get_user(environ)

    if user is None:
        sso = SSO(sp, environ, start_response, cache=CACHE, **ARGS)
        return sso.do()

    body = dict_to_table(user.data)
    authn_stmt = cgi.escape(user.authn_statement)
    body.append('<br><pre>' + authn_stmt + "</pre>")
    body.append('<br><a href="/logout">logout</a>')

    resp = Response(body)
    return resp(environ, start_response)
예제 #8
0
파일: sp.py 프로젝트: vasukikoppula/pysaml2
def main(environ, start_response, sp):
    user = CACHE.get_user(environ)

    if user is None:
        sso = SSO(sp, environ, start_response, cache=CACHE, **ARGS)
        return sso.do()

    body = dict_to_table(user.data)
    body.append("<br><pre>{authn_stmt}</pre>".format(
        authn_stmt=cgi.escape(user.authn_statement)))
    body.append("<br><a href='/logout'>logout</a>")

    resp = Response(body)
    return resp(environ, start_response)
예제 #9
0
파일: idp.py 프로젝트: wibed/pysaml2
    def do(self, request, binding, relay_state="", encrypt_cert=None):
        logger.info("--- Authn Query Service ---")
        _req = IDP.parse_authn_query(request, binding)
        _query = _req.message

        msg = IDP.create_authn_query_response(
            _query.subject, _query.requested_authn_context, _query.session_index
        )

        logger.debug("response: %s", msg)
        hinfo = IDP.apply_binding(BINDING_SOAP, "%s" % msg, "", "", response=True)

        resp = Response(hinfo["data"], headers=hinfo["headers"])
        return resp(self.environ, self.start_response)
예제 #10
0
파일: idp.py 프로젝트: vivekdhayaal/pysaml2
    def do(self, aid, binding, relay_state="", encrypt_cert=None):
        logger.info("--- Assertion ID Service ---")

        try:
            assertion = IDP.create_assertion_id_request_response(aid)
        except Unknown:
            resp = NotFound(aid)
            return resp(self.environ, self.start_response)

        hinfo = IDP.apply_binding(BINDING_URI, "%s" % assertion, response=True)

        logger.debug("HINFO: %s", hinfo)
        resp = Response(hinfo["data"], headers=hinfo["headers"])
        return resp(self.environ, self.start_response)
예제 #11
0
파일: secret.py 프로젝트: dv10den/IdPproxy
 def handle_static(environ, start_response, path):
     """
     Creates a response for a static file.
     :param environ: wsgi enviroment
     :param start_response: wsgi start response
     :param path: the static file and path to the file.
     :return: wsgi response for the static file.
     """
     try:
         text = open(path).read()
         if path.endswith(".ico"):
             resp = Response(text,
                             headers=[('Content-Type', "image/x-icon")])
         elif path.endswith(".html"):
             resp = Response(text, headers=[('Content-Type', 'text/html')])
         elif path.endswith(".txt"):
             resp = Response(text, headers=[('Content-Type', 'text/plain')])
         elif path.endswith(".css"):
             resp = Response(text, headers=[('Content-Type', 'text/css')])
         else:
             resp = Response(text, headers=[('Content-Type', 'text/xml')])
     except IOError:
         resp = NotFound()
     return resp(environ, start_response)
예제 #12
0
def whoami(environ, start_response, user):
    nameid = environ["repoze.who.identity"]["login"]
    ava = environ["repoze.who.identity"]["user"]
    if not nameid:
        return not_authn(environ, start_response)
    if ava:
        response = ["<h2>Your identity is supposed to be</h2>"]
        response.extend(dict_to_table(ava))
    else:
        response = [
            "<h2>The system did not return any information about you</h2>"]

    response.extend("<a href='logout'>Logout</a>")
    resp = Response(response)
    return resp(environ, start_response)
예제 #13
0
    def response(self, binding, http_args, do_not_start_response=False):
        if binding == BINDING_HTTP_REDIRECT:
            for param, value in http_args["headers"]:
                if param == "Location":
                    resp = SeeOther(str(value))
                    break
            else:
                resp = ServiceError("Parameter error")
        else:
            resp = Response(http_args["data"], headers=http_args["headers"])

        if do_not_start_response:
            return resp
        else:
            return resp(self.environ, self.start_response)
예제 #14
0
파일: idp.py 프로젝트: vivekdhayaal/pysaml2
    def response(self, binding, http_args):
        resp = None
        if binding == BINDING_HTTP_ARTIFACT:
            resp = Redirect()
        elif http_args["data"]:
            resp = Response(http_args["data"], headers=http_args["headers"])
        else:
            for header in http_args["headers"]:
                if header[0] == "Location":
                    resp = Redirect(header[1])

        if not resp:
            resp = ServiceError("Don't know how to return response")

        return resp(self.environ, self.start_response)
예제 #15
0
파일: sp.py 프로젝트: rohe/actester
def session(environ, start_response):
    id = environ["PATH_INFO"][9:]
    _info = SESSIONDB[id]
    argv = {
        "assertion":
        json.dumps(_info["assertion"],
                   sort_keys=True,
                   indent=2,
                   separators=(',', ': ')),
        "info":
        _info["info"]
    }
    resp = Response(mako_template="session.mako",
                    template_lookup=LOOKUP,
                    headers=[])
    return resp(environ, start_response, **argv)
예제 #16
0
    def slo_redirect_or_post(self, query, binding):
        log.debug("Query: " + query)
        log.debug("Binding: " + binding)

        try:
            req_info = self.parse_logout_request(query, binding)
        except Exception as exc:
            log.exception("Message parsing failed.")
            return BadRequest("Message parsing failed")

        msg = req_info.message
        if msg.name_id:
            lid = self.ident.find_local_id(msg.name_id)
            if lid in self.cache.user2uid:
                uid = self.cache.user2uid[lid]
                if uid in self.cache.uid2user:
                    del self.cache.uid2user[uid]
                del self.cache.user2uid[lid]
            try:
                self.session_db.remove_authn_statements(msg.name_id)
            except KeyError as exc:
                log.exception("Session removal failed")

        resp = self.create_logout_response(msg, [binding])

        binding, destination = self.pick_binding("single_logout_service",
                                                 [binding], "spsso", req_info)
        response = True

        try:
            hinfo = self.apply_binding(binding,
                                       "%s" % resp,
                                       destination,
                                       query['relay_state'],
                                       response=response)
        except Exception as exc:
            log.exception("ServiceError: %s", exc)
            return ServiceError("%s" % exc)

        if binding == BINDING_HTTP_REDIRECT:
            for key, value in hinfo["headers"]:
                if key.lower() == "location":
                    return Redirect(value, headers=hinfo["headers"])

            return ServiceError("missing Location header")
        else:
            return Response(hinfo["data"], headers=hinfo["headers"])
예제 #17
0
파일: secret.py 프로젝트: dv10den/IdPproxy
    def handle_metadata(self, environ, start_response):
        """
        Creates the response for the first page in the metadata generation.
        :param environ: wsgi enviroment
        :param start_response: wsgi start respons
        :return: wsgi response for the mako file metadata.mako.
        """
        resp = Response(mako_template="metadata.mako",
                        template_lookup=self.lookup,
                        headers=[])

        argv = {
            "action": CONST_METADATASAVE,
            "sociallist": sorted(self.social_service_key_list),
            "spKeyList": sorted(self.sp_key_list),
            "verify": CONST_METADATAVERIFY,
        }
        return resp(environ, start_response, **argv)
예제 #18
0
    def do(self, request, binding, relay_state="", encrypt_cert=None):
        logger.info("--- Single Log Out Service ---")
        try:
            _, body = request.split("\n")
            logger.debug("req: '%s'", body)
            req_info = IDP.parse_logout_request(body, binding)
        except Exception as exc:
            logger.error("Bad request: %s", exc)
            resp = BadRequest("%s" % exc)
            return resp(self.environ, self.start_response)

        msg = req_info.message
        if msg.name_id:
            lid = IDP.ident.find_local_id(msg.name_id)
            logger.info("local identifier: %s", lid)
            if lid in IDP.cache.user2uid:
                uid = IDP.cache.user2uid[lid]
                if uid in IDP.cache.uid2user:
                    del IDP.cache.uid2user[uid]
                del IDP.cache.user2uid[lid]
            # remove the authentication
            try:
                IDP.session_db.remove_authn_statements(msg.name_id)
            except KeyError as exc:
                logger.error("ServiceError: %s", exc)
                resp = ServiceError("%s" % exc)
                return resp(self.environ, self.start_response)

        resp = IDP.create_logout_response(msg, [binding])

        try:
            hinfo = IDP.apply_binding(binding, "%s" % resp, "", relay_state)
        except Exception as exc:
            logger.error("ServiceError: %s", exc)
            resp = ServiceError("%s" % exc)
            return resp(self.environ, self.start_response)

        #_tlh = dict2list_of_tuples(hinfo["headers"])
        delco = delete_cookie(self.environ, "idpauthn")
        if delco:
            hinfo["headers"].append(delco)
        logger.info("Header: %s", (hinfo["headers"], ))
        resp = Response(hinfo["data"], headers=hinfo["headers"])
        return resp(self.environ, self.start_response)
예제 #19
0
파일: front.py 프로젝트: simudream/s2sproxy
    def construct_authn_response(self,
                                 identity,
                                 name_id,
                                 authn,
                                 resp_args,
                                 relay_state,
                                 sign_response=True):
        """

        :param identity:
        :param name_id:
        :param authn:
        :param resp_args:
        :param relay_state:
        :param sign_response:
        :return:
        """

        _resp = self.idp.create_authn_response(identity,
                                               name_id=name_id,
                                               authn=authn,
                                               sign_response=sign_response,
                                               **resp_args)

        http_args = self.idp.apply_binding(resp_args["binding"],
                                           "%s" % _resp,
                                           resp_args["destination"],
                                           relay_state,
                                           response=True)

        logger.debug("HTTPargs: %s" % http_args)

        resp = None
        if http_args["data"]:
            resp = Response(http_args["data"], headers=http_args["headers"])
        else:
            for header in http_args["headers"]:
                if header[0] == "Location":
                    resp = Redirect(header[1])

        if not resp:
            resp = ServiceError("Don't know how to return response")

        return resp(self.environ, self.start_response)
예제 #20
0
def main(environ, start_response, sp):
    user = CACHE.get_user(environ)

    if user is None:
        sso = SSO(sp, environ, start_response, cache=CACHE, **ARGS)
        return sso.do()

    body = dict_to_table(user.data)
    body.append("<br><pre>{authn_stmt}</pre>".format(
        authn_stmt=cgi.escape(user.authn_statement)))
    body.append("<br><a href='/logout'>logout</a>")

    body = [
        item if not isinstance(item, six.binary_type) else item.encode("utf-8")
        for item in body
    ]

    resp = Response(body)
    return resp(environ, start_response)
예제 #21
0
파일: util.py 프로젝트: simudream/IdProxy
    def do(self,
           request,
           binding,
           relay_state="",
           mtype=None,
           encrypt_cert=None):
        _req = self.idphandler.idp_server.parse_artifact_resolve(
            request, binding)

        msg = self.idphandler.idp_server.create_artifact_response(
            _req, _req.artifact.text)

        hinfo = self.idphandler.idp_server.apply_binding(BINDING_SOAP,
                                                         "%s" % msg,
                                                         "",
                                                         "",
                                                         response=True)

        resp = Response(hinfo["data"], headers=hinfo["headers"])
        return resp(self.environ, self.start_response)
예제 #22
0
파일: idp.py 프로젝트: wibed/pysaml2
    def do(self, request, binding, relay_state="", encrypt_cert=None):
        logger.info("--- Attribute Query Service ---")

        _req = IDP.parse_attribute_query(request, binding)
        _query = _req.message

        name_id = _query.subject.name_id
        uid = name_id.text
        logger.debug("Local uid: %s", uid)
        identity = EXTRA[uid]

        # Comes in over SOAP so only need to construct the response
        args = IDP.response_args(_query, [BINDING_SOAP])
        msg = IDP.create_attribute_response(identity, name_id=name_id, **args)

        logger.debug("response: %s", msg)
        hinfo = IDP.apply_binding(BINDING_SOAP, "%s" % msg, "", "", response=True)

        resp = Response(hinfo["data"], headers=hinfo["headers"])
        return resp(self.environ, self.start_response)
예제 #23
0
    def do(self, query, binding, relay_state="", encrypt_cert=None):
        logger.info("--- Manage Name ID Service ---")
        req = IDP.parse_manage_name_id_request(query, binding)
        request = req.message

        # Do the necessary stuff
        name_id = IDP.ident.handle_manage_name_id_request(
            request.name_id, request.new_id, request.new_encrypted_id,
            request.terminate)

        logger.debug("New NameID: %s" % name_id)

        _resp = IDP.create_manage_name_id_response(request)

        # It's using SOAP binding
        hinfo = IDP.apply_binding(BINDING_SOAP, "%s" % _resp, "",
                                  relay_state, response=True)

        resp = Response(hinfo["data"], headers=hinfo["headers"])
        return resp(self.environ, self.start_response)
예제 #24
0
def status(environ, start_response, state):
    """ Return the status of the users SSO sessions """
    result = []
    for session in state.sessions():
        for typ in SOCIAL_SRV:
            if session[typ]:
                result.append("<h2>%s</h2>" % typ.upper())
                break

        result.append("<table border=\"1\">")
        for prop in ["authentication", "identity"]:
            val = session[prop]
            if isinstance(val, dict):
                val = _dict_to_table(val)
            result.append("<tr><td>%s</td><td>%s</td></tr>" % (prop, val))
        result.append("</table>")
        result.append("<br>")

    resp = Response(result)
    return resp(environ, start_response)
예제 #25
0
def authn_response(server_env, req_info, userid, identity,
                   authn=None, authn_decl=None, service=""):
    # base 64 encoded request

    logger.debug("User info: %s" % identity)

    if service:
        issuer = "%s%s" % (server_env["base_url"], service)
    else:
        issuer = None

    logger.info("ISSUER: %s" % issuer)
    _idp = server_env["idp"]

    binding, destination = _idp.pick_binding("assertion_consumer_service",
                                             entity_id=req_info.sender())

    logger.debug("binding: %s, destination: %s" % (binding, destination))

    authn_resp = _idp.create_authn_response(identity, req_info.message.id,
                                            destination,
                                            req_info.sender(),
                                            req_info.message.name_id_policy,
                                            str(userid), authn=authn, 
                                            sign_assertion=server_env["SIGN"],
                                            authn_decl=authn_decl,
                                            issuer=issuer)

    logger.info("LOGIN success: sp_entity_id=%s#authn=%s" % (req_info.sender(),
                                                             authn))
    logger.debug("AuthNResponse: %s" % authn_resp)

    ht_args = _idp.apply_binding(binding, "%s" % authn_resp, destination,
                                 req_info.relay_state, response=True)

    logger.debug("ht_args: %s" % ht_args)

    if "status" in ht_args and ht_args["status"] == 302:
        return Redirect(ht_args["data"], headers=ht_args["headers"])
    else:
        return Response(ht_args["data"], headers=ht_args["headers"])
예제 #26
0
def username_password_authn(environ, start_response, reference, key,
                            redirect_uri):
    """
    Display the login form
    """
    logger.info("The login page")
    headers = []

    resp = Response(mako_template="login.mako", template_lookup=LOOKUP,
                    headers=headers)

    argv = {
        "action": "/verify",
        "login": "",
        "password": "",
        "key": key,
        "authn_reference": reference,
        "redirect_uri": redirect_uri
    }
    logger.info("do_authentication argv: %s" % argv)
    return resp(environ, start_response, **argv)
예제 #27
0
파일: util.py 프로젝트: simudream/IdProxy
    def do(self,
           request,
           binding,
           relay_state="",
           mtype=None,
           encrypt_cert=None):
        logger.info("--- Attribute Query Service ---")

        _req = self.idphandler.idp_server.parse_attribute_query(
            request, binding)
        _query = _req.message

        name_id = _query.subject.name_id
        uid = name_id.text
        logger.debug("Local uid: %s" % uid)
        identity = {}

        authn = self.idphandler.authn_broker[
            self.idphandler.auth_cookie.authn_ref]
        method = None
        if authn:
            method = authn["method"]
        if method:
            identity = method.extra(self.environ, self.start_response,
                                    self.user)

        # Comes in over SOAP so only need to construct the response
        args = self.idphandler.idp_server.response_args(_query, [BINDING_SOAP])
        msg = self.idphandler.idp_server.create_attribute_response(
            identity, name_id=name_id, **args)

        logger.debug("response: %s" % msg)
        hinfo = self.idphandler.idp_server.apply_binding(BINDING_SOAP,
                                                         "%s" % msg,
                                                         "",
                                                         "",
                                                         response=True)

        resp = Response(hinfo["data"], headers=hinfo["headers"])
        return resp(self.environ, self.start_response)
예제 #28
0
    def do(self, query, binding, relay_state="", encrypt_cert=None):
        req = IDP.parse_name_id_mapping_request(query, binding)
        request = req.message
        # Do the necessary stuff
        try:
            name_id = IDP.ident.handle_name_id_mapping_request(
                request.name_id, request.name_id_policy)
        except Unknown:
            resp = BadRequest("Unknown entity")
            return resp(self.environ, self.start_response)
        except PolicyError:
            resp = BadRequest("Unknown entity")
            return resp(self.environ, self.start_response)

        info = IDP.response_args(request)
        _resp = IDP.create_name_id_mapping_response(name_id, **info)

        # Only SOAP
        hinfo = IDP.apply_binding(BINDING_SOAP, "%s" % _resp, "", "",
                                  response=True)

        resp = Response(hinfo["data"], headers=hinfo["headers"])
        return resp(self.environ, self.start_response)
예제 #29
0
def logout_response(server_env, req_info, status=None):
    logger.info("LOGOUT of '%s' by '%s'" % (req_info.subject_id(),
                                            req_info.sender()))

    _idp = server_env["idp"]
    if req_info.binding != BINDING_SOAP:
        bindings = [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST]
        binding, destination = _idp.pick_binding("single_logout_service",
                                                 bindings,
                                                 entity_id=req_info.sender())
        bindings = [binding]
    else:
        bindings = [BINDING_SOAP]
        destination = ""

    response = _idp.create_logout_response(req_info.message, bindings,
                                           status, sign=server_env["SIGN"])

    ht_args = _idp.apply_binding(bindings[0], "%s" % response,
                                 destination, req_info.relay_state,
                                 response=True)

    return Response(**ht_args)
예제 #30
0
파일: idp.py 프로젝트: wibed/pysaml2
def username_password_authn(
    environ, start_response, reference, key, redirect_uri, headers=None
):
    """
    Display the login form
    """
    logger.info("The login page")

    kwargs = dict(mako_template="login.mako", template_lookup=LOOKUP)
    if headers:
        kwargs["headers"] = headers

    resp = Response(**kwargs)

    argv = {
        "action": "/verify",
        "login": "",
        "password": "",
        "key": key,
        "authn_reference": reference,
        "redirect_uri": redirect_uri,
    }
    logger.info("do_authentication argv: %s", argv)
    return resp(environ, start_response, **argv)
예제 #31
0
파일: sp.py 프로젝트: vasukikoppula/pysaml2
def logout(environ, start_response, sp):
    user = CACHE.get_user(environ)

    if user is None:
        sso = SSO(sp, environ, start_response, cache=CACHE, **ARGS)
        return sso.do()

    logger.info("[logout] subject_id: '%s'", user.name_id)

    # What if more than one
    data = sp.global_logout(user.name_id)
    logger.info("[logout] global_logout > %s", data)

    for entity_id, logout_info in data.items():
        if isinstance(logout_info, tuple):
            binding, http_info = logout_info

            if binding == BINDING_HTTP_POST:
                body = "".join(http_info["data"])
                resp = Response(body)
                return resp(environ, start_response)
            elif binding == BINDING_HTTP_REDIRECT:
                for key, value in http_info["headers"]:
                    if key.lower() == "location":
                        resp = Redirect(value)
                        return resp(environ, start_response)

                resp = ServiceError("missing Location header")
                return resp(environ, start_response)
            else:
                resp = ServiceError("unknown logout binding: %s", binding)
                return resp(environ, start_response)
        else:  # result from logout, should be OK
            pass

    return finish_logout(environ, start_response)