Exemplo n.º 1
0
    def __call__(self, *args, **kwargs):
        log.debug("Start new authentication")

        # Redirect to the create challenge entry point
        if "key" in kwargs:
            return Redirect("{0}?key={1}".format(self.urls['url_createchallenge'],kwargs["key"]))
        else:
            return Redirect("{0}?".format(self.urls['url_createchallenge']))
Exemplo n.º 2
0
    def create_authn_request(self, session, acr_value=None, **kwargs):
        session["state"] = rndstr(32)
        request_args = {
            "response_type": self.behaviour["response_type"],
            "state": session["state"],
            "redirect_uri": self.registration_response["redirect_uris"][0]
        }

        try:
            request_args["scope"] = self.behaviour["scope"]
        except KeyError:
            pass

        request_args.update(kwargs)
        cis = self.construct_AuthorizationRequest(request_args=request_args)
        logger.debug("request: %s" % cis)

        url, body, ht_args, cis = self.uri_and_body(AuthorizationRequest,
                                                    cis,
                                                    method="GET",
                                                    request_args=request_args)

        self.authz_req[request_args['state']] = cis
        logger.debug("body: %s" % body)
        logger.info("URL: %s" % url)
        logger.debug("ht_args: %s" % ht_args)

        resp = Redirect(str(url))
        if ht_args:
            resp.headers.extend([(a, b) for a, b in ht_args.items()])
        logger.debug("resp_headers: %s" % resp.headers)
        return resp
    def authn_reply(self, areq, aresp, bsid, **kwargs):
        """

        :param areq: Authorization Request
        :param aresp: Authorization Response
        :param bsid: Session id
        :param kwargs: Additional keyword args
        :return:
        """
        if "redirect_uri" in areq:
            # TODO verify that the uri is reasonable
            redirect_uri = areq["redirect_uri"]
        else:
            redirect_uri = self.urlmap[areq["client_id"]]

        location = location_url(areq["response_type"], redirect_uri,
                                aresp.to_urlencoded())

        LOG_DEBUG("Redirected to: '%s' (%s)" % (location, type(location)))

        # set cookie containing session ID

        cookie = make_cookie(self.cookie_name, bsid, self.seed)

        return Redirect(str(location), headers=[cookie])
Exemplo n.º 4
0
    def create_authn_request(self, session, acr_value=None):
        session["state"] = rndstr()
        session["nonce"] = rndstr()
        request_args = {
            "response_type": self.behaviour["response_type"],
            "scope": self.behaviour["scope"],
            "state": session["state"],
            "nonce": session["nonce"],
            "redirect_uri": self.registration_response["redirect_uris"][0]
        }

        if acr_value is not None:
            request_args["acr_values"] = acr_value

        cis = self.construct_AuthorizationRequest(request_args=request_args)
        logger.debug("request: %s" % cis)

        url, body, ht_args, cis = self.uri_and_body(AuthorizationRequest, cis,
                                                    method="GET",
                                                    request_args=request_args)

        logger.debug("body: %s" % body)
        logger.info("URL: %s" % url)
        logger.debug("ht_args: %s" % ht_args)

        resp = Redirect(str(url))
        if ht_args:
            resp.headers.extend([(a, b) for a, b in ht_args.items()])
        logger.debug("resp_headers: %s" % resp.headers)
        return resp
