Example #1
0
    def test_query_acct_host_forced(self):
        wf = WebFinger(OIC_ISSUER)
        query = wf.query("http://example.com/carol", host='forced.co')

        assert query == "https://forced.co/.well-known/webfinger?resource" \
                        "=http%3A%2F%2Fexample.com%2Fcarol&rel=http%3A%2F%2Fopenid" \
                        ".net%2Fspecs%2Fconnect%2F1.0%2Fissuer"
Example #2
0
    def test_query_acct(self):
        wf = WebFinger(OIC_ISSUER)
        query = wf.query("acct:[email protected]")

        assert query == "https://example.com/.well-known/webfinger?resource" \
                        "=acct%3Acarol%40example.com&rel=http%3A%2F%2Fopenid" \
                        ".net%2Fspecs%2Fconnect%2F1.0%2Fissuer"
Example #3
0
 def test_query_rel(self):
     wf = WebFinger()
     query = wf.query("acct:[email protected]",
                      ["http://webfinger.net/rel/profile-page", "vcard"])
     assert query == "https://example.com/.well-known/webfinger?resource" \
                     "=acct%3Abob%40example.com&rel=http%3A%2F%2Fwebfinger" \
                     ".net%2Frel%2Fprofile-page&rel=vcard"
Example #4
0
 def discover(self, *arg, **kwargs):
     wf = WebFinger(OIC_ISSUER)
     wf.httpd = PBase()
     _url = wf.query(kwargs["principal"])
     self.trace.request("URL: %s" % _url)
     url = wf.discovery_query(kwargs["principal"])
     return url
Example #5
0
 def discover(self, *arg, **kwargs):
     wf = WebFinger(OIC_ISSUER)
     wf.httpd = PBase()
     _url = wf.query(kwargs["principal"])
     self.trace.request("URL: %s" % _url)
     url = wf.discovery_query(kwargs["principal"])
     return url
Example #6
0
def webfinger(environ, events):
    query = parse_qs(environ["QUERY_STRING"])
    _op = environ["oic.op"]

    try:
        if query["rel"] != [OIC_ISSUER]:
            events.store(
                EV_CONDITION,
                State('webfinger_parameters',
                      ERROR,
                      message='parameter rel wrong value: {}'.format(
                          query['rel'])))
            return BadRequest('Parameter value error')
        else:
            resource = query["resource"][0]
    except KeyError as err:
        events.store(
            EV_CONDITION,
            State('webfinger_parameters',
                  ERROR,
                  message='parameter {} missing'.format(err)))
        resp = BadRequest("Missing parameter in request")
    else:
        wf = WebFinger()
        resp = Response(wf.response(subject=resource, base=_op.baseurl))
    return resp
Example #7
0
 def __init__(self, name=""):
     Server.__init__(self)
     self.sdb = SessionDB()
     self.name = name
     self.client = {}
     self.registration_expires_in = 3600
     self.host = ""
     self.webfinger = WebFinger()
Example #8
0
 def setup_webfinger_endpoint(self):
     wf = WebFinger()
     resp = Response(wf.response(subject=self.op_base, base=self.op_base))
     responses.add(responses.GET,
                   self.op_base + ".well-known/webfinger",
                   body=resp.message,
                   status=200,
                   content_type='application/json')
Example #9
0
 def setup_webfinger_endpoint(self):
     wf = WebFinger()
     resp = Response(wf.response(subject=self.op_base, base=self.op_base))
     responses.add(responses.GET,
                   self.op_base + ".well-known/webfinger",
                   body=resp.message,
                   status=200,
                   content_type='application/json')
Example #10
0
    def dynamic_client(self, issuer="", userid=""):
        client = self.client_cls(
            client_authn_method=CLIENT_AUTHN_METHOD,
            verify_ssl=self.verify_ssl,
            **self.jwks_info
        )
        if userid:
            try:
                issuer = client.wf.discovery_query(userid)
            except AttributeError:
                wf = WebFinger(httpd=client)
                issuer = wf.discovery_query(userid)

        if not issuer:
            raise OAuth2Error("Missing issuer")

        logger.info("issuer: {}".format(issuer))

        if issuer in self.client:
            return self.client[issuer]
        else:
            # Gather OP information
            _pcr = client.provider_config(issuer)
            logger.info("Provider info: {}".format(sanitize(_pcr.to_dict())))
            issuer = _pcr["issuer"]  # So no hickup later about trailing '/'
            # register the client
            _cinfo = self.config.CLIENTS[""]["client_info"]
            reg_args = copy.copy(_cinfo)
            h = hashlib.sha256(self.seed)
            h.update(issuer.encode("utf8"))  # issuer has to be bytes
            base_urls = _cinfo["redirect_uris"]

            reg_args["redirect_uris"] = [
                u.format(base=self.base_url, iss=h.hexdigest()) for u in base_urls
            ]
            try:
                reg_args["post_logout_redirect_uris"] = [
                    u.format(base=self.base_url, iss=h.hexdigest())
                    for u in reg_args["post_logout_redirect_uris"]
                ]
            except KeyError:
                pass

            self.get_path(reg_args["redirect_uris"], issuer)
            if client.jwks_uri:
                reg_args["jwks_uri"] = client.jwks_uri

            rr = client.register(_pcr["registration_endpoint"], **reg_args)
            msg = "Registration response: {}"
            logger.info(msg.format(sanitize(rr.to_dict())))

            try:
                client.behaviour.update(**self.config.CLIENTS[""]["behaviour"])
            except KeyError:
                pass

            self.client[issuer] = client
            return client
Example #11
0
    def test_extra_member_response(self):
        wf = WebFinger()
        resp = wf.response('acct:local@domain', 'https://example.com',
                           dummy='foo')

        # resp should be a JSON document

        _resp = json.loads(resp)
        assert _resp['dummy'] == 'foo'
Example #12
0
 def __init__(self, name="", session_db_factory=None):
     Server.__init__(self)
     self.sdb = session_db_factory(name)
     self.name = name
     self.client = {}  # type: Dict[str, Dict[str, Any]]
     self.registration_expires_in = 3600
     self.host = ""
     self.webfinger = WebFinger()
     self.userinfo_signed_response_alg = ""
Example #13
0
def _webfinger(provider, request, **kwargs):
    """Handle webfinger requests."""
    params = urlparse.parse_qs(request)
    if params["rel"][0] == OIC_ISSUER:
        wf = WebFinger()
        return Response(wf.response(params["resource"][0], provider.baseurl),
                        headers=[("Content-Type", "application/jrd+json")])
    else:
        return BadRequest("Incorrect webfinger.")
Example #14
0
def _webfinger(provider, request, **kwargs):
    """Handle webfinger requests."""
    params = urlparse.parse_qs(request)
    if params["rel"][0] == OIC_ISSUER:
        wf = WebFinger()
        return Response(wf.response(params["resource"][0], provider.baseurl),
                        headers=[("Content-Type", "application/jrd+json")])
    else:
        return BadRequest("Incorrect webfinger.")
Example #15
0
 def __init__(self, name=""):
     Server.__init__(self)
     self.sdb = SessionDB(name)
     self.name = name
     self.client = {}
     self.registration_expires_in = 3600
     self.host = ""
     self.webfinger = WebFinger()
     self.userinfo_signed_response_alg = ""
Example #16
0
    def dynamic_client(self, issuer='', userid=''):
        client = self.client_cls(client_authn_method=CLIENT_AUTHN_METHOD,
                                 verify_ssl=self.verify_ssl,
                                 **self.jwks_info)
        if userid:
            try:
                issuer = client.wf.discovery_query(userid)
            except AttributeError:
                wf = WebFinger(httpd=client)
                issuer = wf.discovery_query(userid)

        if not issuer:
            raise OAuth2Error('Missing issuer')

        logger.info('issuer: {}'.format(issuer))

        if issuer in self.client:
            return self.client[issuer]
        else:
            # Gather OP information
            _pcr = client.provider_config(issuer)
            logger.info('Provider info: {}'.format(sanitize(_pcr.to_dict())))
            issuer = _pcr['issuer']  # So no hickup later about trailing '/'
            # register the client
            _cinfo = self.config.CLIENTS[""]["client_info"]
            reg_args = copy.copy(_cinfo)
            h = hashlib.sha256(self.seed)
            h.update(issuer.encode('utf8'))  # issuer has to be bytes
            base_urls = _cinfo["redirect_uris"]

            reg_args['redirect_uris'] = [
                u.format(base=self.base_url, iss=h.hexdigest())
                for u in base_urls]
            try:
                reg_args['post_logout_redirect_uris'] = [
                    u.format(base=self.base_url, iss=h.hexdigest())
                    for u in reg_args['post_logout_redirect_uris']
                    ]
            except KeyError:
                pass

            self.get_path(reg_args['redirect_uris'], issuer)
            if client.jwks_uri:
                reg_args['jwks_uri'] = client.jwks_uri

            rr = client.register(_pcr["registration_endpoint"], **reg_args)
            msg = 'Registration response: {}'
            logger.info(msg.format(sanitize(rr.to_dict())))

            try:
                client.behaviour.update(**self.config.CLIENTS[""]["behaviour"])
            except KeyError:
                pass

            self.client[issuer] = client
            return client
Example #17
0
    def test_extra_member_response(self):
        wf = WebFinger()
        resp = wf.response("acct:local@domain",
                           "https://example.com",
                           dummy="foo")

        # resp should be a JSON document

        _resp = json.loads(resp)
        assert _resp["dummy"] == "foo"
Example #18
0
def test_wf4():
    wf = WebFinger()
    jrd0 = wf.load(json.dumps(EX0))

    print jrd0

    for link in jrd0["links"]:
        if link["rel"] == "blog":
            print link["href"]
            assert link["href"] == "http://blogs.example.com/bob/"
Example #19
0
def test_wf4():
    wf = WebFinger()
    jrd0 = wf.load(json.dumps(EX0))

    print jrd0

    for link in jrd0["links"]:
        if link["rel"] == "blog":
            print link["href"]
            assert link["href"] == "http://blogs.example.com/bob/"
Example #20
0
    def get(self):
        params = self.request.query_arguments

        if params['rel'][0].decode('utf-8') == OIC_ISSUER:
            wf = WebFinger()
            self.write(
                wf.response(params["resource"][0].decode('utf-8'),
                            self.settings['oidc_provider'].baseurl))
        else:
            return self.send_error()
 def _webfinger(self):
     query = request.args
     try:
         assert query["rel"] == OIC_ISSUER
         resource = query["resource"][0]
     except KeyError:
         resp = BadRequest("Missing parameter in request")
     else:
         wf = WebFinger()
         resp = Response(wf.response(subject=resource, base=self.provider.baseurl))
     return resp
Example #22
0
def webfinger(environ, start_response, _):
    query = parse_qs(environ["QUERY_STRING"])
    try:
        assert query["rel"] == [OIC_ISSUER]
        resource = query["resource"][0]
    except KeyError:
        resp = BadRequest("Missing parameter in request")
    else:
        wf = WebFinger()
        resp = Response(wf.response(subject=resource, base=OAS.baseurl))
    return resp(environ, start_response)
Example #23
0
 def test_query_rel_host_forced(self):
     wf = WebFinger()
     query = wf.query(
         "acct:[email protected]",
         ["http://webfinger.net/rel/profile-page", "vcard"],
         host="forced.com:3000",
     )
     assert (
         query == "https://forced.com:3000/.well-known/webfinger?resource"
         "=acct%3Abob%40example.com&rel=http%3A%2F%2Fwebfinger"
         ".net%2Frel%2Fprofile-page&rel=vcard")
Example #24
0
File: as.py Project: dv10den/pyuma
def webfinger(environ):
    query = parse_qs(environ["QUERY_STRING"])
    try:
        assert query["rel"] == [OIC_ISSUER]
        resource = query["resource"][0]
    except KeyError:
        resp = BadRequest("Missing parameter in request")
    else:
        wf = WebFinger()
        resp = Response(wf.response(subject=resource, base=AUTHZSRV.baseurl))
    return resp
Example #25
0
    def find_srv_discovery_url(self, resource):
        """
        Use Webfinger to find the OP, The input is a unique identifier
        of the user. Allowed forms are the acct, mail, http and https
        urls. If no protocol specification is given like if only an
        email like identifier is given. It will be translated if possible to
        one of the allowed formats.

        :param resource: unique identifier of the user.
        :return:
        """

        wf = WebFinger(httpd=PBase(ca_certs=self.extra["ca_bundle"]))
        return wf.discovery_query(resource)
Example #26
0
    def find_srv_discovery_url(self, resource):
        """
        Use Webfinger to find the OP, The input is a unique identifier
        of the user. Allowed forms are the acct, mail, http and https
        urls. If no protocol specification is given like if only an
        email like identifier is given. It will be translated if possible to
        one of the allowed formats.

        :param resource: unique identifier of the user.
        :return:
        """

        wf = WebFinger(httpd=PBase(ca_certs=self.extra["ca_bundle"]))
        return wf.discovery_query(resource)
Example #27
0
 def webfinger(self, environ, start_response):
     query = parse_qs(environ["QUERY_STRING"])
     try:
         rel = query["rel"]
         resource = query["resource"][0]
     except KeyError:
         resp = BadRequest("Missing parameter in request")
     else:
         if rel != [OIC_ISSUER]:
             resp = BadRequest("Bad issuer in request")
         else:
             wf = WebFinger()
             resp = Response(
                 wf.response(subject=resource, base=self.oas.baseurl))
     return resp(environ, start_response)
Example #28
0
    def __init__(self,
                 client_id=None,
                 ca_certs=None,
                 client_prefs=None,
                 client_authn_method=None,
                 keyjar=None,
                 verify_ssl=True):

        oauth2.Client.__init__(self,
                               client_id,
                               ca_certs,
                               client_authn_method=client_authn_method,
                               keyjar=keyjar,
                               verify_ssl=verify_ssl)

        self.file_store = "./file/"
        self.file_uri = "http://localhost/"

        # OpenID connect specific endpoints
        for endpoint in ENDPOINTS:
            setattr(self, endpoint, "")

        self.id_token = None
        self.log = None

        self.request2endpoint = REQUEST2ENDPOINT
        self.response2error = RESPONSE2ERROR

        self.grant_class = Grant
        self.token_class = Token
        self.provider_info = None
        self.registration_response = None
        self.client_prefs = client_prefs or {}

        self.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }

        self.wf = WebFinger(OIC_ISSUER)
        self.wf.httpd = self
        self.allow = {}
        self.post_logout_redirect_uris = []
        self.registration_expires = 0
        self.registration_access_token = None

        # Default key by kid for different key types
        # For instance {"RSA":"abc"}
        self.kid = {"sig": {}, "enc": {}}
Example #29
0
    def __init__(self, client_id=None, ca_certs=None, grant_expire_in=600,
                 jwt_keys=None, client_timeout=0, client_prefs=None):

        oauth2.Client.__init__(self, client_id, ca_certs, grant_expire_in,
                               client_timeout=client_timeout,
                               jwt_keys=jwt_keys)

        self.file_store = "./file/"
        self.file_uri = "http://localhost/"

        # OpenID connect specific endpoints
        for endpoint in ENDPOINTS:
            setattr(self, endpoint, "")

        self.id_token = None
        self.log = None

        self.request2endpoint = REQUEST2ENDPOINT
        self.response2error = RESPONSE2ERROR
        self.grant_class = Grant
        self.token_class = Token
        self.authn_method = AUTHN_METHOD
        self.provider_info = {}
        self.client_prefs = client_prefs or {}
        self.behaviour = {"require_signed_request_object":
                          DEF_SIGN_ALG["openid_request_object"]}

        self.wf = WebFinger(OIC_ISSUER)
        self.wf.httpd = self
Example #30
0
    def __init__(self, client_id=None, ca_certs=None,
                 client_prefs=None, client_authn_method=None, keyjar=None):

        oauth2.Client.__init__(self, client_id, ca_certs,
                               client_authn_method=client_authn_method,
                               keyjar=keyjar)

        self.file_store = "./file/"
        self.file_uri = "http://localhost/"

        # OpenID connect specific endpoints
        for endpoint in ENDPOINTS:
            setattr(self, endpoint, "")

        self.id_token = None
        self.log = None

        self.request2endpoint = REQUEST2ENDPOINT
        self.response2error = RESPONSE2ERROR
        self.grant_class = Grant
        self.token_class = Token
        self.provider_info = {}
        self.client_prefs = client_prefs or {}
        self.behaviour = {"require_signed_request_object":
                          DEF_SIGN_ALG["openid_request_object"]}

        self.wf = WebFinger(OIC_ISSUER)
        self.wf.httpd = self
        self.allow = {}
        self.post_logout_redirect_uris = []