Exemplo n.º 5
0
    def create_authn_request(self, session, acr_value=None, **kwargs):
        session["state"] = rndstr(32)
        request_args = {
            "response_type": self.behaviour["response_type"],
            "scope": self.behaviour["scope"],
            "state": session["state"],
            "redirect_uri": self.registration_response["redirect_uris"][0],
        }

        if self.oidc:
            session["nonce"] = rndstr(32)
            request_args["nonce"] = session["nonce"]

        if acr_value is not None:
            request_args["acr_values"] = acr_value

        request_args.update(kwargs)
        cis = self.construct_AuthorizationRequest(request_args=request_args)
        logger.debug("request: %s" % sanitize(cis))

        url, body, ht_args, cis = self.uri_and_body(
            AuthorizationRequest, cis, method="GET", request_args=request_args
        )

        self.authz_req[request_args["state"]] = cis
        logger.debug("body: %s" % sanitize(body))
        logger.info("URL: %s" % sanitize(url))
        logger.debug("ht_args: %s" % sanitize(ht_args))

        resp = Redirect(str(url))
        if ht_args:
            resp.headers.extend([(a, b) for a, b in ht_args.items()])
        logger.debug("resp_headers: %s" % sanitize(resp.headers))
        return resp
Exemplo n.º 6
0
def logout(request):
    CLIENTS = request.environ["OIDC_CLIENTS"]
    client = CLIENTS[request.session["op"]]

    logout_url = client.endsession_endpoint
    try:
        # Specify to which URL the OP should return the user after
        # log out. That URL must be registered with the OP at client
        # registration.
        logout_url += "?" + urllib.urlencode({
            "post_logout_redirect_uri": client.registration_response["post_logout_redirect_uris"][0]
        })
    except KeyError:
        pass
    else:
        # If there is an ID token send it along as a id_token_hint
        _idtoken = get_id_token(client, request.session)
        if _idtoken:
            logout_url += "&" + urllib.urlencode({
                "id_token_hint": id_token_as_signed_jwt(client, _idtoken, "HS256")
            })

    request.session.clear()
    oic_resp = Redirect(str(logout_url))
    oic_resp(request.environ, start_response)
    resp = HttpResponse(content_type=oic_resp._content_type, status=oic_resp._status)
    for key,val in oic_resp.headers:
        resp[key] = val
    return resp
Exemplo n.º 7
0
    def fini(self, session, conv):
        _tid = session["testid"]
        conv.test_output.append(("X", END_TAG))
        self.store_test_info(session)
        self.dump_log(session, _tid)
        session["node"].complete = True

        _grp = _tid.split("-")[1]

        resp = Redirect("%sopresult#%s" % (self.conf.BASE, _grp))
        return resp(self.environ, self.start_response)
Exemplo n.º 8
0
    def begin(self, environ, server_env, start_response, cookie,
              sid, info):

        state = rndstr()
        server_env["CACHE"].alternate_sid(sid, state)
        callback = server_env["base_url"] + self.social_endpoint

        # redirect the user to facebook for the authentication
        ar = AuthorizationRequest().from_dict({"client_id": self.client_id,
                                               "redirect_uri": callback,
                                               "state": state,
                                               "response_type": ["code"],
                                               "scope": self._scope})
        url = ar.request(self.extra["authorization_endpoint"])
        logger.info("[OAuth2] callback url: %s" % url)
        if cookie:
            resp = Redirect(url, headers=[cookie])
        else:
            resp = Redirect(url)
        return resp(environ, start_response)
Exemplo n.º 9
0
    def run(self):
        _client = self.conv.entity

        url, body, ht_args, csi = _client.request_info(
            self.request, method=self.method, request_args=self.req_args,
            lax=True, **self.op_args)

        self.csi = csi

        self.conv.events.store(EV_REDIRECT_URL, url,
                               sender=self.__class__.__name__)
        return Redirect(str(url))
Exemplo n.º 10
0
 def _redirect_authz_error(error, redirect_uri, descr=None, state="",
                           return_type=None):
     err = AuthorizationErrorResponse(error=error)
     if descr:
         err["error_description"] = descr
     if state:
         err["state"] = state
     if return_type is None or return_type == ["code"]:
         location = err.request(redirect_uri)
     else:
         location = err.request(redirect_uri, True)
     return Redirect(location)
Exemplo n.º 11
0
    def verify(self, request, cookie, **kwargs):
        """
        Verifies if the authentication was successful.

        :rtype : Response
        :param request: Contains the request parameters.
        :param cookie: Cookies sent with the request.
        :param kwargs: Any other parameters.
        :return: If the authentication was successful: a redirect to the
        return_to url. Otherwise a unauthorized response.
        :raise: ValueError
        """
        logger.debug("verify(%s)" % request)
        if isinstance(request, six.string_types):
            _dict = urlparse.parse_qs(request)
        elif isinstance(request, dict):
            _dict = request
        else:
            raise ValueError("Wrong type of input")
        try:
            cas_cookie, _ts, _typ = self.getCookieValue(
                cookie, self.CONST_CAS_COOKIE)
            data = json.loads(cas_cookie)
            nonce = base64.b64decode(data[self.CONST_NONCE])
            if nonce != _dict[self.CONST_NONCE][0]:
                logger.warning(
                    'Someone tried to login without a correct nonce!')
                return Unauthorized("You are not authorized!")
            acr = None
            try:
                acr = _dict["acr_values"][0]
            except KeyError:
                pass
            uid = self.handle_callback(_dict[self.CONST_TICKET],
                                       self.get_service_url(nonce, acr))
            if uid is None or uid == "":
                logger.info('Someone tried to login, but was denied by CAS!')
                return Unauthorized("You are not authorized!")
            cookie = self.create_cookie(uid, "casm")
            return_to = self.generate_return_url(self.return_to, uid)
            if '?' in return_to:
                return_to += "&"
            else:
                return_to += "?"
            return_to += base64.b64decode(data[self.CONST_QUERY])
            return Redirect(return_to, headers=[cookie])
        except:
            logger.fatal('Metod verify in user_cas.py had a fatal exception.',
                         exc_info=True)
            return Unauthorized("You are not authorized!")
Exemplo n.º 12
0
 def display_test_list(self, **kwargs):
     try:
         if self.sh.session_init():
             return self.inut.flow_list()
         else:
             try:
                 resp = Redirect("%s/opresult#%s" %
                                 (self.base_url, self.sh["testid"][0]))
             except KeyError:
                 return self.inut.flow_list(**kwargs)
             else:
                 return resp(self.inut.environ, self.inut.start_response)
     except Exception as err:
         exception_trace("display_test_list", err)
         return self.inut.err_response("session_setup", err)
Exemplo n.º 13
0
 def __call__(self, query, *args, **kwargs):
     """
     Saves the query parameters sent from the client in a cookie and then redirects to the SPHandler.
     :param query: Query parameters to be returned to op server.
     :param args: Not used.
     :param kwargs: Not used.
     :return:
     """
     if self.acr is not None and query is not None and query.find(
             Authenticate.CONST_ACR) == -1:
         query += "&" + Authenticate.CONST_ACR + "=" + self.acr
     cookie = self.create_cookie(
         '{"' + self.CONST_QUERY + '": "' + base64.b64encode(query) + '"}',
         self.CONST_SP_COOKIE, self.CONST_SP_COOKIE)
     return Redirect(self.redirect_url, headers=[cookie])
Exemplo n.º 14
0
def application(environ, start_response):
    session = environ['beaker.session']

    path = environ.get('PATH_INFO', '').lstrip('/')
    if path == "robots.txt":
        return static(environ, start_response, "static/robots.txt")

    if path.startswith("static/"):
        return static(environ, start_response, path)

    if path == "logout":
        session.invalidate()
        resp = Redirect("static/log_out_message.html")
        return resp(environ, start_response)

    if path == "as":
        session["callback"] = True
        request = parse_qs(get_or_post(environ))
        _cli = CONSUMER[unquote(request["authzsrv"][0])]
        session["client"] = _cli
        resp = Redirect(_cli.begin(RP_CONF.BASE, path))
        return resp(environ, start_response)

    if path == "authz_cb":
        _cli = session["client"]
        request = get_or_post(environ)
        aresp = _cli.handle_authorization_response(request)
        rargs = {"code": aresp["code"]}
        atresp = _cli.do_access_token_request(request_args=rargs)
        #extra_args=None, http_args=None,)
        # Access token should be stored somewhere for later usage
        Token[atresp["state"]] = atresp
        resp = Response("Got access token: %s" % atresp["access_token"])
        return resp(environ, start_response)

    return as_choice(environ, start_response)