Example #31
0
def webfinger(environ, start_response, session_info, trace, **kwargs):
    query = parse_qs(environ["QUERY_STRING"])

    # Find the identifier
    session_info["test_id"] = find_identifier(query["resource"][0])

    trace.info(HEADER % "WebFinger")
    trace.request(environ["QUERY_STRING"])
    trace.info("QUERY: %s" % (query,))

    try:
        assert query["rel"] == [OIC_ISSUER]
        resource = query["resource"][0]
    except AssertionError:
        errmsg = "Wrong 'rel' value: %s" % query["rel"][0]
        trace.error(errmsg)
        resp = BadRequest(errmsg)
    except KeyError:
        errmsg = "Missing 'rel' parameter in request"
        trace.error(errmsg)
        resp = BadRequest(errmsg)
    else:
        wf = WebFinger()
        p = urlparse(resource)

        if p.scheme == "acct":
            l, _ = p.path.split("@")
            path = pathmap.IDMAP[l.lower()]
        else:  # scheme == http/-s
            try:
                path = pathmap.IDMAP[p.path[1:].lower()]
            except KeyError:
                path = None

        if path:
            _url = os.path.join(kwargs["op_arg"]["baseurl"],
                                session_info["test_id"],
                                path[1:])
            resp = Response(wf.response(subject=resource, base=_url),
                            content="application/jrd+json")
        else:
            resp = BadRequest("Incorrect resource specification")

        trace.reply(resp.message)

    dump_log(session_info, trace)
    return resp(environ, start_response)
Example #32
0
def webfinger(environ, start_response, session_info, trace, **kwargs):
    query = parse_qs(environ["QUERY_STRING"])

    # Find the identifier
    session_info["test_id"] = find_identifier(query["resource"][0])

    trace.info(HEADER % "WebFinger")
    trace.request(environ["QUERY_STRING"])
    trace.info("QUERY: %s" % (query, ))

    try:
        assert query["rel"] == [OIC_ISSUER]
        resource = query["resource"][0]
    except AssertionError:
        errmsg = "Wrong 'rel' value: %s" % query["rel"][0]
        trace.error(errmsg)
        resp = BadRequest(errmsg)
    except KeyError:
        errmsg = "Missing 'rel' parameter in request"
        trace.error(errmsg)
        resp = BadRequest(errmsg)
    else:
        wf = WebFinger()
        p = urlparse(resource)

        if p.scheme == "acct":
            l, _ = p.path.split("@")
            path = pathmap.IDMAP[l.lower()]
        else:  # scheme == http/-s
            try:
                path = pathmap.IDMAP[p.path[1:].lower()]
            except KeyError:
                path = None

        if path:
            _url = os.path.join(kwargs["op_arg"]["baseurl"],
                                session_info["test_id"], path[1:])
            resp = Response(wf.response(subject=resource, base=_url),
                            content="application/jrd+json")
        else:
            resp = BadRequest("Incorrect resource specification")

        trace.reply(resp.message)

    dump_log(session_info, trace)
    return resp(environ, start_response)
Example #33
0
 def __init__(self, name=""):
     Server.__init__(self)
     self.sdb = SessionDB()
     self.name = name
     self.client = {}
     self.registration_expires_in = 3600
     self.host = ""
     self.webfinger = WebFinger()
Example #34
0
 def __init__(self, name=""):
     Server.__init__(self)
     self.sdb = SessionDB(name)
     self.name = name
     self.client = {}
     self.registration_expires_in = 3600
     self.host = ""
     self.webfinger = WebFinger()
     self.userinfo_signed_response_alg = ""
Example #35
0
    def test_wf4(self):
        EX0 = {
            "expires": "2012-11-16T19:41:35Z",
            "subject": "acct:[email protected]",
            "aliases": [
                "http://www.example.com/~bob/"
            ],
            "properties": {
                "http://example.com/ns/role/": "employee"
            },
            "links": [
                {
                    "rel": "http://webfinger.net/rel/avatar",
                    "type": "image/jpeg",
                    "href": "http://www.example.com/~bob/bob.jpg"
                },
                {
                    "rel": "http://webfinger.net/rel/profile-page",
                    "href": "http://www.example.com/~bob/"
                },
                {
                    "rel": "blog",
                    "type": "text/html",
                    "href": "http://blogs.example.com/bob/",
                    "titles": {
                        "en-us": "The Magical World of Bob",
                        "fr": "Le monde magique de Bob"
                    }
                },
                {
                    "rel": "vcard",
                    "href": "https://www.example.com/~bob/bob.vcf"
                }
            ]
        }

        wf = WebFinger()
        jrd0 = wf.load(json.dumps(EX0))

        for link in jrd0["links"]:
            if link["rel"] == "blog":
                assert link["href"] == "http://blogs.example.com/bob/"
                break
Example #36
0
    def test_wf4(self):
        EX0 = {
            "expires": "2012-11-16T19:41:35Z",
            "subject": "acct:[email protected]",
            "aliases": [
                "http://www.example.com/~bob/"
            ],
            "properties": {
                "http://example.com/ns/role/": "employee"
            },
            "links": [
                {
                    "rel": "http://webfinger.net/rel/avatar",
                    "type": "image/jpeg",
                    "href": "http://www.example.com/~bob/bob.jpg"
                },
                {
                    "rel": "http://webfinger.net/rel/profile-page",
                    "href": "http://www.example.com/~bob/"
                },
                {
                    "rel": "blog",
                    "type": "text/html",
                    "href": "http://blogs.example.com/bob/",
                    "titles": {
                        "en-us": "The Magical World of Bob",
                        "fr": "Le monde magique de Bob"
                    }
                },
                {
                    "rel": "vcard",
                    "href": "https://www.example.com/~bob/bob.vcf"
                }
            ]
        }

        wf = WebFinger()
        jrd0 = wf.load(json.dumps(EX0))

        for link in jrd0["links"]:
            if link["rel"] == "blog":
                assert link["href"] == "http://blogs.example.com/bob/"
                break
Example #37
0
def webfinger(environ, start_response, session_info, events, jlog, **kwargs):
    _query = session_info['parameters']
    events.store(EV_REQUEST, Operation("WebFinger", _query))

    try:
        assert _query["rel"] == [OIC_ISSUER]
        resource = _query["resource"][0]
    except AssertionError:
        errmsg = "Wrong 'rel' value: %s" % _query["rel"][0]
        events.store(EV_FAULT, errmsg)
        resp = BadRequest(errmsg)
    except KeyError:
        errmsg = "Missing 'rel' parameter in request"
        events.store(EV_FAULT, errmsg)
        resp = BadRequest(errmsg)
    else:
        wf = WebFinger()

        _url = os.path.join(kwargs["op_arg"]["baseurl"],
                            session_info['oper_id'],
                            session_info["test_id"])

        _mesg = wf.response(subject=resource, base=_url)
        if session_info['test_id'] == 'rp-discovery-webfinger-http-href':
            _msg = json.loads(_mesg)
            _msg['links'][0]['href'] = _msg['links'][0]['href'].replace(
                'https', 'http')
            _mesg = json.dumps(_msg)
        elif session_info['test_id'] == 'rp-discovery-webfinger-unknown-member':
            _msg = json.loads(_mesg)
            _msg['dummy'] = 'foobar'
            _mesg = json.dumps(_msg)

        resp = Response(_mesg,
                        content="application/jrd+json")

        events.store(EV_RESPONSE, resp.message)

    jlog.info(resp2json(resp))

    dump_log(session_info, events)
    return resp(environ, start_response)
Example #38
0
def webfinger(environ, start_response, session_info, events, jlog, **kwargs):
    _query = session_info['parameters']
    events.store(EV_REQUEST, Operation("WebFinger", _query))

    try:
        assert _query["rel"] == [OIC_ISSUER]
        resource = _query["resource"][0]
    except AssertionError:
        errmsg = "Wrong 'rel' value: %s" % _query["rel"][0]
        events.store(EV_FAULT, errmsg)
        resp = BadRequest(errmsg)
    except KeyError:
        errmsg = "Missing 'rel' parameter in request"
        events.store(EV_FAULT, errmsg)
        resp = BadRequest(errmsg)
    else:
        wf = WebFinger()

        _url = os.path.join(kwargs["op_arg"]["baseurl"],
                            session_info['oper_id'], session_info["test_id"])

        _mesg = wf.response(subject=resource, base=_url)
        if session_info['test_id'] == 'rp-discovery-webfinger-http-href':
            _msg = json.loads(_mesg)
            _msg['links'][0]['href'] = _msg['links'][0]['href'].replace(
                'https', 'http')
            _mesg = json.dumps(_msg)
        elif session_info[
                'test_id'] == 'rp-discovery-webfinger-unknown-member':
            _msg = json.loads(_mesg)
            _msg['dummy'] = 'foobar'
            _mesg = json.dumps(_msg)

        resp = Response(_mesg, content="application/jrd+json")

        events.store(EV_RESPONSE, resp.message)

    jlog.info(resp2json(resp))

    dump_log(session_info, events)
    return resp(environ, start_response)
Example #39
0
def webfinger(environ, start_response, session, trace):
    query = parse_qs(environ["QUERY_STRING"])

    # Find the identifier
    session["test_id"] = find_identifier(query["resource"][0])

    trace.info(HEADER % "WebFinger")
    trace.request(environ["QUERY_STRING"])
    trace.info("QUERY: %s" % (query,))

    try:
        assert query["rel"] == [OIC_ISSUER]
        resource = query["resource"][0]
    except AssertionError:
        errmsg = "Wrong 'rel' value: %s" % query["rel"][0]
        trace.error(errmsg)
        resp = BadRequest(errmsg)
    except KeyError:
        errmsg = "Missing 'rel' parameter in request"
        trace.error(errmsg)
        resp = BadRequest(errmsg)
    else:
        wf = WebFinger()
        p = urlparse(resource)
        if p.scheme == "acct":
            l, _ = p.path.split("@")
            path = pathmap.IDMAP[l]
        else:  # scheme == http/-s
            path = pathmap.IDMAP[p.path[1:]]

        _url = os.path.join(OP_ARG["baseurl"], session["test_id"], path[1:])
        resp = Response(wf.response(subject=resource, base=_url))

        trace.reply(resp.message)

    dump_log(session, trace)
    return resp(environ, start_response)
Example #40
0
def webfinger(environ, start_response, session, trace):
    query = parse_qs(environ["QUERY_STRING"])

    # Find the identifier
    session["test_id"] = find_identifier(query["resource"][0])

    trace.info(HEADER % "WebFinger")
    trace.request(environ["QUERY_STRING"])
    trace.info("QUERY: %s" % (query,))

    try:
        assert query["rel"] == [OIC_ISSUER]
        resource = query["resource"][0]
    except AssertionError:
        errmsg = "Wrong 'rel' value: %s" % query["rel"][0]
        trace.error(errmsg)
        resp = BadRequest(errmsg)
    except KeyError:
        errmsg = "Missing 'rel' parameter in request"
        trace.error(errmsg)
        resp = BadRequest(errmsg)
    else:
        wf = WebFinger()
        p = urlparse(resource)
        if p.scheme == "acct":
            l, _ = p.path.split("@")
            path = pathmap.IDMAP[l]
        else:  # scheme == http/-s
            path = pathmap.IDMAP[p.path[1:]]

        _url = os.path.join(OP_ARG["baseurl"], session["test_id"], path[1:])
        resp = Response(wf.response(subject=resource, base=_url))

        trace.reply(resp.message)

    dump_log(session, trace)
    return resp(environ, start_response)
Example #41
0
    def __init__(self, client_id=None, ca_certs=None,
                 client_prefs=None, client_authn_method=None, keyjar=None,
                 verify_ssl=True):

        oauth2.Client.__init__(self, client_id, ca_certs,
                               client_authn_method=client_authn_method,
                               keyjar=keyjar, verify_ssl=verify_ssl)

        self.file_store = "./file/"
        self.file_uri = "http://localhost/"

        # OpenID connect specific endpoints
        for endpoint in ENDPOINTS:
            setattr(self, endpoint, "")

        self.id_token = None
        self.log = None

        self.request2endpoint = REQUEST2ENDPOINT
        self.response2error = RESPONSE2ERROR

        self.grant_class = Grant
        self.token_class = Token
        self.provider_info = None
        self.registration_response = None
        self.client_prefs = client_prefs or {}

        self.behaviour = {
            "request_object_signing_alg":
            DEF_SIGN_ALG["openid_request_object"]}

        self.wf = WebFinger(OIC_ISSUER)
        self.wf.httpd = self
        self.allow = {}
        self.post_logout_redirect_uris = []
        self.registration_expires = 0
        self.registration_access_token = None

        # Default key by kid for different key types
        # For instance {"RSA":"abc"}
        self.kid = {"sig": {}, "enc": {}}
Example #42
0
 def test_query_device_host_forced(self):
     wf = WebFinger()
     query = wf.query(resource="device:p1.example.com", host='forced.com')
     assert query == 'https://forced.com/.well-known/webfinger' \
                     '?resource=device%3Ap1.example.com'