Exemplo n.º 15
0
 def display_test_list(self):
     try:
         if self.sh.session_init():
             return self.io.flow_list(self.sh.session)
         else:
             try:
                 resp = Redirect(
                     "%sopresult#%s" %
                     (self.io.conf.BASE, self.sh.session["testid"][0]))
             except KeyError:
                 return self.io.flow_list(self.sh.session)
             else:
                 return resp(self.io.environ, self.io.start_response)
     except Exception as err:
         exception_trace("display_test_list", err)
         return self.io.err_response(self.sh.session, "session_setup", err)
Exemplo n.º 16
0
    def run(self):
        _client = self.conv.entity
        _trace = self.conv.trace

        url, body, ht_args, csi = _client.request_info(
            self.request,
            method=self.method,
            request_args=self.req_args,
            lax=True,
            **self.op_args)

        self.csi = csi

        _trace.info("redirect.url: %s" % url)
        _trace.info("redirect.header: %s" % ht_args)
        self.conv.events.store('url', url)
        return Redirect(str(url))
Exemplo n.º 17
0
    def _create_authzreq(self, role, session, acr_value=""):
        request_args = role.get_request_args(acr_value, session)

        try:
            url, body, ht_args, csi = role.request_info(
                AuthorizationRequest, "GET", request_args=request_args)
        except Exception:
            message = traceback.format_exception(*sys.exc_info())
            resp = ServiceError(message)
        else:
            resp_headers = [("Location", str(url))]

            if ht_args:
                resp_headers.extend([(a, b) for a, b in list(ht_args.items())])

            resp = Redirect(url, headers=resp_headers)
        return resp
Exemplo n.º 18
0
def test(environ, session, path):
    _test = path[5:]
    session["flow_index"] = FLOW_SEQUENCE.index(_test)
    session["phase_index"] = 0
    session["start"] = 0
    session["trace"] = Trace()
    _op = resp = client = link = None
    try:
        query = parse_qs(environ["QUERY_STRING"])
    except KeyError:
        pass
    else:
        try:
            session["op"] = query["op"][0]
            try:
                assert session["op"] in SERVER_ENV["OP"]
                _op = session["op_conf"] = SERVER_ENV["OP"][session["op"]]
            except AssertionError:
                return BadRequest("OP chosen that is not configured")
        except KeyError:
            pass
    if _op:
        try:
            client = SERVER_ENV["OIC_CLIENT"][session["opkey"]]
        except KeyError:
            _key = rndstr()
            try:
                kwargs = {"deviate": _op["deviate"]}
            except KeyError:
                kwargs = {}
            client = create_client(_key, **kwargs)
            session["opkey"] = _key
            SERVER_ENV["OIC_CLIENT"][session["opkey"]] = client

        if _op["features"]["discovery"]:
            link = _op["provider"]["dynamic"]
            session["srv_discovery_url"] = link
        else:
            client.handle_provider_config(_op["provider"], session["op"])
    else:
        resp = Redirect("/")

    if resp:
        return resp
    else:
        return {"client": client, "link": link}
Exemplo n.º 19
0
    def response(self, binding, http_args, query):
            cookie = self.create_cookie('{"' + self.CONST_QUERY + '": "' + base64.b64encode(query) +
                                        '" , "' + self.CONST_HASIDP + '": "True" }',
                                        self.CONST_SAML_COOKIE, self.CONST_SAML_COOKIE)
            if binding == BINDING_HTTP_ARTIFACT:
                resp = Redirect()
            elif binding == BINDING_HTTP_REDIRECT:
                for param, value in http_args["headers"]:
                    if param == "Location":
                        resp = SeeOther(str(value), headers=[cookie])
                        break
                else:
                    raise ServiceErrorException("Parameter error")
            else:
                http_args["headers"].append(cookie)
                resp = Response(http_args["data"], headers=http_args["headers"])

            return resp
Exemplo n.º 20
0
    def verify(self, request, **kwargs):
        """
        Verifies that the given username and password was correct
        :param request: Either the query part of a URL a urlencoded
        body of a HTTP message or a parse such.
        :param kwargs: Catch whatever else is sent.
        :return: redirect back to where ever the base applications
        wants the user after authentication.
        """

        logger.debug("verify(%s)" % request)
        if isinstance(request, basestring):
            _dict = parse_qs(request)
        elif isinstance(request, dict):
            _dict = request
        else:
            raise ValueError("Wrong type of input")

        logger.debug("dict: %s" % _dict)
        logger.debug("passwd: %s" % self.passwd)
        # verify username and password
        try:
            self._verify(_dict["password"][0], _dict["login"][0])
        except (AssertionError, KeyError):
            resp = Unauthorized("Unknown user or wrong password")
            return resp, False
        else:
            # if "cookie" not in kwargs or self.srv.cookie_name not in kwargs["cookie"]:
            headers = [self.create_cookie(_dict["login"][0], "upm")]
            try:
                _qp = _dict["query"][0]
            except KeyError:
                _qp = self.get_multi_auth_cookie(kwargs['cookie'])
            try:
                return_to = self.generate_return_url(kwargs["return_to"], _qp)
            except KeyError:
                try:
                    return_to = self.generate_return_url(
                        self.return_to, _qp, kwargs["path"])
                except KeyError:
                    return_to = self.generate_return_url(self.return_to, _qp)

            return Redirect(return_to, headers=headers), True
Exemplo n.º 21
0
    def authz_part2(self, user, areq, sid, **kwargs):
        """
        After the authentication this is where you should end up

        :param user:
        :param areq: The Authorization Request
        :param sid: Session key
        :param kwargs: possible other parameters
        :return: A redirect to the redirect_uri of the client
        """
        result = self._complete_authz(user, areq, sid, **kwargs)
        if isinstance(result, Response):
            return result
        else:
            aresp, headers, redirect_uri, fragment_enc = result

        # Just do whatever is the default
        location = aresp.request(redirect_uri, fragment_enc)
        logger.debug("Redirected to: '%s' (%s)" % (location, type(location)))
        return Redirect(str(location), headers=headers)
Exemplo n.º 22
0
def login_shi():
    session["state"] = rndstr()
    session["nonce"] = rndstr()
    claims_request = ClaimsRequest(
        userinfo=Claims(
            uiucedu_uin={"essential": True}
        )
    )
    args = {
        "client_id": client.client_id,
        "response_type": "code",
        "scope": Config.SCOPES,
        "claims": claims_request,
        "nonce": session["nonce"],
        "redirect_uri": client.registration_response["redirect_uris"][0],
        "state": session["state"]
    }
    auth_req = client.construct_AuthorizationRequest(request_args=args)
    login_url = auth_req.request(client.authorization_endpoint)
    return Redirect(login_url)
Exemplo n.º 23
0
 def authn_redirect(self, uid, cookie):
     """
     Creates the URL the SP should redirect to after a successful authentication.
     This is generally the clients request to the authorization endpoint at the OP.
     :param uid: Unique user identification a.k.a sub.
     :param cookie: Cookie string sent from the server. Same as environ["HTTP-COOKIE"]
     :return: A redirect URL.
     """
     return_to = self.generateReturnUrl(self.return_to, uid)
     #Retrieve the query parameters saved by the method __call__ below.
     sp_cookie, _ts, _typ = self.getCookieValue(cookie,
                                                self.CONST_SP_COOKIE)
     data = json.loads(sp_cookie)
     if '?' in return_to:
         return_to += "&"
     else:
         return_to += "?"
     return_to += base64.b64decode(data[self.CONST_QUERY])
     #Creates the cookie that the op server needs for authentication.
     return Redirect(return_to, headers=[self.create_cookie(uid, "spm")])