Example #43
0
class Client(oauth2.Client):
    _endpoints = ENDPOINTS

    def __init__(
        self, client_id=None, ca_certs=None, client_prefs=None, client_authn_method=None, keyjar=None, verify_ssl=True
    ):

        oauth2.Client.__init__(
            self, client_id, ca_certs, client_authn_method=client_authn_method, keyjar=keyjar, verify_ssl=verify_ssl
        )

        self.file_store = "./file/"
        self.file_uri = "http://localhost/"

        # OpenID connect specific endpoints
        for endpoint in ENDPOINTS:
            setattr(self, endpoint, "")

        self.id_token = None
        self.log = None

        self.request2endpoint = REQUEST2ENDPOINT
        self.response2error = RESPONSE2ERROR

        self.grant_class = Grant
        self.token_class = Token
        self.provider_info = None
        self.registration_response = None
        self.client_prefs = client_prefs or {}

        self.behaviour = {}

        self.wf = WebFinger(OIC_ISSUER)
        self.wf.httpd = self
        self.allow = {}
        self.post_logout_redirect_uris = []
        self.registration_expires = 0
        self.registration_access_token = None
        self.id_token_max_age = 0

        # Default key by kid for different key types
        # For instance {"RSA":"abc"}
        self.kid = {"sig": {}, "enc": {}}

    def _get_id_token(self, **kwargs):
        try:
            return kwargs["id_token"]
        except KeyError:
            grant = self.get_grant(**kwargs)

        if grant:
            try:
                _scope = kwargs["scope"]
            except KeyError:
                _scope = None

            for token in grant.tokens:
                if token.scope and _scope:
                    flag = True
                    for item in _scope:
                        try:
                            assert item in token.scope
                        except AssertionError:
                            flag = False
                            break
                    if not flag:
                        break
                if token.id_token:
                    return token.id_token

        return None

    def request_object_encryption(self, msg, **kwargs):
        try:
            encalg = kwargs["request_object_encryption_alg"]
        except KeyError:
            try:
                encalg = self.behaviour["request_object_encryption_alg"]
            except KeyError:
                return msg

        try:
            encenc = kwargs["request_object_encryption_enc"]
        except KeyError:
            try:
                encenc = self.behaviour["request_object_encryption_enc"]
            except KeyError:
                raise MissingRequiredAttribute("No request_object_encryption_enc specified")

        _jwe = JWE(msg, alg=encalg, enc=encenc)
        _kty = jwe.alg2keytype(encalg)

        try:
            _kid = kwargs["enc_kid"]
        except KeyError:
            _kid = ""

        if "target" not in kwargs:
            raise MissingRequiredAttribute("No target specified")

        if _kid:
            _keys = self.keyjar.get_encrypt_key(_kty, owner=kwargs["target"], kid=_kid)
            _jwe["kid"] = _kid
        else:
            _keys = self.keyjar.get_encrypt_key(_kty, owner=kwargs["target"])

        return _jwe.encrypt(_keys)

    def construct_AuthorizationRequest(
        self, request=AuthorizationRequest, request_args=None, extra_args=None, request_param=None, **kwargs
    ):

        if request_args is not None:
            # if "claims" in request_args:
            # kwargs["claims"] = request_args["claims"]
            #     del request_args["claims"]
            if "nonce" not in request_args:
                _rt = request_args["response_type"]
                if "token" in _rt or "id_token" in _rt:
                    request_args["nonce"] = rndstr(12)
        elif "response_type" in kwargs:
            if "token" in kwargs["response_type"]:
                request_args = {"nonce": rndstr(12)}
        else:  # Never wrong to specify a nonce
            request_args = {"nonce": rndstr(12)}

        if "request_method" in kwargs:
            if kwargs["request_method"] == "file":
                request_param = "request_uri"
            else:
                request_param = "request"
            del kwargs["request_method"]

        areq = oauth2.Client.construct_AuthorizationRequest(self, request, request_args, extra_args, **kwargs)

        if request_param:
            alg = None
            for arg in ["request_object_signing_alg", "algorithm"]:
                try:  # Trumps everything
                    alg = kwargs[arg]
                except KeyError:
                    pass
                else:
                    break

            if not alg:
                try:
                    alg = self.behaviour["request_object_signing_alg"]
                except KeyError:
                    alg = "none"

            kwargs["request_object_signing_alg"] = alg

            if "keys" not in kwargs and alg and alg != "none":
                _kty = jws.alg2keytype(alg)
                try:
                    _kid = kwargs["sig_kid"]
                except KeyError:
                    _kid = self.kid["sig"].get(_kty, None)

                kwargs["keys"] = self.keyjar.get_signing_key(_kty, kid=_kid)

            _req = make_openid_request(areq, **kwargs)

            # Should the request be encrypted
            _req = self.request_object_encryption(_req, **kwargs)

            if request_param == "request":
                areq["request"] = _req
            else:
                _filedir = kwargs["local_dir"]
                if not os.path.isdir(_filedir):
                    os.makedirs(_filedir)
                _webpath = kwargs["base_path"]
                _name = rndstr(10) + ".jwt"
                filename = os.path.join(_filedir, _name)
                while os.path.exists(filename):
                    _name = rndstr(10)
                    filename = os.path.join(_filedir, _name)
                fid = open(filename, mode="w")
                fid.write(_req)
                fid.close()
                _webname = "%s%s" % (_webpath, _name)
                areq["request_uri"] = _webname

        return areq

    # noinspection PyUnusedLocal
    def construct_AccessTokenRequest(self, request=AccessTokenRequest, request_args=None, extra_args=None, **kwargs):

        return oauth2.Client.construct_AccessTokenRequest(self, request, request_args, extra_args, **kwargs)

    def construct_RefreshAccessTokenRequest(
        self, request=RefreshAccessTokenRequest, request_args=None, extra_args=None, **kwargs
    ):

        return oauth2.Client.construct_RefreshAccessTokenRequest(self, request, request_args, extra_args, **kwargs)

    def construct_UserInfoRequest(self, request=UserInfoRequest, request_args=None, extra_args=None, **kwargs):

        if request_args is None:
            request_args = {}

        if "access_token" in request_args:
            pass
        else:
            if "scope" not in kwargs:
                kwargs["scope"] = "openid"
            token = self.get_token(**kwargs)
            if token is None:
                raise PyoidcError("No valid token available")

            request_args["access_token"] = token.access_token

        return self.construct_request(request, request_args, extra_args)

    # noinspection PyUnusedLocal
    def construct_RegistrationRequest(self, request=RegistrationRequest, request_args=None, extra_args=None, **kwargs):

        return self.construct_request(request, request_args, extra_args)

    # noinspection PyUnusedLocal
    def construct_RefreshSessionRequest(
        self, request=RefreshSessionRequest, request_args=None, extra_args=None, **kwargs
    ):

        return self.construct_request(request, request_args, extra_args)

    def _id_token_based(self, request, request_args=None, extra_args=None, **kwargs):

        if request_args is None:
            request_args = {}

        try:
            _prop = kwargs["prop"]
        except KeyError:
            _prop = "id_token"

        if _prop in request_args:
            pass
        else:
            id_token = self._get_id_token(**kwargs)
            if id_token is None:
                raise PyoidcError("No valid id token available")

            request_args[_prop] = id_token

        return self.construct_request(request, request_args, extra_args)

    def construct_CheckSessionRequest(self, request=CheckSessionRequest, request_args=None, extra_args=None, **kwargs):

        return self._id_token_based(request, request_args, extra_args, **kwargs)

    def construct_CheckIDRequest(self, request=CheckIDRequest, request_args=None, extra_args=None, **kwargs):

        # access_token is where the id_token will be placed
        return self._id_token_based(request, request_args, extra_args, prop="access_token", **kwargs)

    def construct_EndSessionRequest(self, request=EndSessionRequest, request_args=None, extra_args=None, **kwargs):

        if request_args is None:
            request_args = {}

        if "state" in kwargs:
            request_args["state"] = kwargs["state"]
        elif "state" in request_args:
            kwargs["state"] = request_args["state"]

        # if "redirect_url" not in request_args:
        #            request_args["redirect_url"] = self.redirect_url

        return self._id_token_based(request, request_args, extra_args, **kwargs)

    # ------------------------------------------------------------------------
    def authorization_request_info(self, request_args=None, extra_args=None, **kwargs):
        return self.request_info(AuthorizationRequest, "GET", request_args, extra_args, **kwargs)

    # ------------------------------------------------------------------------
    def do_authorization_request(
        self,
        request=AuthorizationRequest,
        state="",
        body_type="",
        method="GET",
        request_args=None,
        extra_args=None,
        http_args=None,
        response_cls=AuthorizationResponse,
    ):

        algs = self.sign_enc_algs("id_token")

        return oauth2.Client.do_authorization_request(
            self, request, state, body_type, method, request_args, extra_args, http_args, response_cls, algs=algs
        )

    def do_access_token_request(
        self,
        request=AccessTokenRequest,
        scope="",
        state="",
        body_type="json",
        method="POST",
        request_args=None,
        extra_args=None,
        http_args=None,
        response_cls=AccessTokenResponse,
        authn_method="client_secret_basic",
        **kwargs
    ):

        return oauth2.Client.do_access_token_request(
            self,
            request,
            scope,
            state,
            body_type,
            method,
            request_args,
            extra_args,
            http_args,
            response_cls,
            authn_method,
            **kwargs
        )

    def do_access_token_refresh(
        self,
        request=RefreshAccessTokenRequest,
        state="",
        body_type="json",
        method="POST",
        request_args=None,
        extra_args=None,
        http_args=None,
        response_cls=AccessTokenResponse,
        **kwargs
    ):

        return oauth2.Client.do_access_token_refresh(
            self, request, state, body_type, method, request_args, extra_args, http_args, response_cls, **kwargs
        )

    def do_registration_request(
        self,
        request=RegistrationRequest,
        scope="",
        state="",
        body_type="json",
        method="POST",
        request_args=None,
        extra_args=None,
        http_args=None,
        response_cls=None,
    ):

        url, body, ht_args, csi = self.request_info(
            request, method=method, request_args=request_args, extra_args=extra_args, scope=scope, state=state
        )

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(http_args)

        if response_cls is None:
            response_cls = RegistrationResponse

        response = self.request_and_return(url, response_cls, method, body, body_type, state=state, http_args=http_args)

        return response

    def do_check_session_request(
        self,
        request=CheckSessionRequest,
        scope="",
        state="",
        body_type="json",
        method="GET",
        request_args=None,
        extra_args=None,
        http_args=None,
        response_cls=IdToken,
    ):

        url, body, ht_args, csi = self.request_info(
            request, method=method, request_args=request_args, extra_args=extra_args, scope=scope, state=state
        )

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(http_args)

        return self.request_and_return(url, response_cls, method, body, body_type, state=state, http_args=http_args)

    def do_check_id_request(
        self,
        request=CheckIDRequest,
        scope="",
        state="",
        body_type="json",
        method="GET",
        request_args=None,
        extra_args=None,
        http_args=None,
        response_cls=IdToken,
    ):

        url, body, ht_args, csi = self.request_info(
            request, method=method, request_args=request_args, extra_args=extra_args, scope=scope, state=state
        )

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(http_args)

        return self.request_and_return(url, response_cls, method, body, body_type, state=state, http_args=http_args)

    def do_end_session_request(
        self,
        request=EndSessionRequest,
        scope="",
        state="",
        body_type="",
        method="GET",
        request_args=None,
        extra_args=None,
        http_args=None,
        response_cls=None,
    ):

        url, body, ht_args, csi = self.request_info(
            request, method=method, request_args=request_args, extra_args=extra_args, scope=scope, state=state
        )

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(http_args)

        return self.request_and_return(url, response_cls, method, body, body_type, state=state, http_args=http_args)

    def user_info_request(self, method="GET", state="", scope="", **kwargs):
        uir = UserInfoRequest()
        logger.debug("[user_info_request]: kwargs:%s" % (kwargs,))
        if "token" in kwargs:
            if kwargs["token"]:
                uir["access_token"] = kwargs["token"]
                token = Token()
                token.token_type = "Bearer"
                token.access_token = kwargs["token"]
                kwargs["behavior"] = "use_authorization_header"
            else:
                # What to do ? Need a callback
                token = None
        elif "access_token" in kwargs and kwargs["access_token"]:
            uir["access_token"] = kwargs["access_token"]
            del kwargs["access_token"]
            token = None
        else:
            token = self.grant[state].get_token(scope)

            if token.is_valid():
                uir["access_token"] = token.access_token
                if token.token_type == "Bearer" and method == "GET":
                    kwargs["behavior"] = "use_authorization_header"
            else:
                # raise oauth2.OldAccessToken
                if self.log:
                    self.log.info("do access token refresh")
                try:
                    self.do_access_token_refresh(token=token)
                    token = self.grant[state].get_token(scope)
                    uir["access_token"] = token.access_token
                except Exception:
                    raise

        uri = self._endpoint("userinfo_endpoint", **kwargs)
        # If access token is a bearer token it might be sent in the
        # authorization header
        # 3-ways of sending the access_token:
        # - POST with token in authorization header
        # - POST with token in message body
        # - GET with token in authorization header
        if "behavior" in kwargs:
            _behav = kwargs["behavior"]
            _token = uir["access_token"]
            try:
                _ttype = kwargs["token_type"]
            except KeyError:
                try:
                    _ttype = token.token_type
                except AttributeError:
                    raise MissingParameter("Unspecified token type")

            # use_authorization_header, token_in_message_body
            if "use_authorization_header" in _behav and _ttype == "Bearer":
                bh = "Bearer %s" % _token
                if "headers" in kwargs:
                    kwargs["headers"].update({"Authorization": bh})
                else:
                    kwargs["headers"] = {"Authorization": bh}

            if "token_in_message_body" not in _behav:
                # remove the token from the request
                del uir["access_token"]

        path, body, kwargs = get_or_post(uri, method, uir, **kwargs)

        h_args = dict([(k, v) for k, v in kwargs.items() if k in HTTP_ARGS])

        return path, body, method, h_args

    def do_user_info_request(self, method="POST", state="", scope="openid", request="openid", **kwargs):

        kwargs["request"] = request
        path, body, method, h_args = self.user_info_request(method, state, scope, **kwargs)

        logger.debug("[do_user_info_request] PATH:%s BODY:%s H_ARGS: %s" % (path, body, h_args))

        try:
            resp = self.http_request(path, method, data=body, **h_args)
        except oauth2.MissingRequiredAttribute:
            raise

        if resp.status_code == 200:
            try:
                assert "application/json" in resp.headers["content-type"]
                sformat = "json"
            except AssertionError:
                assert "application/jwt" in resp.headers["content-type"]
                sformat = "jwt"
        elif resp.status_code == 500:
            raise PyoidcError("ERROR: Something went wrong: %s" % resp.text)
        else:
            raise PyoidcError("ERROR: Something went wrong [%s]: %s" % (resp.status_code, resp.text))

        try:
            _schema = kwargs["user_info_schema"]
        except KeyError:
            _schema = OpenIDSchema

        logger.debug("Reponse text: '%s'" % resp.text)

        _txt = resp.text
        if sformat == "json":
            res = _schema().from_json(txt=_txt)
        else:
            res = _schema().from_jwt(_txt, keyjar=self.keyjar, sender=self.provider_info["issuer"])

        self.store_response(res, _txt)

        return res

    def get_userinfo_claims(self, access_token, endpoint, method="POST", schema_class=OpenIDSchema, **kwargs):

        uir = UserInfoRequest(access_token=access_token)

        h_args = dict([(k, v) for k, v in kwargs.items() if k in HTTP_ARGS])

        if "authn_method" in kwargs:
            http_args = self.init_authentication_method(**kwargs)
        else:
            # If nothing defined this is the default
            http_args = self.init_authentication_method(uir, "bearer_header", **kwargs)

        h_args.update(http_args)
        path, body, kwargs = get_or_post(endpoint, method, uir, **kwargs)

        try:
            resp = self.http_request(path, method, data=body, **h_args)
        except oauth2.MissingRequiredAttribute:
            raise

        if resp.status_code == 200:
            assert "application/json" in resp.headers["content-type"]
        elif resp.status_code == 500:
            raise PyoidcError("ERROR: Something went wrong: %s" % resp.text)
        else:
            raise PyoidcError("ERROR: Something went wrong [%s]: %s" % (resp.status_code, resp.text))

        res = schema_class().from_json(txt=resp.text)
        self.store_response(res, resp.txt)
        return res

    def handle_provider_config(self, pcr, issuer, keys=True, endpoints=True):
        """
        Deal with Provider Config Response
        :param pcr: The ProviderConfigResponse instance
        :param issuer: The one I thought should be the issuer of the config
        :param keys: Should I deal with keys
        :param endpoints: Should I deal with endpoints, that is store them
        as attributes in self.
        """

        if "issuer" in pcr:
            _pcr_issuer = pcr["issuer"]
            if pcr["issuer"].endswith("/"):
                if issuer.endswith("/"):
                    _issuer = issuer
                else:
                    _issuer = issuer + "/"
            else:
                if issuer.endswith("/"):
                    _issuer = issuer[:-1]
                else:
                    _issuer = issuer

            try:
                _ = self.allow["issuer_mismatch"]
            except KeyError:
                try:
                    assert _issuer == _pcr_issuer
                except AssertionError:
                    raise IssuerMismatch("'%s' != '%s'" % (_issuer, _pcr_issuer), pcr)

            self.provider_info = pcr
        else:
            _pcr_issuer = issuer

        if endpoints:
            for key, val in pcr.items():
                if key.endswith("_endpoint"):
                    setattr(self, key, val)

        if keys:
            if self.keyjar is None:
                self.keyjar = KeyJar(verify_ssl=self.verify_ssl)

            self.keyjar.load_keys(pcr, _pcr_issuer)

    def provider_config(
        self,
        issuer,
        keys=True,
        endpoints=True,
        response_cls=ProviderConfigurationResponse,
        serv_pattern=OIDCONF_PATTERN,
    ):
        if issuer.endswith("/"):
            _issuer = issuer[:-1]
        else:
            _issuer = issuer

        url = serv_pattern % _issuer

        pcr = None
        r = self.http_request(url)
        if r.status_code == 200:
            try:
                pcr = response_cls().from_json(r.text)
            except:
                logger.error("Faulty provider config response: {}".format(r.text))
        elif r.status_code == 302 or r.status_code == 301:
            while r.status_code == 302 or r.status_code == 301:
                r = self.http_request(r.headers["location"])
                if r.status_code == 200:
                    pcr = response_cls().from_json(r.text)
                    break

        # logger.debug("Provider info: %s" % pcr)
        if pcr is None:
            raise PyoidcError("Trying '%s', status %s" % (url, r.status_code))

        self.store_response(pcr, r.text)

        self.handle_provider_config(pcr, issuer, keys, endpoints)

        return pcr

    def unpack_aggregated_claims(self, userinfo):
        if userinfo["_claim_sources"]:
            for csrc, spec in userinfo["_claim_sources"].items():
                if "JWT" in spec:
                    aggregated_claims = Message().from_jwt(spec["JWT"].encode("utf-8"), keyjar=self.keyjar, sender=csrc)
                    claims = [value for value, src in userinfo["_claim_names"].items() if src == csrc]
                    assert claims == aggregated_claims.keys()

                    for key, vals in aggregated_claims.items():
                        userinfo[key] = vals

        return userinfo

    def fetch_distributed_claims(self, userinfo, callback=None):
        for csrc, spec in userinfo["_claim_sources"].items():
            if "endpoint" in spec:
                if "access_token" in spec:
                    _uinfo = self.do_user_info_request(token=spec["access_token"], userinfo_endpoint=spec["endpoint"])
                else:
                    _uinfo = self.do_user_info_request(token=callback(csrc), userinfo_endpoint=spec["endpoint"])

                claims = [value for value, src in userinfo["_claim_names"].items() if src == csrc]
                assert claims == _uinfo.keys()

                for key, vals in _uinfo.items():
                    userinfo[key] = vals

        return userinfo

    def verify_alg_support(self, alg, usage, other):
        """
        Verifies that the algorithm to be used are supported by the other side.

        :param alg: The algorithm specification
        :param usage: In which context the 'alg' will be used.
            The following values are supported:
            - userinfo
            - id_token
            - request_object
            - token_endpoint_auth
        :param other: The identifier for the other side
        :return: True or False
        """

        try:
            _pcr = self.provider_info
            supported = _pcr["%s_algs_supported" % usage]
        except KeyError:
            try:
                supported = getattr(self, "%s_algs_supported" % usage)
            except AttributeError:
                supported = None

        if supported is None:
            return True
        else:
            if alg in supported:
                return True
            else:
                return False

    def match_preferences(self, pcr=None, issuer=None):
        """
        Match the clients preferences against what the provider can do.

        :param pcr: Provider configuration response if available
        :param issuer: The issuer identifier
        """
        if not pcr:
            pcr = self.provider_info

        regreq = RegistrationRequest

        for _pref, _prov in PREFERENCE2PROVIDER.items():
            try:
                vals = self.client_prefs[_pref]
            except KeyError:
                continue

            try:
                _pvals = pcr[_prov]
            except KeyError:
                try:
                    self.behaviour[_pref] = PROVIDER_DEFAULT[_pref]
                except KeyError:
                    # self.behaviour[_pref]= vals[0]
                    if isinstance(pcr.c_param[_prov][0], list):
                        self.behaviour[_pref] = []
                    else:
                        self.behaviour[_pref] = None
                continue

            if isinstance(vals, basestring):
                if vals in _pvals:
                    self.behaviour[_pref] = vals
            else:
                vtyp = regreq.c_param[_pref]

                if isinstance(vtyp[0], list):
                    self.behaviour[_pref] = []
                    for val in vals:
                        if val in _pvals:
                            self.behaviour[_pref].append(val)
                else:
                    for val in vals:
                        if val in _pvals:
                            self.behaviour[_pref] = val
                            break

            if _pref not in self.behaviour:
                raise ConfigurationError("OP couldn't match preference:%s" % _pref, pcr)

        for key, val in self.client_prefs.items():
            if key in self.behaviour:
                continue

            try:
                vtyp = regreq.c_param[key]
                if isinstance(vtyp[0], list):
                    pass
                elif isinstance(val, list) and not isinstance(val, basestring):
                    val = val[0]
            except KeyError:
                pass
            if key not in PREFERENCE2PROVIDER:
                self.behaviour[key] = val

    def store_registration_info(self, reginfo):
        self.registration_response = reginfo
        if "token_endpoint_auth_method" not in self.registration_response:
            self.registration_response["token_endpoint_auth_method"] = "client_secret_post"
        self.client_id = reginfo["client_id"]
        try:
            self.client_secret = reginfo["client_secret"]
        except KeyError:  # Not required
            pass
        else:
            try:
                self.registration_expires = reginfo["client_secret_expires_at"]
            except KeyError:
                pass
        try:
            self.registration_access_token = reginfo["registration_access_token"]
        except KeyError:
            pass

    def handle_registration_info(self, response):
        if response.status_code == 200:
            resp = RegistrationResponse().deserialize(response.text, "json")
            self.store_response(resp, response.text)
            self.store_registration_info(resp)
        else:
            err = ErrorResponse().deserialize(response.text, "json")
            raise PyoidcError("Registration failed: %s" % err.to_json())

        return resp

    def registration_read(self, url="", registration_access_token=None):
        if not url:
            url = self.registration_response["registration_client_uri"]

        if not registration_access_token:
            registration_access_token = self.registration_access_token

        headers = [("Authorization", "Bearer %s" % registration_access_token)]
        rsp = self.http_request(url, "GET", headers=headers)

        return self.handle_registration_info(rsp)

    def create_registration_request(self, **kwargs):
        """
        Create a registration request

        :param kwargs: parameters to the registration request
        :return:
        """
        req = RegistrationRequest()

        for prop in req.parameters():
            try:
                req[prop] = kwargs[prop]
            except KeyError:
                try:
                    req[prop] = self.behaviour[prop]
                except KeyError:
                    pass

        if "post_logout_redirect_uris" not in req:
            try:
                req["post_logout_redirect_uris"] = self.post_logout_redirect_uris
            except AttributeError:
                pass

        if "redirect_uris" not in req:
            try:
                req["redirect_uris"] = self.redirect_uris
            except AttributeError:
                raise MissingRequiredAttribute("redirect_uris", req)

        return req

    def register(self, url, **kwargs):
        """
        Register the client at an OP

        :param url: The OPs registration endpoint
        :param kwargs: parameters to the registration request
        :return:
        """
        req = self.create_registration_request(**kwargs)

        headers = {"content-type": "application/json"}

        rsp = self.http_request(url, "POST", data=req.to_json(), headers=headers)

        return self.handle_registration_info(rsp)

    def normalization(self, principal, idtype="mail"):
        if idtype == "mail":
            (local, domain) = principal.split("@")
            subject = "acct:%s" % principal
        elif idtype == "url":
            p = urlparse(principal)
            domain = p.netloc
            subject = principal
        else:
            domain = ""
            subject = principal

        return subject, domain

    def discover(self, principal):
        # subject, host = self.normalization(principal)
        return self.wf.discovery_query(principal)

    def sign_enc_algs(self, typ):
        resp = {}
        for key, val in PARAMMAP.items():
            try:
                resp[key] = self.registration_response[val % typ]
            except (TypeError, KeyError):
                if key == "sign":
                    resp[key] = DEF_SIGN_ALG["id_token"]
        return resp

    def _verify_id_token(self, id_token, nonce="", acr_values=None, auth_time=0, max_age=0):
        """
        If the JWT alg Header Parameter uses a MAC based algorithm s uch as
        HS256, HS384, or HS512, the octets of the UTF-8 representation of the
        client_secret corresponding to the client_id contained in the aud
        (audience) Claim are used as the key to validate the signature. For MAC
        based algorithms, the behavior is unspecified if the aud is
        multi-valued or if an azp value is present that is different than the
        aud value.

        :param id_token: The ID Token tp check
        :param nonce: The nonce specified in the authorization request
        :param acr_values: Asked for acr values
        :param auth_time: An auth_time claim
        :param max_age: Max age of authentication
        """

        try:
            assert self.provider_info["issuer"] == id_token["iss"]
        except AssertionError:
            raise OtherError("issuer != iss")

        _now = time_util.utc_time_sans_frac()

        try:
            assert _now < id_token["exp"]
        except AssertionError:
            raise OtherError("Passed best before date")

        if self.id_token_max_age:
            try:
                assert _now < int(id_token["iat"]) + self.id_token_max_age
            except AssertionError:
                raise OtherError("I think this ID token is to old")

        if nonce:
            try:
                assert nonce == id_token["nonce"]
            except AssertionError:
                raise OtherError("nonce mismatch")

        if acr_values:
            try:
                assert id_token["acr"] in acr_values
            except AssertionError:
                raise OtherError("acr mismatch")

        if max_age:
            try:
                assert _now < int(id_token["auth_time"]) + max_age
            except AssertionError:
                raise AuthnToOld("To old authentication")

        if auth_time:
            if not claims_match(id_token["auth_time"], {"auth_time": auth_time}):
                raise AuthnToOld("To old authentication")

    def verify_id_token(self, id_token, authn_req):
        kwa = {}
        try:
            kwa["nonce"] = authn_req["nonce"]
        except KeyError:
            pass

        for param in ["acr_values", "max_age"]:
            try:
                kwa[param] = authn_req[param]
            except KeyError:
                pass

        self._verify_id_token(id_token, **kwa)