Exemplo n.º 24
0
    def verify(self, request, **kwargs):
        """
        Verifies that the given username and password was correct
        :param request: Either the query part of a URL a urlencoded
        body of a HTTP message or a parse such.
        :param kwargs: Catch whatever else is sent.
        :return: redirect back to where ever the base applications
        wants the user after authentication.
        """

        logger.debug("verify(%s)" % request)
        if isinstance(request, six.string_types):
            _dict = parse_qs(request)
        elif isinstance(request, dict):
            _dict = request
        else:
            raise ValueError("Wrong type of input")

        logger.debug("dict: %s" % _dict)
        logger.debug("passwd: %s" % self.passwd)
        # verify username and password
        try:
            assert _dict['login_parameter'][0] == 'logged_in'
        except (AssertionError, KeyError):
            resp = Unauthorized(
                "You are not authorized. Javascript not executed")
            return resp, False
        else:
            cookie = self.create_cookie("diana", "upm")
            try:
                _qp = _dict["query"][0]
            except KeyError:
                _qp = self.get_multi_auth_cookie(kwargs['cookie'])
            try:
                return_to = self.generate_return_url(kwargs["return_to"], _qp)
            except KeyError:
                return_to = self.generate_return_url(self.return_to, _qp)
            resp = Redirect(return_to, headers=[cookie])

        return resp, True
Exemplo n.º 25
0
    def run(self):
        _client = self.conv.entity

        if 'add_state' in self.op_args:
            _state = rndstr(32)
            _client.logout_state2state[_state] = self.req_args['state']
            self.op_args['state'] = self.req_args['state']
            self.conv.end_session_state = _state
            self.req_args['state'] = _state

        logger.debug('req_args {}'.format(self.req_args))
        logger.debug('op_args {}'.format(self.op_args))

        url, body, ht_args, csi = _client.request_info(
            self.request,
            method=self.method,
            request_args=self.req_args,
            lax=True,
            **self.op_args)

        if 'remove_id_token_hint' in self.op_args:
            try:
                del csi['id_token_hint']
            except KeyError:
                pass
            head, tail = url.split('?')
            _qs = parse_qs(tail)
            try:
                del _qs['id_token_hint']
            except KeyError:
                pass
            _qs = {k: v[0] for k, v in _qs.items()}
            url = '{}?{}'.format(head, urlencode(_qs))

        self.csi = csi

        self.conv.events.store(EV_REDIRECT_URL,
                               url,
                               sender=self.__class__.__name__)
        return Redirect(str(url))
Exemplo n.º 26
0
def login():
    session['state'] = rndstr()
    session['nonce'] = rndstr()

    # setup claim request
    claims_request = ClaimsRequest(
         userinfo = Claims(uiucedu_uin={"essential": True})
    )
    args = {
         "client_id": client.client_id,
         "response_type": "code",
         "scope": app.config["SCOPES"],
         "nonce": session["nonce"],
         "redirect_uri": app.config["REDIRECT_URIS"][0],
         "state": session["state"],
         "claims": claims_request
    }

    auth_req = client.construct_AuthorizationRequest(request_args=args)
    login_url = auth_req.request(client.authorization_endpoint)

    return Redirect(login_url)
Exemplo n.º 27
0
    def create_redirect(self, query):
        """
        Performs the redirect to the CAS server.

        :rtype : Response
        :param query: All query parameters to be added to the return_to URL
        after successful authentication.
        :return: A redirect response to the CAS server.
        """
        try:
            req = urlparse.parse_qs(query)
            acr = req['acr_values'][0]
        except KeyError:
            acr = None

        nonce = uuid.uuid4().get_urn()
        service_url = urlparse.urlencode(
            {self.CONST_SERVICE: self.get_service_url(nonce, acr)})
        cas_url = self.cas_server + self.CONST_CASLOGIN + service_url
        cookie = self.create_cookie(
            '{"' + self.CONST_NONCE + '": "' + base64.b64encode(nonce) +
            '", "' + self.CONST_QUERY + '": "' + base64.b64encode(query) +
            '"}', self.CONST_CAS_COOKIE, self.CONST_CAS_COOKIE)
        return Redirect(cas_url, headers=[cookie])
Exemplo n.º 28
0
                    if not allowed:
                        return Unauthorized(self.not_authorized)

        #logger.info("parsed OK")'
        uid = response.assertion.subject.name_id.text
        self.setup_userdb(uid, response.ava)

        return_to = create_return_url(self.return_to, uid, **{self.query_param: "true"})
        if '?' in return_to:
            return_to += "&"
        else:
            return_to += "?"
        return_to += base64.b64decode(data[self.CONST_QUERY])

        auth_cookie = self.create_cookie(uid, "samlm")
        resp = Redirect(return_to, headers=[auth_cookie])
        return resp

    def setup_userdb(self, uid, samldata):
        attributes = {}
        if self.sp_conf.ATTRIBUTE_WHITELIST is not None:
            for attr, allowed in self.sp_conf.ATTRIBUTE_WHITELIST.iteritems():
                if attr in samldata:
                    if allowed is not None:
                        tmp_attr_list = []
                        for tmp_value in samldata[attr]:
                            for allowed_str in allowed:
                                if allowed_str in tmp_value:
                                    tmp_attr_list.append(tmp_value)
                        if len(tmp_attr_list) > 0:
                            attributes[attr] = tmp_attr_list
Exemplo n.º 29
0
def application(environ, start_response):
    session = environ['beaker.session']

    path = environ.get('PATH_INFO', '').lstrip('/')
    if path == "robots.txt":
        return static(environ, start_response, LOGGER, "static/robots.txt")

    if path.startswith("static/"):
        return static(environ, start_response, LOGGER, path)

    query = parse_qs(environ["QUERY_STRING"])

    if path == "rp":  # After having chosen which OP to authenticate at
        if "uid" in query:
            client = CLIENTS.dynamic_client(query["uid"][0])
            session["op"] = client.provider_info["issuer"]
        else:
            client = CLIENTS[query["op"][0]]
            session["op"] = query["op"][0]

        try:
            resp = client.create_authn_request(session)
        except Exception:
            raise
        else:
            return resp(environ, start_response)
    elif path == "authz_cb":  # After having authenticated at the OP
        client = CLIENTS[session["op"]]
        try:
            userinfo = client.callback(query)
        except OIDCError as err:
            return operror(environ, start_response, "%s" % err)
        except Exception:
            raise
        else:
            return opresult(environ, start_response, userinfo)
    elif path == "logout":  # After the user has pressed the logout button
        client = CLIENTS[session["op"]]
        logout_url = client.endsession_endpoint
        try:
            # Specify to which URL the OP should return the user after
            # log out. That URL must be registered with the OP at client
            # registration.
            logout_url += "?" + urllib.urlencode({
                "post_logout_redirect_uri":
                client.registration_response["post_logout_redirect_uris"][0]
            })
        except KeyError:
            pass
        else:
            # If there is an ID token send it along as a id_token_hint
            _idtoken = get_id_token(client, session)
            if _idtoken:
                logout_url += "&" + urllib.urlencode({
                    "id_token_hint":
                    id_token_as_signed_jwt(client, _idtoken, "HS256")
                })

        clear_session(session)
        resp = Redirect(str(logout_url))
        return resp(environ, start_response)

    return opchoice(environ, start_response, CLIENTS)