Example #44
0
class Client(oauth2.Client):
    _endpoints = ENDPOINTS

    def __init__(self,
                 client_id=None,
                 ca_certs=None,
                 client_prefs=None,
                 client_authn_method=None,
                 keyjar=None,
                 verify_ssl=True):

        oauth2.Client.__init__(self,
                               client_id,
                               ca_certs,
                               client_authn_method=client_authn_method,
                               keyjar=keyjar,
                               verify_ssl=verify_ssl)

        self.file_store = "./file/"
        self.file_uri = "http://localhost/"

        # OpenID connect specific endpoints
        for endpoint in ENDPOINTS:
            setattr(self, endpoint, "")

        self.id_token = None
        self.log = None

        self.request2endpoint = REQUEST2ENDPOINT
        self.response2error = RESPONSE2ERROR

        self.grant_class = Grant
        self.token_class = Token
        self.provider_info = None
        self.registration_response = None
        self.client_prefs = client_prefs or {}

        self.behaviour = {
            "request_object_signing_alg": DEF_SIGN_ALG["openid_request_object"]
        }

        self.wf = WebFinger(OIC_ISSUER)
        self.wf.httpd = self
        self.allow = {}
        self.post_logout_redirect_uris = []
        self.registration_expires = 0
        self.registration_access_token = None

        # Default key by kid for different key types
        # For instance {"RSA":"abc"}
        self.kid = {"sig": {}, "enc": {}}

    def _get_id_token(self, **kwargs):
        try:
            return kwargs["id_token"]
        except KeyError:
            grant = self.get_grant(**kwargs)

        if grant:
            try:
                _scope = kwargs["scope"]
            except KeyError:
                _scope = None

            for token in grant.tokens:
                if token.scope and _scope:
                    flag = True
                    for item in _scope:
                        try:
                            assert item in token.scope
                        except AssertionError:
                            flag = False
                            break
                    if not flag:
                        break
                if token.id_token:
                    return token.id_token

        return None

    def construct_AuthorizationRequest(self,
                                       request=AuthorizationRequest,
                                       request_args=None,
                                       extra_args=None,
                                       request_param=None,
                                       **kwargs):

        if request_args is not None:
            # if "claims" in request_args:
            #     kwargs["claims"] = request_args["claims"]
            #     del request_args["claims"]
            if "nonce" not in request_args:
                _rt = request_args["response_type"]
                if "token" in _rt or "id_token" in _rt:
                    request_args["nonce"] = rndstr(12)
        elif "response_type" in kwargs:
            if "token" in kwargs["response_type"]:
                request_args = {"nonce": rndstr(12)}
        else:  # Never wrong to specify a nonce
            request_args = {"nonce": rndstr(12)}

        if "request_method" in kwargs:
            if kwargs["request_method"] == "file":
                request_param = "request_uri"
                del kwargs["request_method"]

        areq = oauth2.Client.construct_AuthorizationRequest(
            self, request, request_args, extra_args, **kwargs)

        if request_param:
            alg = self.behaviour["request_object_signing_alg"]
            if "algorithm" not in kwargs:
                kwargs["algorithm"] = alg

            if "keys" not in kwargs and alg:
                _kty = alg2keytype(alg)
                try:
                    kwargs["keys"] = self.keyjar.get_signing_key(
                        _kty, kid=self.kid["sig"][_kty])
                except KeyError:
                    kwargs["keys"] = self.keyjar.get_signing_key(_kty)

            _req = make_openid_request(areq, **kwargs)

            if request_param == "request":
                areq["request"] = _req
            else:
                _filedir = kwargs["local_dir"]
                _webpath = kwargs["base_path"]
                _name = rndstr(10)
                filename = os.path.join(_filedir, _name)
                while os.path.exists(filename):
                    _name = rndstr(10)
                    filename = os.path.join(_filedir, _name)
                fid = open(filename, mode="w")
                fid.write(_req)
                fid.close()
                _webname = "%s%s" % (_webpath, _name)
                areq["request_uri"] = _webname

        return areq

    #noinspection PyUnusedLocal
    def construct_AccessTokenRequest(self,
                                     request=AccessTokenRequest,
                                     request_args=None,
                                     extra_args=None,
                                     **kwargs):

        return oauth2.Client.construct_AccessTokenRequest(
            self, request, request_args, extra_args, **kwargs)

    def construct_RefreshAccessTokenRequest(self,
                                            request=RefreshAccessTokenRequest,
                                            request_args=None,
                                            extra_args=None,
                                            **kwargs):

        return oauth2.Client.construct_RefreshAccessTokenRequest(
            self, request, request_args, extra_args, **kwargs)

    def construct_UserInfoRequest(self,
                                  request=UserInfoRequest,
                                  request_args=None,
                                  extra_args=None,
                                  **kwargs):

        if request_args is None:
            request_args = {}

        if "access_token" in request_args:
            pass
        else:
            if "scope" not in kwargs:
                kwargs["scope"] = "openid"
            token = self.get_token(**kwargs)
            if token is None:
                raise PyoidcError("No valid token available")

            request_args["access_token"] = token.access_token

        return self.construct_request(request, request_args, extra_args)

    #noinspection PyUnusedLocal
    def construct_RegistrationRequest(self,
                                      request=RegistrationRequest,
                                      request_args=None,
                                      extra_args=None,
                                      **kwargs):

        return self.construct_request(request, request_args, extra_args)

    #noinspection PyUnusedLocal
    def construct_RefreshSessionRequest(self,
                                        request=RefreshSessionRequest,
                                        request_args=None,
                                        extra_args=None,
                                        **kwargs):

        return self.construct_request(request, request_args, extra_args)

    def _id_token_based(self,
                        request,
                        request_args=None,
                        extra_args=None,
                        **kwargs):

        if request_args is None:
            request_args = {}

        try:
            _prop = kwargs["prop"]
        except KeyError:
            _prop = "id_token"

        if _prop in request_args:
            pass
        else:
            id_token = self._get_id_token(**kwargs)
            if id_token is None:
                raise PyoidcError("No valid id token available")

            request_args[_prop] = id_token

        return self.construct_request(request, request_args, extra_args)

    def construct_CheckSessionRequest(self,
                                      request=CheckSessionRequest,
                                      request_args=None,
                                      extra_args=None,
                                      **kwargs):

        return self._id_token_based(request, request_args, extra_args,
                                    **kwargs)

    def construct_CheckIDRequest(self,
                                 request=CheckIDRequest,
                                 request_args=None,
                                 extra_args=None,
                                 **kwargs):

        # access_token is where the id_token will be placed
        return self._id_token_based(request,
                                    request_args,
                                    extra_args,
                                    prop="access_token",
                                    **kwargs)

    def construct_EndSessionRequest(self,
                                    request=EndSessionRequest,
                                    request_args=None,
                                    extra_args=None,
                                    **kwargs):

        if request_args is None:
            request_args = {}

        if "state" in kwargs:
            request_args["state"] = kwargs["state"]
        elif "state" in request_args:
            kwargs["state"] = request_args["state"]

        #        if "redirect_url" not in request_args:
        #            request_args["redirect_url"] = self.redirect_url

        return self._id_token_based(request, request_args, extra_args,
                                    **kwargs)

    # ------------------------------------------------------------------------
    def authorization_request_info(self,
                                   request_args=None,
                                   extra_args=None,
                                   **kwargs):
        return self.request_info(AuthorizationRequest, "GET", request_args,
                                 extra_args, **kwargs)

    # ------------------------------------------------------------------------
    def do_authorization_request(self,
                                 request=AuthorizationRequest,
                                 state="",
                                 body_type="",
                                 method="GET",
                                 request_args=None,
                                 extra_args=None,
                                 http_args=None,
                                 response_cls=AuthorizationResponse):

        return oauth2.Client.do_authorization_request(self, request, state,
                                                      body_type, method,
                                                      request_args, extra_args,
                                                      http_args, response_cls)

    def do_access_token_request(self,
                                request=AccessTokenRequest,
                                scope="",
                                state="",
                                body_type="json",
                                method="POST",
                                request_args=None,
                                extra_args=None,
                                http_args=None,
                                response_cls=AccessTokenResponse,
                                authn_method="",
                                **kwargs):

        return oauth2.Client.do_access_token_request(self, request, scope,
                                                     state, body_type, method,
                                                     request_args, extra_args,
                                                     http_args, response_cls,
                                                     authn_method, **kwargs)

    def do_access_token_refresh(self,
                                request=RefreshAccessTokenRequest,
                                state="",
                                body_type="json",
                                method="POST",
                                request_args=None,
                                extra_args=None,
                                http_args=None,
                                response_cls=AccessTokenResponse,
                                **kwargs):

        return oauth2.Client.do_access_token_refresh(self, request, state,
                                                     body_type, method,
                                                     request_args, extra_args,
                                                     http_args, response_cls,
                                                     **kwargs)

    def do_registration_request(self,
                                request=RegistrationRequest,
                                scope="",
                                state="",
                                body_type="json",
                                method="POST",
                                request_args=None,
                                extra_args=None,
                                http_args=None,
                                response_cls=None):

        url, body, ht_args, csi = self.request_info(request,
                                                    method=method,
                                                    request_args=request_args,
                                                    extra_args=extra_args,
                                                    scope=scope,
                                                    state=state)

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(http_args)

        if response_cls is None:
            response_cls = RegistrationResponse

        response = self.request_and_return(url,
                                           response_cls,
                                           method,
                                           body,
                                           body_type,
                                           state=state,
                                           http_args=http_args)

        return response

    def do_check_session_request(self,
                                 request=CheckSessionRequest,
                                 scope="",
                                 state="",
                                 body_type="json",
                                 method="GET",
                                 request_args=None,
                                 extra_args=None,
                                 http_args=None,
                                 response_cls=IdToken):

        url, body, ht_args, csi = self.request_info(request,
                                                    method=method,
                                                    request_args=request_args,
                                                    extra_args=extra_args,
                                                    scope=scope,
                                                    state=state)

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(http_args)

        return self.request_and_return(url,
                                       response_cls,
                                       method,
                                       body,
                                       body_type,
                                       state=state,
                                       http_args=http_args)

    def do_check_id_request(self,
                            request=CheckIDRequest,
                            scope="",
                            state="",
                            body_type="json",
                            method="GET",
                            request_args=None,
                            extra_args=None,
                            http_args=None,
                            response_cls=IdToken):

        url, body, ht_args, csi = self.request_info(request,
                                                    method=method,
                                                    request_args=request_args,
                                                    extra_args=extra_args,
                                                    scope=scope,
                                                    state=state)

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(http_args)

        return self.request_and_return(url,
                                       response_cls,
                                       method,
                                       body,
                                       body_type,
                                       state=state,
                                       http_args=http_args)

    def do_end_session_request(self,
                               request=EndSessionRequest,
                               scope="",
                               state="",
                               body_type="",
                               method="GET",
                               request_args=None,
                               extra_args=None,
                               http_args=None,
                               response_cls=None):

        url, body, ht_args, csi = self.request_info(request,
                                                    method=method,
                                                    request_args=request_args,
                                                    extra_args=extra_args,
                                                    scope=scope,
                                                    state=state)

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(http_args)

        return self.request_and_return(url,
                                       response_cls,
                                       method,
                                       body,
                                       body_type,
                                       state=state,
                                       http_args=http_args)

    def user_info_request(self, method="GET", state="", scope="", **kwargs):
        uir = UserInfoRequest()
        logger.debug("[user_info_request]: kwargs:%s" % (kwargs, ))
        if "token" in kwargs:
            if kwargs["token"]:
                uir["access_token"] = kwargs["token"]
                token = Token()
                token.token_type = "Bearer"
                token.access_token = kwargs["token"]
                kwargs["behavior"] = "use_authorization_header"
            else:
                # What to do ? Need a callback
                token = None
        elif "access_token" in kwargs and kwargs["access_token"]:
            uir["access_token"] = kwargs["access_token"]
            del kwargs["access_token"]
            token = None
        else:
            token = self.grant[state].get_token(scope)

            if token.is_valid():
                uir["access_token"] = token.access_token
                if token.token_type == "Bearer" and method == "GET":
                    kwargs["behavior"] = "use_authorization_header"
            else:
                # raise oauth2.OldAccessToken
                if self.log:
                    self.log.info("do access token refresh")
                try:
                    self.do_access_token_refresh(token=token)
                    token = self.grant[state].get_token(scope)
                    uir["access_token"] = token.access_token
                except Exception:
                    raise

        uri = self._endpoint("userinfo_endpoint", **kwargs)
        # If access token is a bearer token it might be sent in the
        # authorization header
        # 3-ways of sending the access_token:
        # - POST with token in authorization header
        # - POST with token in message body
        # - GET with token in authorization header
        if "behavior" in kwargs:
            _behav = kwargs["behavior"]
            _token = uir["access_token"]
            try:
                _ttype = kwargs["token_type"]
            except KeyError:
                try:
                    _ttype = token.token_type
                except AttributeError:
                    raise MissingParameter("Unspecified token type")

            # use_authorization_header, token_in_message_body
            if "use_authorization_header" in _behav and _ttype == "Bearer":
                bh = "Bearer %s" % _token
                if "headers" in kwargs:
                    kwargs["headers"].update({"Authorization": bh})
                else:
                    kwargs["headers"] = {"Authorization": bh}

            if not "token_in_message_body" in _behav:
                # remove the token from the request
                del uir["access_token"]

        path, body, kwargs = self.get_or_post(uri, method, uir, **kwargs)

        h_args = dict([(k, v) for k, v in kwargs.items() if k in HTTP_ARGS])

        return path, body, method, h_args

    def do_user_info_request(self,
                             method="POST",
                             state="",
                             scope="openid",
                             request="openid",
                             **kwargs):

        kwargs["request"] = request
        path, body, method, h_args = self.user_info_request(
            method, state, scope, **kwargs)

        logger.debug("[do_user_info_request] PATH:%s BODY:%s H_ARGS: %s" %
                     (path, body, h_args))

        try:
            resp = self.http_request(path, method, data=body, **h_args)
        except oauth2.MissingRequiredAttribute:
            raise

        if resp.status_code == 200:
            try:
                assert "application/json" in resp.headers["content-type"]
                sformat = "json"
            except AssertionError:
                assert "application/jwt" in resp.headers["content-type"]
                sformat = "jwt"
        elif resp.status_code == 500:
            raise PyoidcError("ERROR: Something went wrong: %s" % resp.text)
        else:
            raise PyoidcError("ERROR: Something went wrong [%s]: %s" %
                              (resp.status_code, resp.text))

        try:
            _schema = kwargs["user_info_schema"]
        except KeyError:
            _schema = OpenIDSchema

        logger.debug("Reponse text: '%s'" % resp.text)

        if sformat == "json":
            return _schema().from_json(txt=resp.text)
        else:
            algo = self.client_prefs["userinfo_signed_response_alg"]
            _kty = alg2keytype(algo)
            # Keys of the OP ?
            try:
                keys = self.keyjar.get_signing_key(_kty, self.kid["sig"][_kty])
            except KeyError:
                keys = self.keyjar.get_signing_key(_kty)

            return _schema().from_jwt(resp.text, keys)

    def get_userinfo_claims(self,
                            access_token,
                            endpoint,
                            method="POST",
                            schema_class=OpenIDSchema,
                            **kwargs):

        uir = UserInfoRequest(access_token=access_token)

        h_args = dict([(k, v) for k, v in kwargs.items() if k in HTTP_ARGS])

        if "authn_method" in kwargs:
            http_args = self.init_authentication_method(**kwargs)
        else:
            # If nothing defined this is the default
            http_args = self.init_authentication_method(
                uir, "bearer_header", **kwargs)

        h_args.update(http_args)
        path, body, kwargs = self.get_or_post(endpoint, method, uir, **kwargs)

        try:
            resp = self.http_request(path, method, data=body, **h_args)
        except oauth2.MissingRequiredAttribute:
            raise

        if resp.status_code == 200:
            assert "application/json" in resp.headers["content-type"]
        elif resp.status_code == 500:
            raise PyoidcError("ERROR: Something went wrong: %s" % resp.text)
        else:
            raise PyoidcError("ERROR: Something went wrong [%s]" %
                              resp.status_code)

        return schema_class().from_json(txt=resp.text)

    def handle_provider_config(self, pcr, issuer, keys=True, endpoints=True):
        """
        Deal with Provider Config Response
        :param pcr: The ProviderConfigResponse instance
        :param issuer: The one I thought should be the issuer of the config
        :param keys: Should I deal with keys
        :param endpoints: Should I deal with endpoints, that is store them
        as attributes in self.
        """

        if "issuer" in pcr:
            _pcr_issuer = pcr["issuer"]
            if pcr["issuer"].endswith("/"):
                if issuer.endswith("/"):
                    _issuer = issuer
                else:
                    _issuer = issuer + "/"
            else:
                if issuer.endswith("/"):
                    _issuer = issuer[:-1]
                else:
                    _issuer = issuer

            try:
                _ = self.allow["issuer_mismatch"]
            except KeyError:
                try:
                    assert _issuer == _pcr_issuer
                except AssertionError:
                    raise IssuerMismatch(
                        "'%s' != '%s'" % (_issuer, _pcr_issuer), pcr)

            self.provider_info = pcr
        else:
            _pcr_issuer = issuer

        if endpoints:
            for key, val in pcr.items():
                if key.endswith("_endpoint"):
                    setattr(self, key, val)

        if keys:
            if self.keyjar is None:
                self.keyjar = KeyJar(verify_ssl=self.verify_ssl)

            self.keyjar.load_keys(pcr, _pcr_issuer)

    def provider_config(self,
                        issuer,
                        keys=True,
                        endpoints=True,
                        response_cls=ProviderConfigurationResponse,
                        serv_pattern=OIDCONF_PATTERN):
        if issuer.endswith("/"):
            _issuer = issuer[:-1]
        else:
            _issuer = issuer

        url = serv_pattern % _issuer

        pcr = None
        r = self.http_request(url)
        if r.status_code == 200:
            pcr = response_cls().from_json(r.text)
        elif r.status_code == 302:
            while r.status_code == 302:
                r = self.http_request(r.headers["location"])
                if r.status_code == 200:
                    pcr = response_cls().from_json(r.text)
                    break

        #logger.debug("Provider info: %s" % pcr)
        if pcr is None:
            raise PyoidcError("Trying '%s', status %s" % (url, r.status_code))

        self.handle_provider_config(pcr, issuer, keys, endpoints)

        return pcr

    def unpack_aggregated_claims(self, userinfo):
        if userinfo._claim_sources:
            for csrc, spec in userinfo._claim_sources.items():
                if "JWT" in spec:
                    if not csrc in self.keyjar:
                        self.provider_config(csrc, endpoints=False)

                    keycol = self.keyjar.get_verify_key(owner=csrc)
                    for typ, keyl in self.keyjar.get_verify_key().items():
                        try:
                            keycol[typ].extend(keyl)
                        except KeyError:
                            keycol[typ] = keyl

                    info = json.loads(JWS().verify(str(spec["JWT"]), keycol))
                    attr = [
                        n for n, s in userinfo._claim_names.items()
                        if s == csrc
                    ]
                    assert attr == info.keys()

                    for key, vals in info.items():
                        userinfo[key] = vals

        return userinfo

    def fetch_distributed_claims(self, userinfo, callback=None):
        for csrc, spec in userinfo._claim_sources.items():
            if "endpoint" in spec:
                #pcr = self.provider_config(csrc, keys=False, endpoints=False)

                if "access_token" in spec:
                    _uinfo = self.do_user_info_request(
                        token=spec["access_token"],
                        userinfo_endpoint=spec["endpoint"])
                else:
                    _uinfo = self.do_user_info_request(
                        token=callback(csrc),
                        userinfo_endpoint=spec["endpoint"])

                attr = [
                    n for n, s in userinfo._claim_names.items() if s == csrc
                ]
                assert attr == _uinfo.keys()

                for key, vals in _uinfo.items():
                    userinfo[key] = vals

        return userinfo

    def verify_alg_support(self, alg, usage, other):
        """
        Verifies that the algorithm to be used are supported by the other side.

        :param alg: The algorithm specification
        :param usage: In which context the 'alg' will be used.
            The following values are supported:
            - userinfo
            - id_token
            - request_object
            - token_endpoint_auth
        :param other: The identifier for the other side
        :return: True or False
        """

        try:
            _pcr = self.provider_info
            supported = _pcr["%s_algs_supported" % usage]
        except KeyError:
            try:
                supported = getattr(self, "%s_algs_supported" % usage)
            except AttributeError:
                supported = None

        if supported is None:
            return True
        else:
            if alg in supported:
                return True
            else:
                return False

    def match_preferences(self, pcr=None, issuer=None):
        """
        Match the clients preferences against what the provider can do.

        :param pcr: Provider configuration response if available
        :param issuer: The issuer identifier
        """
        if not pcr:
            pcr = self.provider_info

        regreq = RegistrationRequest

        for _pref, _prov in PREFERENCE2PROVIDER.items():
            try:
                vals = self.client_prefs[_pref]
            except KeyError:
                continue

            try:
                _pvals = pcr[_prov]
            except KeyError:
                try:
                    self.behaviour[_pref] = PROVIDER_DEFAULT[_pref]
                except KeyError:
                    #self.behaviour[_pref]= vals[0]
                    if isinstance(pcr.c_param[_prov][0], list):
                        self.behaviour[_pref] = []
                    else:
                        self.behaviour[_pref] = None
                continue

            if isinstance(vals, basestring):
                if vals in _pvals:
                    self.behaviour[_pref] = vals
            else:
                vtyp = regreq.c_param[_pref]
                if isinstance(vtyp[0], list):
                    _list = True
                else:
                    _list = False

                for val in vals:
                    if val in _pvals:
                        if not _list:
                            self.behaviour[_pref] = val
                            break
                        else:
                            try:
                                self.behaviour[_pref].append(val)
                            except KeyError:
                                self.behaviour[_pref] = [val]

            if _pref not in self.behaviour:
                raise ConfigurationError(
                    "OP couldn't match preference:%s" % _pref, pcr)

        for key, val in self.client_prefs.items():
            if key in self.behaviour:
                continue

            try:
                vtyp = regreq.c_param[key]
                if isinstance(vtyp[0], list):
                    pass
                elif isinstance(val, list) and not isinstance(val, basestring):
                    val = val[0]
            except KeyError:
                pass
            if key not in PREFERENCE2PROVIDER:
                self.behaviour[key] = val

    def store_registration_info(self, reginfo):
        self.registration_response = reginfo
        if "token_endpoint_auth_method" not in self.registration_response:
            self.registration_response[
                "token_endpoint_auth_method"] = "client_secret_post"
        self.client_secret = reginfo["client_secret"]
        self.client_id = reginfo["client_id"]
        try:
            self.registration_expires = reginfo["client_secret_expires_at"]
        except KeyError:
            pass
        try:
            self.registration_access_token = reginfo[
                "registration_access_token"]
        except KeyError:
            pass

    def handle_registration_info(self, response):
        if response.status_code == 200:
            resp = RegistrationResponse().deserialize(response.text, "json")
            self.store_registration_info(resp)
        else:
            err = ErrorResponse().deserialize(response.text, "json")
            raise PyoidcError("Registration failed: %s" % err.get_json())

        return resp

    def registration_read(self, url="", registration_access_token=None):
        if not url:
            url = self.registration_response["registration_client_uri"]

        if not registration_access_token:
            registration_access_token = self.registration_access_token

        headers = [("Authorization", "Bearer %s" % registration_access_token)]
        rsp = self.http_request(url, "GET", headers=headers)

        return self.handle_registration_info(rsp)

    def create_registration_request(self, **kwargs):
        """
        Create a registration request

        :param kwargs: parameters to the registration request
        :return:
        """
        req = RegistrationRequest()

        for prop in req.parameters():
            try:
                req[prop] = kwargs[prop]
            except KeyError:
                try:
                    req[prop] = self.behaviour[prop]
                except KeyError:
                    pass

        if "post_logout_redirect_uris" not in req:
            try:
                req["post_logout_redirect_uris"] = self.post_logout_redirect_uris
            except AttributeError:
                pass

        if "redirect_uris" not in req:
            try:
                req["redirect_uris"] = self.redirect_uris
            except AttributeError:
                raise MissingRequiredAttribute("redirect_uris", req)

        return req

    def register(self, url, **kwargs):
        """
        Register the client at an OP

        :param url: The OPs registration endpoint
        :param kwargs: parameters to the registration request
        :return:
        """
        req = self.create_registration_request(**kwargs)

        headers = {"content-type": "application/json"}

        rsp = self.http_request(url,
                                "POST",
                                data=req.to_json(),
                                headers=headers)

        return self.handle_registration_info(rsp)

    def normalization(self, principal, idtype="mail"):
        if idtype == "mail":
            (local, domain) = principal.split("@")
            subject = "acct:%s" % principal
        elif idtype == "url":
            p = urlparse.urlparse(principal)
            domain = p.netloc
            subject = principal
        else:
            domain = ""
            subject = principal

        return subject, domain

    def discover(self, principal):
        #subject, host = self.normalization(principal)
        return self.wf.discovery_query(principal)
Example #45
0
class MyFakeOICServer(Server):
    def __init__(self, name=""):
        Server.__init__(self)
        self.sdb = SessionDB(name)
        self.name = name
        self.client = {}
        self.registration_expires_in = 3600
        self.host = ""
        self.webfinger = WebFinger()
        self.userinfo_signed_response_alg = ""

    def http_request(self, path, method="GET", **kwargs):
        part = urlparse(path)
        path = part[2]
        query = part[4]
        self.host = "%s://%s" % (part.scheme, part.netloc)

        response = Response
        response.status_code = 500
        response.text = ""

        if path == ENDPOINT["authorization_endpoint"]:
            assert method == "GET"
            response = self.authorization_endpoint(query)
        elif path == ENDPOINT["token_endpoint"]:
            assert method == "POST"
            response = self.token_endpoint(kwargs["data"])
        elif path == ENDPOINT["user_info_endpoint"]:
            assert method == "POST"
            response = self.userinfo_endpoint(kwargs["data"])
        elif path == ENDPOINT["refresh_session_endpoint"]:
            assert method == "GET"
            response = self.refresh_session_endpoint(query)
        elif path == ENDPOINT["check_session_endpoint"]:
            assert method == "GET"
            response = self.check_session_endpoint(query)
        elif path == ENDPOINT["end_session_endpoint"]:
            assert method == "GET"
            response = self.end_session_endpoint(query)
        elif path == ENDPOINT["registration_endpoint"]:
            if method == "POST":
                response = self.registration_endpoint(kwargs["data"])
        elif path == "/.well-known/webfinger":
            assert method == "GET"
            qdict = parse_qs(query)
            response.status_code = 200
            response.text = self.webfinger.response(qdict["resource"][0],
                                                    "%s/" % self.name)
        elif path == "/.well-known/openid-configuration":
            assert method == "GET"
            response = self.openid_conf()

        return response

    def authorization_endpoint(self, query):
        req = self.parse_authorization_request(query=query)
        aevent = AuthnEvent("user", "salt", authn_info="acr")
        sid = self.sdb.create_authz_session(aevent, areq=req)
        self.sdb.do_sub(sid, "client_salt")
        _info = self.sdb[sid]

        if "code" in req["response_type"]:
            if "token" in req["response_type"]:
                grant = _info["code"]
                if 'offline_access' in _info['scope']:
                    _dict = self.sdb.upgrade_to_token(grant,
                                                      issue_refresh=True)
                else:
                    _dict = self.sdb.upgrade_to_token(grant)
                _dict["oauth_state"] = "authz",

                _dict = by_schema(AuthorizationResponse(), **_dict)
                resp = AuthorizationResponse(**_dict)
                # resp.code = grant
            else:
                _state = req["state"]
                resp = AuthorizationResponse(state=_state, code=_info["code"])

        else:  # "implicit" in req.response_type:
            grant = _info["code"]
            params = AccessTokenResponse.c_param.keys()

            _dict = dict([(k, v)
                          for k, v in self.sdb.upgrade_to_token(grant).items()
                          if k in params])
            try:
                del _dict["refresh_token"]
            except KeyError:
                pass

            if "id_token" in req["response_type"]:
                _idt = self.make_id_token(_info,
                                          issuer=self.name,
                                          access_token=_dict["access_token"])
                alg = "RS256"
                ckey = self.keyjar.get_signing_key(alg2keytype(alg),
                                                   _info["client_id"])
                _dict["id_token"] = _idt.to_jwt(key=ckey, algorithm=alg)

            resp = AccessTokenResponse(**_dict)

        location = resp.request(req["redirect_uri"])
        response = Response()
        response.headers = {"location": location}
        response.status_code = 302
        response.text = ""
        return response

    def token_endpoint(self, data):
        if "grant_type=refresh_token" in data:
            req = self.parse_refresh_token_request(body=data)
            _info = self.sdb.refresh_token(req["refresh_token"],
                                           req['client_id'])
        elif "grant_type=authorization_code" in data:
            req = self.parse_token_request(body=data)
            if 'offline_access' in self.sdb[req['code']]['scope']:
                _info = self.sdb.upgrade_to_token(req["code"],
                                                  issue_refresh=True)
            else:
                _info = self.sdb.upgrade_to_token(req["code"])
        else:
            response = TokenErrorResponse(error="unsupported_grant_type")
            return response, ""

        resp = AccessTokenResponse(**by_schema(AccessTokenResponse, **_info))
        response = Response()
        response.headers = {"content-type": "application/json"}
        response.text = resp.to_json()

        return response

    def userinfo_endpoint(self, data):

        self.parse_user_info_request(data)
        _info = {
            "sub": "melgar",
            "name": "Melody Gardot",
            "nickname": "Mel",
            "email": "*****@*****.**",
            "verified": True,
        }

        resp = OpenIDSchema(**_info)
        response = Response()

        if self.userinfo_signed_response_alg:
            alg = self.userinfo_signed_response_alg
            response.headers = {"content-type": "application/jwt"}
            key = self.keyjar.get_signing_key(alg2keytype(alg), "", alg=alg)
            response.text = resp.to_jwt(key, alg)
        else:
            response.headers = {"content-type": "application/json"}
            response.text = resp.to_json()

        return response

    def registration_endpoint(self, data):
        try:
            req = self.parse_registration_request(data, "json")
        except ValueError:
            req = self.parse_registration_request(data)

        client_secret = rndstr()
        expires = utc_time_sans_frac() + self.registration_expires_in
        kwargs = {}
        if "client_id" not in req:
            client_id = rndstr(10)
            registration_access_token = rndstr(20)
            _client_info = req.to_dict()
            kwargs.update(_client_info)
            _client_info.update({
                "client_secret": client_secret,
                "info": req.to_dict(),
                "expires": expires,
                "registration_access_token": registration_access_token,
                "registration_client_uri": "register_endpoint"
            })
            self.client[client_id] = _client_info
            kwargs["registration_access_token"] = registration_access_token
            kwargs["registration_client_uri"] = "register_endpoint"
            try:
                del kwargs["operation"]
            except KeyError:
                pass
        else:
            client_id = req.client_id
            _cinfo = self.client[req.client_id]
            _cinfo["info"].update(req.to_dict())
            _cinfo["client_secret"] = client_secret
            _cinfo["expires"] = expires

        resp = RegistrationResponse(client_id=client_id,
                                    client_secret=client_secret,
                                    client_secret_expires_at=expires,
                                    **kwargs)

        response = Response()
        response.headers = {"content-type": "application/json"}
        response.text = resp.to_json()

        return response

    def check_session_endpoint(self, query):
        try:
            idtoken = self.parse_check_session_request(query=query)
        except Exception:
            raise

        response = Response()
        response.text = idtoken.to_json()
        response.headers = {"content-type": "application/json"}
        return response

    def refresh_session_endpoint(self, query):
        self.parse_refresh_session_request(query=query)

        resp = RegistrationResponse(client_id="anonymous",
                                    client_secret="hemligt")

        response = Response()
        response.headers = {"content-type": "application/json"}
        response.text = resp.to_json()
        return response

    def end_session_endpoint(self, query):
        try:
            req = self.parse_end_session_request(query=query)
        except Exception:
            raise

        # redirect back
        resp = EndSessionResponse(state=req["state"])

        url = resp.request(req["redirect_url"])

        response = Response()
        response.headers = {"location": url}
        response.status_code = 302  # redirect
        response.text = ""
        return response

    @staticmethod
    def add_credentials(user, passwd):
        pass

    def openid_conf(self):
        endpoint = {}
        for point, path in ENDPOINT.items():
            endpoint[point] = "%s%s" % (self.host, path)

        signing_algs = list(jws.SIGNER_ALGS.keys())
        resp = ProviderConfigurationResponse(
            issuer=self.name,
            scopes_supported=["openid", "profile", "email", "address"],
            identifiers_supported=["public", "PPID"],
            flows_supported=[
                "code", "token", "code token", "id_token", "code id_token",
                "token id_token"
            ],
            subject_types_supported=["pairwise", "public"],
            response_types_supported=[
                "code", "token", "id_token", "code token", "code id_token",
                "token id_token", "code token id_token"
            ],
            jwks_uri="http://example.com/oidc/jwks",
            id_token_signing_alg_values_supported=signing_algs,
            grant_types_supported=["authorization_code", "implicit"],
            **endpoint)

        response = Response()
        response.headers = {"content-type": "application/json"}
        response.text = resp.to_json()
        return response