Exemplo n.º 30
0
def auth_callback():
    """
    Auth callback: authenticate the user and get an access token
    """
    login_hint_token = request.args.get('login_hint_token')
    error = request.args.get('error')
    state = request.args.get('state')
    code = request.args.get('code')
    current_user = get_current_user(session)
    redirect_uri = url_for('auth_callback',
                           _external=True,
                           _scheme=('http' if IS_LOCAL else 'https'))

    zenkey_oidc_service = ZenKeyOIDCService(CLIENT_ID, CLIENT_SECRET,
                                            redirect_uri, session_service)
    auth_flow_handler = AuthorizationFlowHandler(session)

    # handle errors returned from ZenKey
    if error is not None:
        # if an error happens, delete the auth information saved in the session
        auth_flow_handler.delete_authorization_details()
        session_service.clear()
        raise Exception(error)

    # check if the user is already logged in
    if current_user is not None and not auth_flow_handler.authorization_in_progress(
    ):
        return redirect('/')

    # use a cached MCCMNC if needed
    mccmnc = request.args.get('mccmnc', session_service.get_mccmnc())

    # If we have no mccmnc, begin the carrier discovery process
    if mccmnc is None:
        return redirect('/auth')

    if state is None:
        # if an error happens, delete the auth information saved in the session
        auth_flow_handler.delete_authorization_details()
        raise Exception('missing state')

    # build our OpenID client
    openid_client = Client(client_authn_method=CLIENT_AUTHN_METHOD,
                           client_id=CLIENT_ID)
    # save the client information to the OIDC client
    client_registration_info = RegistrationResponse(
        **{
            "client_id": CLIENT_ID,
            "client_secret": CLIENT_SECRET
        })
    openid_client.store_registration_info(client_registration_info)
    # discover the carrier OIDC endpoint configuration
    oidc_configuration = zenkey_oidc_service.discover_oidc_provider_metadata(
        mccmnc)
    # save the provider config to the OIDC client after we've discovered it
    provider_configuration = ProviderConfigurationResponse(
        **oidc_configuration)
    openid_client.handle_provider_config(provider_configuration,
                                         provider_configuration['issuer'],
                                         True, True)

    if code is None:
        # Request an auth code
        # The carrier discovery endpoint has redirected back to our app with the mccmnc.
        # Now we can start the authorize flow by requesting an auth code.
        # Send the user to the ZenKey authorization endpoint. After authorization, this endpoint
        # will redirect back to our app with an auth code.

        if auth_flow_handler.authorization_in_progress():
            # authorization is in progress
            auth_kwargs = {
                # only openid scope is needed for this auth request
                'scope': ['openid'],
                # add the context and acr value to the auth request
                'context':
                auth_flow_handler.get_authorization_details().get('context'),
                'acr_values':
                'a3'
            }
        else:
            # no authorization in progress: do a standard login authorization
            auth_kwargs = {'scope': SCOPE}

        authorization_url = zenkey_oidc_service.get_auth_code_request_url(
            openid_client, login_hint_token, state, mccmnc, **auth_kwargs)
        return Redirect(authorization_url)

    if code:
        # Token exchange:
        # Now that the Auth redirect has returned to our app with an auth code, we can
        # do the token exchange.
        # Exchange the auth code for a token and then call the userinfo endpoint.

        token_response = zenkey_oidc_service.request_token(
            openid_client, request.environ['QUERY_STRING'])

        # if auth in progress, do the auth thing
        # otherwise do the userinfo call and login
        if auth_flow_handler.authorization_in_progress():
            return auth_flow_handler.success_router(token_response)

        # fetch the userinfo from the API
        userinfo = zenkey_oidc_service.get_userinfo(
            openid_client, token_response["access_token"])

        # this is where a real app might look up the user in the database using the "sub" value
        # we could also create a new user or show a registration form
        # the userinfo object contains values like sub, name, and email (depending on which
        # scopes were requested)
        # these values can be saved for the user or used to auto-populate a registration form

        # save the userinfo in the session and return to the homepage: now the user is logged in
        session['userinfo'] = json.dumps(userinfo.to_dict())
        return redirect('/')

    # If we have no mccmnc, begin the carrier discovery process
    return redirect('/auth')