Example #46
0
 def test_query_rel(self):
     wf = WebFinger()
     query = wf.query("acct:[email protected]",
                      ["http://webfinger.net/rel/profile-page", "vcard"])
     assert query == "https://example.com/.well-known/webfinger?resource=acct%3Abob%40example.com&rel=http%3A%2F%2Fwebfinger.net%2Frel%2Fprofile-page&rel=vcard"
Example #47
0
    def test_query_acct(self):
        wf = WebFinger(OIC_ISSUER)
        query = wf.query("acct:[email protected]")

        assert query == "https://example.com/.well-known/webfinger?resource=acct%3Acarol%40example.com&rel=http%3A%2F%2Fopenid.net%2Fspecs%2Fconnect%2F1.0%2Fissuer"
Example #48
0
import sys
from oic.oauth2 import PBase
from oic.utils.webfinger import WebFinger, OIC_ISSUER

__author__ = 'roland'

wf = WebFinger(OIC_ISSUER)
wf.httpd = PBase()
print(wf.discovery_query(sys.argv[1]))
Example #49
0
#
#      HTTP/1.1 200 OK
#      Access-Control-Allow-Origin *
#      Content-Type: application/jrd+json
#
#      {
#           "subject" : "acct:[email protected]",
#           "links":
#           [{
#               "rel": "http://openid.net/specs/connect/1.0/issuer",
#               "href": "https://openid.example.com"
#           }]
#      }

userid = "*****@*****.**"

wf = WebFinger()
query = wf.query("acct:%s" % userid, rel=OIC_ISSUER)
print query

r = requests.request("GET", query, verify=False)
jwt = json.loads(r.text)
print json.dumps(jwt, sort_keys=True, indent=4, separators=(',', ': '))
print

#########################################################

wf = WebFinger()
wf.httpd = PBase(verify_ssl=False)
url = wf.discovery_query("acct:%s" % userid)
print "The user should be redirected here for login", url
Example #50
0
#!/usr/bin/env python
from oic.oauth2 import PBase
from oic.oic import Client
from oic.utils.webfinger import WebFinger

__author__ = 'roland'


import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-w', dest='webfinger')
parser.add_argument('-p', dest='providerinfo')
cargs = parser.parse_args()

issuer = ""

if cargs.webfinger:
    _httpd = PBase(verify_ssl=False)
    w = WebFinger(httpd=_httpd)
    issuer = w.discovery_query(cargs.webfinger)
    print issuer

if cargs.providerinfo:
    cli = Client(verify_ssl=False)
    if cargs.providerinfo != "-":
        issuer = cargs.providerinfo

    cli.provider_config(issuer)
    print cli.provider_info
Example #51
0
"""
Shows off how you can do OpenID Connect dynamic configuration discovery
"""
import json
import requests

from oic.oic import Client
from oic.oic import OIDCONF_PATTERN
from oic.utils.webfinger import WebFinger
from oic.utils.webfinger import OIC_ISSUER

__author__ = 'roland'

# =============================================================================

wf = WebFinger()
query = wf.query("acct:[email protected]:8060", rel=OIC_ISSUER)

r = requests.request("GET", query, verify=False)

jwt = json.loads(r.text)
url = jwt["links"][0]["href"]

print("Provider:", url)

# Construct the URL used to get the provider configuration
url = OIDCONF_PATTERN % url[:-1]

print("Provider info url:", url)

r = requests.request("GET", url, verify=False)
Example #52
0
class Client(oauth2.Client):
    _endpoints = ENDPOINTS

    def __init__(self, client_id=None, ca_certs=None, grant_expire_in=600,
                 jwt_keys=None, client_timeout=0, client_prefs=None):

        oauth2.Client.__init__(self, client_id, ca_certs, grant_expire_in,
                               client_timeout=client_timeout,
                               jwt_keys=jwt_keys)

        self.file_store = "./file/"
        self.file_uri = "http://localhost/"

        # OpenID connect specific endpoints
        for endpoint in ENDPOINTS:
            setattr(self, endpoint, "")

        self.id_token = None
        self.log = None

        self.request2endpoint = REQUEST2ENDPOINT
        self.response2error = RESPONSE2ERROR
        self.grant_class = Grant
        self.token_class = Token
        self.authn_method = AUTHN_METHOD
        self.provider_info = {}
        self.client_prefs = client_prefs or {}
        self.behaviour = {"require_signed_request_object":
                          DEF_SIGN_ALG["openid_request_object"]}

        self.wf = WebFinger(OIC_ISSUER)
        self.wf.httpd = self

    def _get_id_token(self, **kwargs):
        try:
            return kwargs["id_token"]
        except KeyError:
            grant = self.get_grant(**kwargs)

        if grant:
            try:
                _scope = kwargs["scope"]
            except KeyError:
                _scope = None

            for token in grant.tokens:
                if token.scope and _scope:
                    flag = True
                    for item in _scope:
                        try:
                            assert item in token.scope
                        except AssertionError:
                            flag = False
                            break
                    if not flag:
                        break
                if token.id_token:
                    return token.id_token

        return None

    def construct_AuthorizationRequest(self, request=AuthorizationRequest,
                                       request_args=None, extra_args=None,
                                       **kwargs):

        if request_args is not None:
            for arg in ["idtoken_claims", "userinfo_claims"]:
                if arg in request_args:
                    kwargs[arg] = request_args[arg]
                    del request_args[arg]
            if "nonce" not in request_args:
                _rt = request_args["response_type"]
                if "token" in _rt or "id_token" in _rt:
                    request_args["nonce"] = rndstr(12)
        elif "response_type" in kwargs:
            if "token" in kwargs["response_type"]:
                request_args = {"nonce": rndstr(12)}
        else: # Never wrong to specify a nonce
            request_args = {"nonce": rndstr(12)}

        if "idtoken_claims" in kwargs or "userinfo_claims" in kwargs:
            request_param = "request"
        else:
            request_param = None

        if "request_method" in kwargs:
            if kwargs["request_method"] == "file":
                request_param = "request_uri"
                del kwargs["request_method"]

        areq = oauth2.Client.construct_AuthorizationRequest(self, request,
                                                            request_args,
                                                            extra_args,
                                                            **kwargs)

        if request_param:
            alg = self.behaviour["require_signed_request_object"]
            if "algorithm" not in kwargs:
                kwargs["algorithm"] = alg

            if "keys" not in kwargs and alg:
                atype = alg2keytype(alg)
                kwargs["keys"] = self.keyjar.get_signing_key(atype)

            _req = make_openid_request(areq, **kwargs)

            if request_param == "request":
                areq["request"] = _req
            else:
                _filedir = kwargs["local_dir"]
                _webpath = kwargs["base_path"]
                _name = rndstr(10)
                filename = os.path.join(_filedir, _name)
                while os.path.exists(filename):
                    _name = rndstr(10)
                    filename = os.path.join(_filedir, _name)
                fid = open(filename, mode="w")
                fid.write(_req)
                fid.close()
                _webname = "%s%s" % (_webpath,_name)
                areq["request_uri"] = _webname

        return areq

    #noinspection PyUnusedLocal
    def construct_AccessTokenRequest(self, request=AccessTokenRequest,
                                     request_args=None, extra_args=None,
                                     **kwargs):

        return oauth2.Client.construct_AccessTokenRequest(self, request,
                                                          request_args,
                                                          extra_args, **kwargs)

    def construct_RefreshAccessTokenRequest(self,
                                            request=RefreshAccessTokenRequest,
                                            request_args=None, extra_args=None,
                                            **kwargs):

        return oauth2.Client.construct_RefreshAccessTokenRequest(self, request,
                                                                 request_args,
                                                                 extra_args,
                                                                 **kwargs)

    def construct_UserInfoRequest(self, request=UserInfoRequest,
                                  request_args=None, extra_args=None,
                                  **kwargs):

        if request_args is None:
            request_args = {}

        if "access_token" in request_args:
            pass
        else:
            if "scope" not in kwargs:
                kwargs["scope"] = "openid"
            token = self.get_token(**kwargs)
            if token is None:
                raise Exception("No valid token available")

            request_args["access_token"] = token.access_token

        return self.construct_request(request, request_args, extra_args)

    #noinspection PyUnusedLocal
    def construct_RegistrationRequest(self, request=RegistrationRequest,
                                      request_args=None, extra_args=None,
                                      **kwargs):

        return self.construct_request(request, request_args, extra_args)

    #noinspection PyUnusedLocal
    def construct_RefreshSessionRequest(self,
                                        request=RefreshSessionRequest,
                                        request_args=None, extra_args=None,
                                        **kwargs):

        return self.construct_request(request, request_args, extra_args)

    def _id_token_based(self, request, request_args=None, extra_args=None,
                        **kwargs):

        if request_args is None:
            request_args = {}

        try:
            _prop = kwargs["prop"]
        except KeyError:
            _prop = "id_token"

        if _prop in request_args:
            pass
        else:
            id_token = self._get_id_token(**kwargs)
            if id_token is None:
                raise Exception("No valid id token available")

            request_args[_prop] = id_token

        return self.construct_request(request, request_args, extra_args)

    def construct_CheckSessionRequest(self, request=CheckSessionRequest,
                                      request_args=None, extra_args=None,
                                      **kwargs):

        return self._id_token_based(request, request_args, extra_args, **kwargs)

    def construct_CheckIDRequest(self, request=CheckIDRequest,
                                 request_args=None,
                                 extra_args=None, **kwargs):

        # access_token is where the id_token will be placed
        return self._id_token_based(request, request_args, extra_args,
                                    prop="access_token", **kwargs)

    def construct_EndSessionRequest(self, request=EndSessionRequest,
                                    request_args=None, extra_args=None,
                                    **kwargs):

        if request_args is None:
            request_args = {}

        if "state" in kwargs:
            request_args["state"] = kwargs["state"]
        elif "state" in request_args:
            kwargs["state"] = request_args["state"]

        #        if "redirect_url" not in request_args:
        #            request_args["redirect_url"] = self.redirect_url

        return self._id_token_based(request, request_args, extra_args, 
                                    **kwargs)


    # ------------------------------------------------------------------------

    def authorization_request_info(self, request_args=None, extra_args=None,
                                   **kwargs):
        return self.request_info(AuthorizationRequest, "GET",
                                 request_args, extra_args, **kwargs)

    # ------------------------------------------------------------------------

    def do_authorization_request(self, request=AuthorizationRequest,
                                 state="", body_type="", method="GET",
                                 request_args=None, extra_args=None,
                                 http_args=None,
                                 response_cls=AuthorizationResponse):

        return oauth2.Client.do_authorization_request(self, request, state,
                                                      body_type, method,
                                                      request_args,
                                                      extra_args, http_args,
                                                      response_cls)


    def do_access_token_request(self, request=AccessTokenRequest,
                                scope="", state="", body_type="json",
                                method="POST", request_args=None,
                                extra_args=None, http_args=None,
                                response_cls=AccessTokenResponse,
                                authn_method="", **kwargs):

        return oauth2.Client.do_access_token_request(self, request, scope, state,
                                                     body_type, method,
                                                     request_args, extra_args,
                                                     http_args, response_cls,
                                                     authn_method, **kwargs)

    def do_access_token_refresh(self, request=RefreshAccessTokenRequest,
                                state="", body_type="json", method="POST",
                                request_args=None, extra_args=None,
                                http_args=None,
                                response_cls=AccessTokenResponse,
                                **kwargs):

        return oauth2.Client.do_access_token_refresh(self, request, state,
                                                     body_type, method,
                                                     request_args,
                                                     extra_args, http_args,
                                                     response_cls, **kwargs)

    def do_registration_request(self, request=RegistrationRequest,
                                scope="", state="", body_type="json",
                                method="POST", request_args=None,
                                extra_args=None, http_args=None,
                                response_cls=None):

        url, body, ht_args, csi = self.request_info(request, method=method,
                                                    request_args=request_args,
                                                    extra_args=extra_args,
                                                    scope=scope, state=state)

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(http_args)

        if response_cls is None:
            response_cls = RegistrationResponse

        response = self.request_and_return(url, response_cls, method, body,
                                           body_type, state=state,
                                           http_args=http_args)

        #        if isinstance(response, Message):
        #            if "token_endpoint_auth_type" not in response:
        #                response["token_endpoint_auth_type"] = "client_secret_basic"

        return response

    def do_check_session_request(self, request=CheckSessionRequest,
                                 scope="",
                                 state="", body_type="json", method="GET",
                                 request_args=None, extra_args=None,
                                 http_args=None,
                                 response_cls=IdToken):

        url, body, ht_args, csi = self.request_info(request, method=method,
                                                    request_args=request_args,
                                                    extra_args=extra_args,
                                                    scope=scope, state=state)

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(http_args)

        return self.request_and_return(url, response_cls, method, body,
                                       body_type, state=state,
                                       http_args=http_args)

    def do_check_id_request(self, request=CheckIDRequest, scope="",
                            state="", body_type="json", method="GET",
                            request_args=None, extra_args=None,
                            http_args=None,
                            response_cls=IdToken):

        url, body, ht_args, csi = self.request_info(request, method=method,
                                                    request_args=request_args,
                                                    extra_args=extra_args,
                                                    scope=scope, state=state)

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(http_args)

        return self.request_and_return(url, response_cls, method, body,
                                       body_type, state=state,
                                       http_args=http_args)

    def do_end_session_request(self, request=EndSessionRequest, scope="",
                               state="", body_type="", method="GET",
                               request_args=None, extra_args=None,
                               http_args=None, response_cls=None):

        url, body, ht_args, csi = self.request_info(request, method=method,
                                                    request_args=request_args,
                                                    extra_args=extra_args,
                                                    scope=scope, state=state)

        if http_args is None:
            http_args = ht_args
        else:
            http_args.update(http_args)

        return self.request_and_return(url, response_cls, method, body,
                                       body_type, state=state,
                                       http_args=http_args)

    def user_info_request(self, method="GET", state="", scope="", **kwargs):
        uir = UserInfoRequest()
        logger.debug("[user_info_request]: kwargs:%s" % (kwargs,))
        if "token" in kwargs:
            if kwargs["token"]:
                uir["access_token"] = kwargs["token"]
                token = Token()
                token.type = "Bearer"
                token.access_token = kwargs["token"]
                kwargs["behavior"] = "use_authorization_header"
            else:
                # What to do ? Need a callback
                token = None
        elif "access_token" in kwargs and kwargs["access_token"]:
            uir["access_token"] = kwargs["access_token"]
            del kwargs["access_token"]
            token = None
        else:
            token = self.grant[state].get_token(scope)

            if token.is_valid():
                uir["access_token"] = token.access_token
            else:
                # raise oauth2.OldAccessToken
                if self.log:
                    self.log.info("do access token refresh")
                try:
                    self.do_access_token_refresh(token=token)
                    token = self.grant[state].get_token(scope)
                    uir["access_token"] = token.access_token
                except Exception:
                    raise

        try:
            uir["schema"] = kwargs["schema"]
        except KeyError:
            pass

        uri = self._endpoint("userinfo_endpoint", **kwargs)
        # If access token is a bearer token it might be sent in the
        # authorization header
        # 3-ways of sending the access_token:
        # - POST with token in authorization header
        # - POST with token in message body
        # - GET with token in authorization header
        if "behavior" in kwargs:
            _behav = kwargs["behavior"]
            # use_authorization_header, token_in_message_body
            if "use_authorization_header" in _behav and token.type == "Bearer":
                bh = "Bearer %s" % token.access_token
                if "headers" in kwargs:
                    kwargs["headers"]= {"Authorization": bh}
                else:
                    kwargs["headers"] = {"Authorization": bh}
            if not "token_in_message_body" in _behav:
                # remove the token from the request
                del uir["access_token"]

        path, body, kwargs = self.get_or_post(uri, method, uir, **kwargs)

        h_args = dict([(k, v) for k,v in kwargs.items() if k in HTTP_ARGS])

        return path, body, method, h_args

    def do_user_info_request(self, method="POST", state="", scope="openid",
                             request="openid", **kwargs):

        kwargs["request"] = request
        path, body, method, h_args = self.user_info_request(method, state,
                                                            scope, **kwargs)

        logger.debug("[do_user_info_request] PATH:%s BODY:%s H_ARGS: %s" % (
                                                        path, body, h_args))

        try:
            resp = self.http_request(path, method, data=body, **h_args)
        except oauth2.MissingRequiredAttribute:
            raise

        if resp.status_code == 200:
            try:
                assert "application/json" in resp.headers["content-type"]
                format = "json"
            except AssertionError:
                assert "application/jwt" in resp.headers["content-type"]
                format = "jwt"
        elif resp.status_code == 500:
            raise Exception("ERROR: Something went wrong: %s" % resp.text)
        else:
            raise Exception("ERROR: Something went wrong [%s]: %s" % (
                                                            resp.status_code,
                                                            resp.text))

        if format == "json":
            return OpenIDSchema().from_json(txt=resp.text)
        else:
            algo = self.client_prefs["userinfo_signed_response_alg"]
            # Keys of the OP ?
            keys = self.keyjar.get_signing_key(alg2keytype(algo))
            return OpenIDSchema().from_jwt(resp.text, keys)

    def get_userinfo_claims(self, access_token, endpoint, method="POST",
                            schema_class=OpenIDSchema, **kwargs):

        uir = UserInfoRequest(access_token=access_token)
        try:
            uir["schema"] = kwargs["schema"]
        except KeyError:
            pass


        h_args = dict([(k, v) for k,v in kwargs.items() if k in HTTP_ARGS])

        if "authn_method" in kwargs:
            http_args = self.init_authentication_method(**kwargs)
        else:
            # If nothing defined this is the default
            http_args = self.init_authentication_method(uir, "bearer_header",
                                                        **kwargs)

        h_args.update(http_args)
        path, body, kwargs = self.get_or_post(endpoint, method, uir, **kwargs)

        try:
            resp = self.http_request(path, method, data=body, **h_args)
        except oauth2.MissingRequiredAttribute:
            raise

        if resp.status_code == 200:
            assert "application/json" in resp.headers["content-type"]
        elif resp.status_code == 500:
            raise Exception("ERROR: Something went wrong: %s" % resp.text)
        else:
            raise Exception("ERROR: Something went wrong [%s]" % resp.status_code)

        return schema_class().from_json(txt=resp.text)

    def provider_config(self, issuer, keys=True, endpoints=True):
        if issuer.endswith("/"):
            _issuer = issuer[:-1]
        else:
            _issuer = issuer

        url = OIDCONF_PATTERN % _issuer

        pcr = None
        r = self.http_request(url)
        if r.status_code == 200:
            pcr = ProviderConfigurationResponse().from_json(r.text)
        elif r.status_code == 302:
            while r.status_code == 302:
                r = self.http_request(r.headers["location"])
                if r.status_code == 200:
                    pcr = ProviderConfigurationResponse().from_json(r.text)
                    break

        if pcr is None:
            raise Exception("Trying '%s', status %s" % (url, r.status_code))

        if "issuer" in pcr:
            _pcr_issuer = pcr["issuer"]
            if pcr["issuer"].endswith("/"):
                if issuer.endswith("/"):
                    _issuer = issuer
                else:
                    _issuer = issuer + "/"
            else:
                if issuer.endswith("/"):
                    _issuer = issuer[:-1]
                else:
                    _issuer = issuer

            try:
                assert _issuer == _pcr_issuer
            except AssertionError:
                raise Exception("provider info issuer mismatch '%s' != '%s'" % (
                    _issuer, _pcr_issuer))

            self.provider_info[_pcr_issuer] = pcr
        else:
            _pcr_issuer = issuer

        if endpoints:
            for key, val in pcr.items():
                if key.endswith("_endpoint"):
                    setattr(self, key, val)

        if keys:
            self.keyjar.load_keys(pcr, _pcr_issuer)

        return pcr

    def unpack_aggregated_claims(self, userinfo):
        if userinfo._claim_sources:
            for csrc, spec in userinfo._claim_sources.items():
                if "JWT" in spec:
                    if not csrc in self.keyjar:
                        self.provider_config(csrc, endpoints=False)

                    keycol = self.keyjar.get_verify_key(owner=csrc)
                    for typ, keyl in self.keyjar.get_verify_key().items():
                        try:
                            keycol[typ].extend(keyl)
                        except KeyError:
                            keycol[typ] = keyl

                    info = json.loads(jws.verify(str(spec["JWT"]), keycol))
                    attr = [n for n, s in userinfo._claim_names.items() if s ==
                                                                           csrc]
                    assert attr == info.keys()

                    for key, vals in info.items():
                        userinfo[key] = vals

        return userinfo

    def fetch_distributed_claims(self, userinfo, callback=None):
        for csrc, spec in userinfo._claim_sources.items():
            if "endpoint" in spec:
                #pcr = self.provider_config(csrc, keys=False, endpoints=False)

                if "access_token" in spec:
                    _uinfo = self.do_user_info_request(
                        token=spec["access_token"],
                        userinfo_endpoint=spec["endpoint"])
                else:
                    _uinfo = self.do_user_info_request(token=callback(csrc),
                                                       userinfo_endpoint=spec["endpoint"])

                attr = [n for n, s in userinfo._claim_names.items() if s ==
                                                                       csrc]
                assert attr == _uinfo.keys()

                for key, vals in _uinfo.items():
                    userinfo[key] = vals

        return userinfo

    def verify_alg_support(self, alg, usage, other):
        """
        Verifies that the algorithm to be used are supported by the other side.

        :param alg: The algorithm specification
        :param usage: In which context the 'alg' will be used.
            The following values are supported:
            - userinfo
            - id_token
            - request_object
            - token_endpoint_auth
        :param other: The identifier for the other side
        :return: True or False
        """

        try:
            _pcr = self.provider_info[other]
            supported = _pcr["%s_algs_supported" % usage]
        except KeyError:
            try:
                supported = getattr(self, "%s_algs_supported" % usage)
            except AttributeError:
                supported = None

        if supported is None:
            return True
        else:
            if alg in supported:
                return True
            else:
                return False

    def match_preferences(self, pcr=None, issuer=None):
        """
        Match the clients preferences against what the provider can do.

        :param pcr: Provider configuration response if available
        :param issuer: The issuer identifier
        """
        if not pcr:
            pcr = self.provider_info[issuer]

        for _pref, _prov in PREFERENCE2PROVIDER.items():
            try:
                vals = self.client_prefs[_pref]
            except KeyError:
                continue

            try:
                _pvals = pcr[_prov]
            except KeyError:
                try:
                    self.behaviour[_pref] = PROVIDER_DEFAULT[_pref]
                except KeyError:
                    #self.behaviour[_pref]= vals[0]
                    self.behaviour[_pref] = None
                continue

            for val in vals:
                if val in _pvals:
                    self.behaviour[_pref]= val
                    break

            if _pref not in self.behaviour:
                raise ConfigurationError(
                    "OP couldn't match preferences",
                                         "%s" % _pref)

        for key, val in self.client_prefs.items():
            if key not in PREFERENCE2PROVIDER:
                self.behaviour[key] = val

    def register(self, url, operation="register", application_type="web",
                 **kwargs):
        req = RegistrationRequest(operation=operation,
                                  application_type=application_type)

        if operation == "update":
            req["client_id"] = self.client_id
            req["client_secret"] = self.client_secret

        for prop in req.parameters():
            if prop in ["operation", "client_id", "client_secret"]:
                continue

            try:
                req[prop] = kwargs[prop]
            except KeyError:
                try:
                    req[prop] = self.behaviour[prop]
                except KeyError:
                    pass

        if "redirect_uris" not in req:
            try:
                req["redirect_uris"] = self.redirect_uris
            except AttributeError:
                raise MissingRequiredAttribute("redirect_uris")

        headers = {"content-type": "application/x-www-form-urlencoded"}

        if operation == "client_update":
            headers["Authorization"] = "Bearer %s" % self.registration_access_token

        rsp = self.http_request(url, "POST", data=req.to_urlencoded(),
                                headers=headers)

        if rsp.status_code == 200:
            resp = RegistrationResponse().deserialize(rsp.text, "json")
            self.client_secret = resp["client_secret"]
            self.client_id = resp["client_id"]
            self.registration_expires = resp["expires_at"]
            self.registration_access_token = resp["registration_access_token"]
        else:
            err = ErrorResponse().deserialize(rsp.text, "json")
            raise Exception("Registration failed: %s" % err.get_json())

        return resp


    def normalization(self, principal, idtype="mail"):
        if idtype == "mail":
            (local, domain) = principal.split("@")
            subject = "acct:%s" % principal
        elif idtype == "url":
            p = urlparse.urlparse(principal)
            domain = p.netloc
            subject = principal
        else:
            domain = ""
            subject = principal

        return subject, domain

    def discover(self, principal):
        subject, host = self.normalization(principal)
        return self.wf.discovery_query(host, subject)
Example #53
0
import sys

from oic.oauth2 import PBase
from oic.utils.webfinger import OIC_ISSUER
from oic.utils.webfinger import WebFinger

__author__ = 'roland'

wf = WebFinger(OIC_ISSUER)
wf.httpd = PBase()
print (wf.discovery_query(sys.argv[1]))
Example #54
0
"""
Code to show how you can use WebFinger to aquire the issuer ID
of an OpenID Connect provider using an account id
"""
import json
from oic.oauth2 import PBase
import requests
from oic.utils.webfinger import WebFinger, OIC_ISSUER

__author__ = 'roland'

# =====================================================================
# Using only very basic functions and methods

# Initiate the WebFinger class
wf = WebFinger()

# contruct the webfinger query URL
query = wf.query("acct:[email protected]", rel=OIC_ISSUER)

print(query)

r = requests.request("GET", query, verify=False)

# parse the JSON returned by the website and dump the content to
# standard out
jwt = json.loads(r.text)
print(json.dumps(jwt, sort_keys=True, indent=4, separators=(',', ': ')))

# =====================================================================
# A bit more high level
Example #55
0
#!/usr/bin/env python
from oic.oauth2 import PBase
from oic.oic import Client
from oic.utils.webfinger import WebFinger

__author__ = 'roland'

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-w', dest='webfinger')
parser.add_argument('-p', dest='providerinfo')
cargs = parser.parse_args()

issuer = ""

if cargs.webfinger:
    _httpd = PBase(verify_ssl=False)
    w = WebFinger(httpd=_httpd)
    issuer = w.discovery_query(cargs.webfinger)
    print issuer

if cargs.providerinfo:
    cli = Client(verify_ssl=False)
    if cargs.providerinfo != "-":
        issuer = cargs.providerinfo

    cli.provider_config(issuer)
    print cli.provider_info
Example #56
0
 def test_query_device(self):
     wf = WebFinger()
     query = wf.query(resource="device:p1.example.com")
     assert query == 'https://p1.example.com/.well-known/webfinger?resource=device%3Ap1.example.com'
Example #57
0
class MyFakeOICServer(Server):
    def __init__(self, name=""):
        Server.__init__(self)
        self.sdb = SessionDB()
        self.name = name
        self.client = {}
        self.registration_expires_in = 3600
        self.host = ""
        self.webfinger = WebFinger()

    #noinspection PyUnusedLocal
    def http_request(self, path, method="GET", **kwargs):
        part = urlparse(path)
        path = part[2]
        query = part[4]
        self.host = "%s://%s" % (part.scheme, part.netloc)

        response = Response
        response.status_code = 500
        response.text = ""

        if path == ENDPOINT["authorization_endpoint"]:
            assert method == "GET"
            response = self.authorization_endpoint(query)
        elif path == ENDPOINT["token_endpoint"]:
            assert method == "POST"
            response = self.token_endpoint(kwargs["data"])
        elif path == ENDPOINT["user_info_endpoint"]:
            assert method == "POST"
            response = self.userinfo_endpoint(kwargs["data"])
        elif path == ENDPOINT["refresh_session_endpoint"]:
            assert method == "GET"
            response = self.refresh_session_endpoint(query)
        elif path == ENDPOINT["check_session_endpoint"]:
            assert method == "GET"
            response = self.check_session_endpoint(query)
        elif path == ENDPOINT["end_session_endpoint"]:
            assert method == "GET"
            response = self.end_session_endpoint(query)
        elif path == ENDPOINT["registration_endpoint"]:
            if method == "POST":
                response = self.registration_endpoint(kwargs["data"])
        elif path == "/.well-known/webfinger":
            assert method == "GET"
            qdict = parse_qs(query)
            response.status_code = 200
            response.text = self.webfinger.response(qdict["resource"][0],
                                                    "%s/" % self.name)
        elif path == "/.well-known/openid-configuration":
            assert method == "GET"
            response = self.openid_conf()

        return response

    def authorization_endpoint(self, query):
        req = self.parse_authorization_request(query=query)
        sid = self.sdb.create_authz_session(sub="user", areq=req)
        _info = self.sdb[sid]
        _info["sub"] = _info["local_sub"]

        if "code" in req["response_type"]:
            if "token" in req["response_type"]:
                grant = _info["code"]
                _dict = self.sdb.upgrade_to_token(grant)
                _dict["oauth_state"] = "authz",

                _dict = by_schema(AuthorizationResponse(), **_dict)
                resp = AuthorizationResponse(**_dict)
                #resp.code = grant
            else:
                resp = AuthorizationResponse(state=req["state"],
                                             code=_info["code"])

        else:  # "implicit" in req.response_type:
            grant = _info["code"]
            params = AccessTokenResponse.c_param.keys()

            _dict = dict([(k, v) for k, v in
                          self.sdb.upgrade_to_token(grant).items() if k in
                                                                     params])
            try:
                del _dict["refresh_token"]
            except KeyError:
                pass

            if "id_token" in req["response_type"]:
                _idt = self.make_id_token(_info, issuer=self.name,
                                          access_token=_dict["access_token"])
                alg = "RS256"
                ckey = self.keyjar.get_signing_key(alg2keytype(alg),
                                                   _info["client_id"])
                _dict["id_token"] = _idt.to_jwt(key=ckey, algorithm=alg)

            resp = AccessTokenResponse(**_dict)

        location = resp.request(req["redirect_uri"])
        response = Response()
        response.headers = {"location": location}
        response.status_code = 302
        response.text = ""
        return response

    def token_endpoint(self, data):
        if "grant_type=refresh_token" in data:
            req = self.parse_refresh_token_request(body=data)
            _info = self.sdb.refresh_token(req["refresh_token"])
        elif "grant_type=authorization_code":
            req = self.parse_token_request(body=data)
            _info = self.sdb.upgrade_to_token(req["code"])
        else:
            response = TokenErrorResponse(error="unsupported_grant_type")
            return response, ""

        resp = AccessTokenResponse(**by_schema(AccessTokenResponse, **_info))
        response = Response()
        response.headers = {"content-type": "application/json"}
        response.text = resp.to_json()

        return response

    def userinfo_endpoint(self, data):

        _ = self.parse_user_info_request(data)
        _info = {
            "sub": "melgar",
            "name": "Melody Gardot",
            "nickname": "Mel",
            "email": "*****@*****.**",
            "verified": True,
        }

        resp = OpenIDSchema(**_info)
        response = Response()
        response.headers = {"content-type": "application/json"}
        response.text = resp.to_json()

        return response

    def registration_endpoint(self, data):
        try:
            req = self.parse_registration_request(data, "json")
        except ValueError:
            req = self.parse_registration_request(data)

        client_secret = rndstr()
        expires = utc_time_sans_frac() + self.registration_expires_in
        kwargs = {}
        if "client_id" not in req:
            client_id = rndstr(10)
            registration_access_token = rndstr(20)
            _client_info = req.to_dict()
            kwargs.update(_client_info)
            _client_info.update({
                "client_secret": client_secret,
                "info": req.to_dict(),
                "expires": expires,
                "registration_access_token": registration_access_token,
                "registration_client_uri": "register_endpoint"
            })
            self.client[client_id] = _client_info
            kwargs["registration_access_token"] = registration_access_token
            kwargs["registration_client_uri"] = "register_endpoint"
            try:
                del kwargs["operation"]
            except KeyError:
                pass
        else:
            client_id = req.client_id
            _cinfo = self.client[req.client_id]
            _cinfo["info"].update(req.to_dict())
            _cinfo["client_secret"] = client_secret
            _cinfo["expires"] = expires

        resp = RegistrationResponse(client_id=client_id,
                                    client_secret=client_secret,
                                    client_secret_expires_at=expires,
                                    **kwargs)

        response = Response()
        response.headers = {"content-type": "application/json"}
        response.text = resp.to_json()

        return response

    def check_session_endpoint(self, query):
        try:
            idtoken = self.parse_check_session_request(query=query)
        except Exception:
            raise

        response = Response()
        response.text = idtoken.to_json()
        response.headers = {"content-type": "application/json"}
        return response

    #noinspection PyUnusedLocal
    def refresh_session_endpoint(self, query):
        try:
            req = self.parse_refresh_session_request(query=query)
        except Exception:
            raise

        resp = RegistrationResponse(client_id="anonymous",
                                    client_secret="hemligt")

        response = Response()
        response.headers = {"content-type": "application/json"}
        response.text = resp.to_json()
        return response

    def end_session_endpoint(self, query):
        try:
            req = self.parse_end_session_request(query=query)
        except Exception:
            raise

        # redirect back
        resp = EndSessionResponse(state=req["state"])

        url = resp.request(req["redirect_url"])

        response = Response()
        response.headers = {"location": url}
        response.status_code = 302  # redirect
        response.text = ""
        return response

    #noinspection PyUnusedLocal
    def add_credentials(self, user, passwd):
        return

    def openid_conf(self):
        endpoint = {}
        for point, path in ENDPOINT.items():
            endpoint[point] = "%s%s" % (self.host, path)

        signing_algs = jws.SIGNER_ALGS.keys()
        resp = ProviderConfigurationResponse(
            issuer=self.name,
            scopes_supported=["openid", "profile", "email", "address"],
            identifiers_supported=["public", "PPID"],
            flows_supported=["code", "token", "code token", "id_token",
                             "code id_token", "token id_token"],
            subject_types_supported=["pairwise", "public"],
            response_types_supported=["code", "token", "id_token",
                                      "code token", "code id_token",
                                      "token id_token", "code token id_token"],
            jwks_uri="http://example.com/oidc/jwks",
            id_token_signing_alg_values_supported=signing_algs,
            grant_types_supported=["authorization_code", "implicit"],
            **endpoint)

        response = Response()
        response.headers = {"content-type": "application/json"}
        response.text = resp.to_json()
        return response
Example #58
0
def application(environ, start_response):
    session = environ['beaker.session']
    rpSession = RpSession(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 == "logout":
        try:
            logoutUrl = rpSession.getClient().endsession_endpoint
            logoutUrl += "?" + urllib.urlencode({"post_logout_redirect_uri": SERVER_ENV["base_url"]})
            try:
                logoutUrl += "&" + urllib.urlencode({"id_token_hint": id_token_as_signed_jwt(rpSession.getClient(), "HS256")})
            except:
                pass
            rpSession.clearSession()
            resp = Redirect(str(logoutUrl))
            return resp(environ, start_response)
        except:
            pass

    if rpSession.getCallback():
        for key, _dict in rp_conf.SERVICE.items():
            if "opKey" in _dict and _dict["opKey"] == path:
                rpSession.setCallback(False)
                func = getattr(rp_conf.SERVICE[key]["instance"], "callback")
                return func(environ, SERVER_ENV, start_response, query, rpSession)

    if path == "rpAcr" and "key" in query and query["key"][0] in rp_conf.SERVICE:
        return chooseAcrValue(environ, start_response, rpSession, query["key"][0])

    if path == "rpAuth":    #Only called if multiple arc_values (that is authentications) exists.
        if "acr" in query and query["acr"][0] in rpSession.getAcrvalues() and \
                        "key" in query and query["key"][0] in rp_conf.SERVICE:
            func = getattr(rp_conf.SERVICE[query["key"][0]]["instance"], "create_authnrequest")
            return func(environ, SERVER_ENV, start_response, rpSession, query["acr"][0])

    if rpSession.getClient() is not None:
        rpSession.setCallback(True)
        func = getattr(rp_conf.SERVICE[rpSession.getService()]["instance"], "begin")
        return func(environ, SERVER_ENV, start_response, rpSession)

    if path == "rp":
        if "key" in query:
            print "key"
            key = query["key"][0]
            if key in rp_conf.SERVICE:
                rpSession.setCallback(True)
                func = getattr(rp_conf.SERVICE[key]["instance"], "begin")
                return func(environ, SERVER_ENV, start_response, rpSession)

        if "uid" in query:
            print "uid"
            _val = URINormalizer().normalize(query["uid"][0])
            wf = WebFinger(httpd=Httpd())
            link = wf.discovery_query(resource=_val)
            #requests.get(url, verify=True)
            md5 = hashlib.md5()
            md5.update(link)
            opkey = base64.b16encode(md5.digest())
            kwargs = {'opKey': opkey,
                      'description': 'OIDC server with discovery url: ' + link,
                      'class': pyoidcOIC,
                      'srv_discovery_url': link,
                      'scope': ["openid", "profile", "email", "address",
                                "phone"],
                      'name': link}
            rp_conf.SERVICE[opkey] = kwargs
            rp_conf.SERVICE[opkey]["instance"] = pyoidcOIC(None, None, **kwargs)
            rpSession.setCallback(True)
            func = getattr(rp_conf.SERVICE[opkey]["instance"], "begin")
            return func(environ, SERVER_ENV, start_response, rpSession)

    if path == "opbyuid":
        return opbyuid(environ, start_response)
    if path == "oplist":
        return oplist(environ, start_response)
    if path == "about":
        return about(environ, start_response)

    return start(environ, start_response)
Example #59
0
 def test_query_device(self):
     wf = WebFinger()
     query = wf.query(resource="device:p1.example.com")
     assert query == 'https://p1.example.com/.well-known/webfinger?resource=device%3Ap1.example.com'
Example #60
0
#!/usr/bin/env python

import json
import requests
from oic.oauth2 import PBase
from oic.oic import OIDCONF_PATTERN
from oic.utils.webfinger import WebFinger

# This is a complete discovery example with OpenID Connect. After having retrieved the provide URL, its information
# is retrieved and printed. The standard URL format for obtaining OP information is:
# https://<op.servername>/.well-known/openid-configuration

userid = "[email protected]:8060"
wf = WebFinger()
wf.httpd = PBase(verify_ssl=False)
url = wf.discovery_query("acct:%s" % userid)

print "Provider:", url

if url[-1] == '/': url = url[:-1]
url = OIDCONF_PATTERN % url

print "Provider info url:", url

r = requests.request("GET", url, verify=False)

jwt = json.loads(r.text)
print "---- provider configuration info ----"
print json.dumps(jwt, sort_keys=True, indent=4, separators=(',', ': '))