Esempio n. 1
0
def left_hash(msg, func="HS256"):
    """ 128 bits == 16 bytes """
    if func == 'HS256':
        return as_unicode(b64e(sha256_digest(msg)[:16]))
    elif func == 'HS384':
        return as_unicode(b64e(sha384_digest(msg)[:24]))
    elif func == 'HS512':
        return as_unicode(b64e(sha512_digest(msg)[:32]))
Esempio n. 2
0
def verify_self_signed_jwks(sjwt):
    """
    Verify the signature of a signed JWT containing a JWKS.
    The JWT is signed by one of the keys in the JWKS. 
    In the JWT the JWKS is stored using this format ::
    
        'jwks': {
            'keys': [ ]
        }

    :param sjwt: Signed Jason Web Token
    :return: Dictionary containing 'jwks' (the JWKS) and 'iss' (the issuer of 
        the JWT)
    """

    _jws = factory(sjwt)
    _json = _jws.jwt.part[1]
    _body = json.loads(as_unicode(_json))
    iss = _body['iss']
    _jwks = _body['jwks']

    _kj = jwks_to_keyjar(_jwks, iss)

    try:
        _kid = _jws.jwt.headers['kid']
    except KeyError:
        _keys = _kj.get_signing_key(owner=iss)
    else:
        _keys = _kj.get_signing_key(owner=iss, kid=_kid)

    _ver = _jws.verify_compact(sjwt, _keys)
    return {'jwks': _ver['jwks'], 'iss': iss}
    def thumbprint(self, hash_function, members=None):
        """
        Create a thumbprint of the key following the outline in
        https://tools.ietf.org/html/draft-jones-jose-jwk-thumbprint-01

        :param hash_function: A hash function to use for hashing the
            information
        :param members: Which attributes of the Key instance that should
            be included when computing the hash value.
        :return: A base64 encode hash over a set of Key attributes
        """
        if members is None:
            members = self.required

        members.sort()
        ser = self.serialize()
        _se = []
        for elem in members:
            try:
                _val = ser[elem]
            except KeyError:  # should never happen with the required set
                pass
            else:
                if isinstance(_val, bytes):
                    _val = as_unicode(_val)
                _se.append('"{}":{}'.format(elem, json.dumps(_val)))
        _json = '{{{}}}'.format(','.join(_se))

        return b64e(DIGEST_HASH[hash_function](_json))
Esempio n. 4
0
def post_parse_request(request, client_id, endpoint_context, **kwargs):
    """
    Expect http_info attribute in kwargs. http_info should be a dictionary
    containing HTTP information.

    :param request:
    :param client_id:
    :param endpoint_context:
    :param kwargs:
    :return:
    """

    _http_info = kwargs.get("http_info")
    if not _http_info:
        return request

    _dpop = DPoPProof().verify_header(_http_info["headers"]["dpop"])

    # The signature of the JWS is verified, now for checking the
    # content

    if _dpop["htu"] != _http_info["url"]:
        raise ValueError("htu in DPoP does not match the HTTP URI")

    if _dpop["htm"] != _http_info["method"]:
        raise ValueError("htm in DPoP does not match the HTTP method")

    if not _dpop.key:
        _dpop.key = key_from_jwk_dict(_dpop["jwk"])

    # Need something I can add as a reference when minting tokens
    request["dpop_jkt"] = as_unicode(_dpop.key.thumbprint("SHA-256"))
    return request
    def encryption_key(self, alg, **kwargs):
        """
        Return an encryption key as per
        http://openid.net/specs/openid-connect-core-1_0.html#Encryption

        :param alg: encryption algorithm
        :param kwargs:
        :return: encryption key as byte string
        """
        if not self.key:
            self.deserialize()

        tsize = ALG2KEYLEN[alg]
        # _keylen = len(self.key)

        if tsize <= 32:
            # SHA256
            _enc_key = sha256_digest(self.key)[:tsize]
        elif tsize <= 48:
            # SHA384
            _enc_key = sha384_digest(self.key)[:tsize]
        elif tsize <= 64:
            # SHA512
            _enc_key = sha512_digest(self.key)[:tsize]
        else:
            raise JWKException("No support for symmetric keys > 512 bits")

        logger.debug('Symmetric encryption key: {}'.format(
            as_unicode(b64e(_enc_key))))

        return _enc_key
Esempio n. 6
0
def get_sub(token):
    _jwt = factory(token)

    if _jwt:
        return json.loads(as_unicode(_jwt.jwt.part[1]))['sub']
    else:
        return ''
def get_jwt_keys(jwt, keys, use):
    try:
        if use == 'sig':
            _key_type = jws.alg2keytype(jwt.headers['alg'])
        else:
            _key_type = jwe.alg2keytype(jwt.headers['alg'])
    except KeyError:
        _key_type = ''

    try:
        _kid = jwt.headers['kid']
    except KeyError:
        _kid = ''  # Unknown

    # pick issuer keys
    if use == 'sig':
        payload = json.loads(as_unicode(jwt.part[1]))
        try:
            _keys = keys[payload['iss']]
        except KeyError:  # No issuer, not kosher
            raise MissingValue('iss')
        if not _kid:
            try:
                _kid = payload['kid']
            except KeyError:
                _kid = ''  # Unknown
    else:
        _keys = keys

    return pick_key(_keys, use, key_type=_key_type, kid=_kid)
Esempio n. 8
0
    def dump_attr(self,
                  cls,
                  item,
                  exclude_attributes: Optional[List[str]] = None) -> dict:
        if cls in [None, 0, "", [], {}, bool, b'']:
            if cls == b'':
                val = as_unicode(item)
            else:
                val = item
        elif cls == "DICT_TYPE":
            if isinstance(item, dict):
                val = item
            else:
                if isinstance(item,
                              DictType):  # item should be a class instance
                    val = {
                        "DICT_TYPE": {
                            "class": fully_qualified_name(item),
                            "kwargs": item.kwargs
                        }
                    }
                else:
                    raise ValueError("Expected a DictType class")
        elif isinstance(item, Message):
            val = {qualified_name(item.__class__): item.to_dict()}
        elif cls == object:
            val = qualified_name(item)
        elif isinstance(cls, list):
            val = [self.dump_attr(cls[0], v, exclude_attributes) for v in item]
        else:
            val = item.dump(exclude_attributes=exclude_attributes)

        return val
Esempio n. 9
0
def test_client_secret_basic():
    _token = '{}:{}'.format(client_id, client_secret)
    token = as_unicode(base64.b64encode(as_bytes(_token)))

    authz_token = 'Basic {}'.format(token)

    authn_info = ClientSecretBasic(endpoint_context).verify({}, authz_token)

    assert authn_info['client_id'] == client_id
Esempio n. 10
0
    def val_hash(self, alg):
        halg = "HS%s" % alg[-3:]

        for attr, hash_attr in self.hashable.items():
            try:
                self[hash_attr] = left_hash(as_unicode(self[attr]), halg)
            except KeyError:
                pass
            else:
                del self[attr]
    def test_parse_with_wrong_client_authn(self):
        _context = self.introspection_endpoint.endpoint_context
        _token = self._create_at("diana")
        _basic_token = "{}:{}".format(
            "client_1", _context.cdb["client_1"]["client_secret"])
        _basic_token = as_unicode(base64.b64encode(as_bytes(_basic_token)))
        _basic_authz = "Basic {}".format(_basic_token)

        with pytest.raises(UnAuthorizedClient):
            self.introspection_endpoint.parse_request({"token": _token},
                                                      _basic_authz)
Esempio n. 12
0
    def test_parse_with_wrong_client_authn(self):
        _context = self.introspection_endpoint.endpoint_context
        _ = setup_session(_context, AUTH_REQ, uid="diana")
        _token = self._create_jwt("diana")
        _basic_token = "{}:{}".format(
            "client_1", _context.cdb["client_1"]["client_secret"])
        _basic_token = as_unicode(base64.b64encode(as_bytes(_basic_token)))
        _basic_authz = "Basic {}".format(_basic_token)

        with pytest.raises(WrongAuthnMethod):
            self.introspection_endpoint.parse_request({"token": _token},
                                                      _basic_authz)
Esempio n. 13
0
def parse_cookie(name, seed, kaka, enc_key=None):
    """Parses and verifies a cookie value

    Parses a cookie created by `make_cookie` and verifies
    it has not been tampered with.

    You need to provide the same `seed` and `enc_key`
    used when creating the cookie, otherwise the verification
    fails. See `make_cookie` for details about the verification.

    :param seed: A seed key used for the HMAC signature
    :type seed: bytes
    :param kaka: The cookie
    :param enc_key: The encryption key used.
    :type enc_key: bytes or None
    :raises InvalidCookieSign: When verification fails.
    :return: A tuple consisting of (payload, timestamp) or None if parsing fails
    """
    if not kaka:
        return None

    seed = as_unicode(seed)

    parts = cookie_parts(name, kaka)
    if parts is None:
        return None
    elif len(parts) == 3:
        # verify the cookie signature
        cleartext, timestamp, sig = parts
        if not verify_cookie_signature(sig, seed, cleartext, timestamp):
            raise InvalidCookieSign()
        return cleartext, timestamp
    elif len(parts) == 4:
        # encrypted and signed
        timestamp = parts[0]
        iv = base64.b64decode(parts[1])
        ciphertext = base64.b64decode(parts[2])
        tag = base64.b64decode(parts[3])
        ct = ciphertext + tag

        # Make sure the key is 32-Bytes long
        key = _make_hashed_key((enc_key, seed))
        aesgcm = AESGCM(key)

        # timestamp does not need to be encrypted, just MAC'ed,
        # so we add it to 'Associated Data' only.
        aad = timestamp.encode('utf-8')
        try:
            cleartext = aesgcm.decrypt(iv, ct, aad)
        except JWEException:
            raise InvalidCookieSign()
        return cleartext.decode('utf-8'), timestamp
    return None
Esempio n. 14
0
def verify_cookie_signature(sig, key, *parts):
    """Constant time verifier for signatures

       :param sig: The signature hexdigest to check
       :type sig: str
       :param key: The HMAC key to use.
       :type key: bytes
       :param parts: List of parts to include in the MAC
       :type parts: list of bytes or strings
       :raises: `InvalidCookieSign` when the signature is wrong
    """
    return safe_str_cmp(as_unicode(sig), cookie_signature(key, *parts))
Esempio n. 15
0
def test_encryption_key():
    sk = SYMKey(key='df34db91c16613deba460752522d28f6ebc8a73d0d9185836270c26b')
    _enc = sk.encryption_key(alg='A128KW')
    _v = as_unicode(b64e(_enc))
    assert _v == 'xCo9VhtommCTGMWi-RyWBw'

    sk = SYMKey(key='df34db91c16613deba460752522d28f6ebc8a73d0d9185836270c26b')
    _enc = sk.encryption_key(alg='A192KW')
    _v = as_unicode(b64e(_enc))
    assert _v == 'xCo9VhtommCTGMWi-RyWB14GQqHAGC86'

    sk = SYMKey(key='df34db91c16613deba460752522d28f6ebc8a73d0d9185836270c26b')
    _enc = sk.encryption_key(alg='A256KW')
    _v = as_unicode(b64e(_enc))
    assert _v == 'xCo9VhtommCTGMWi-RyWB14GQqHAGC86vweU_Pi62X8'

    ek = sha256_digest(
        'YzE0MjgzNmRlODI5Yzg2MGYyZTRjNGE0NTZlMzBkZDRiNzJkNDA5MzUzNjM0ODkzM2E2MDk3ZWY'
    )[:16]
    assert as_unicode(b64e(ek)) == 'yf_UUkAFZ8Pn_prxPPgu9w'

    sk = SYMKey(
        key=
        'YzE0MjgzNmRlODI5Yzg2MGYyZTRjNGE0NTZlMzBkZDRiNzJkNDA5MzUzNjM0ODkzM2E2MDk3ZWY'
    )
    _enc = sk.encryption_key(alg='A128KW')
    _v = as_unicode(b64e(_enc))
    assert _v == as_unicode(b64e(ek))
    def __init__(self,
                 kty="",
                 alg="",
                 use="",
                 kid="",
                 key=None,
                 x5c=None,
                 x5t="",
                 x5u="",
                 **kwargs):
        self.key = key
        self.extra_args = kwargs

        # want kty, alg, use and kid to be strings
        if isinstance(kty, str):
            self.kty = kty
        else:
            self.kty = as_unicode(kty)

        if isinstance(alg, str):
            self.alg = alg
        else:
            self.alg = as_unicode(alg)

        if isinstance(use, str):
            self.use = use
        else:
            self.use = as_unicode(use)

        if isinstance(kid, str):
            self.kid = kid
        else:
            self.kid = as_unicode(kid)

        self.x5c = x5c or []
        self.x5t = x5t
        self.x5u = x5u
        self.inactive_since = 0
Esempio n. 17
0
def test_pack_metadata_statement_other_alg():
    _keyjar = build_keyjar(KEYDEFS)[1]
    op = Operator(keyjar=_keyjar, iss='https://example.com/')
    req = MetadataStatement(issuer='https://example.org/op')
    sms = op.pack_metadata_statement(req, alg='ES256')
    assert sms  # Should be a signed JWT
    _jwt = factory(sms)
    _body = json.loads(as_unicode(_jwt.jwt.part[1]))
    assert _body['iss'] == 'https://example.com/'

    # verify signature
    _kj = public_keys_keyjar(_keyjar, '', None, op.iss)
    r = _jwt.verify_compact(sms, _kj.get_signing_key(owner=op.iss))
    assert r
Esempio n. 18
0
def cookie_parts(name, kaka):
    """
    Give me the parts of the cookie payload

    :param name: A name of a cookie object
    :param kaka: The cookie
    :return: A list of parts or None if there is no cookie object with the
        given name
    """
    cookie_obj = SimpleCookie(as_unicode(kaka))
    morsel = cookie_obj.get(name)
    if morsel:
        return morsel.value.split("|")
    else:
        return None
Esempio n. 19
0
    def test_parse_with_wrong_client_authn(self):
        access_token = self._get_access_token(AUTH_REQ)

        _basic_token = "{}:{}".format(
            "client_1",
            self.introspection_endpoint.server_get(
                "endpoint_context").cdb["client_1"]["client_secret"],
        )
        _basic_token = as_unicode(base64.b64encode(as_bytes(_basic_token)))
        _basic_authz = "Basic {}".format(_basic_token)
        http_info = {"headers": {"authorization": _basic_authz}}

        with pytest.raises(UnAuthorizedClient):
            self.introspection_endpoint.parse_request(
                {"token": access_token.value}, http_info=http_info)
Esempio n. 20
0
def backchannel_logout(client, request='', request_args=None):
    """

    :param request: URL encoded logout request
    :return:
    """
    if request:
        req = BackChannelLogoutRequest().from_urlencoded(as_unicode(request))
    elif request_args:
        req = BackChannelLogoutRequest(**request_args)
    else:
        raise MissingRequiredAttribute('logout_token')

    _context = client.client_get("service_context")
    kwargs = {
        'aud':
        client.get_client_id(),
        'iss':
        _context.get('issuer'),
        'keyjar':
        _context.keyjar,
        'allowed_sign_alg':
        _context.get('registration_response').get(
            "id_token_signed_response_alg", "RS256")
    }

    logger.debug(f"(backchannel_logout) Verifying request using: {kwargs}")
    try:
        req.verify(**kwargs)
    except (MessageException, ValueError, NotForMe) as err:
        raise MessageException('Bogus logout request: {}'.format(err))
    else:
        logger.debug("Request verified OK")

    # Find the subject through 'sid' or 'sub'
    sub = req[verified_claim_name('logout_token')].get('sub')
    sid = None
    if not sub:
        sid = req[verified_claim_name('logout_token')].get('sid')

    if not sub and not sid:
        raise MessageException('Neither "sid" nor "sub"')
    elif sub:
        _state = _context.state.get_state_by_sub(sub)
    elif sid:
        _state = _context.state.get_state_by_sid(sid)
    return _state
Esempio n. 21
0
    def parse_response(self, response):
        if 200 <= response.status_code < 300:
            _jw = factory(response.text)

            # First Just checking the issuer ID *not* verifying the Signature
            body = json.loads(as_unicode(_jw.jwt.part[1]))
            assert body['iss'] == self.iss

            # Now verifying the signature
            try:
                _jw.verify_compact(response.text,
                                   self.keyjar.get_verify_key(owner=self.iss))
            except AssertionError:
                raise JWSException('JWS signature verification error')

            location = response.headers['Location']

            return {'sms': response.text, 'loc': location}
        else:
            raise SigningServiceError("{}: {}".format(response.status_code,
                                                      response.text))
Esempio n. 22
0
def check_session_iframe():
    if request.method == 'GET':
        req_args = request.args.to_dict()
    else:
        if request.data:
            req_args = json.loads(as_unicode(request.data))
        else:
            req_args = dict([(k, v) for k, v in request.form.items()])

    if req_args:
        # will contain client_id and origin
        if req_args['origin'] != current_app.endpoint_context.issuer:
            return 'error'
        if req_args['client_id'] != current_app.endpoint_context.cdb:
            return 'error'
        return 'OK'

    current_app.srv_config.logger.debug(
        'check_session_iframe: {}'.format(req_args))
    doc = open('templates/check_session_iframe.html').read()
    return doc
Esempio n. 23
0
def test_pack_metadata_statement():
    jb = FSJWKSBundle('', None, 'fo_jwks',
                      key_conv={'to': quote_plus, 'from': unquote_plus})
    _keyjar = build_keyjar(KEYDEFS)[1]
    self_signer = InternalSigningService('https://example.com/op',
                                         keyjar=_keyjar)
    op = Operator(self_signer=self_signer, jwks_bundle=jb,
                  iss='https://example.com/op')
    req = MetadataStatement(issuer='https://example.org/op')
    sms = op.pack_metadata_statement(req)
    assert sms  # Should be a signed JWT
    _jwt = factory(sms)
    assert _jwt
    assert _jwt.jwt.headers['alg'] == 'RS256'
    _body = json.loads(as_unicode(_jwt.jwt.part[1]))
    assert _body['iss'] == op.iss
    assert _body['issuer'] == 'https://example.org/op'

    # verify signature
    _kj = public_keys_keyjar(_keyjar, '', None, op.iss)
    r = _jwt.verify_compact(sms, _kj.get_signing_key(owner=op.iss))
    assert r
Esempio n. 24
0
def verify_request_signed_by_signing_keys(smsreq):
    """
    Verify that a JWT is signed with a key that is inside the JWT.
    
    :param smsreq: Signed Metadata Statement signing request
    :return: Dictionary containing 'ms' (the signed request) and 'iss' (the
        issuer of the JWT).
    """

    _jws = factory(smsreq)
    _json = _jws.jwt.part[1]
    _body = json.loads(as_unicode(_json))
    iss = _body['iss']
    _jwks = _body['signing_keys']

    _kj = jwks_to_keyjar(_jwks, iss)

    try:
        _kid = _jws.jwt.headers['kid']
    except KeyError:
        _keys = _kj.get_signing_key(owner=iss)
    else:
        _keys = _kj.get_signing_key(owner=iss, kid=_kid)

    _ver = _jws.verify_compact(smsreq, _keys)
    # remove the JWT specific claims
    for k in JsonWebToken.c_param.keys():
        try:
            del _ver[k]
        except KeyError:
            pass
    try:
        del _ver['kid']
    except KeyError:
        pass

    return {'ms': MetadataStatement(**_ver), 'iss': iss}
Esempio n. 25
0
    def process_request(self, request=None, cookie=None, **kwargs):
        """
        Perform user logout

        :param request:
        :param cookie:
        :param kwargs:
        :return:
        """
        _cntx = self.endpoint_context
        _sdb = _cntx.sdb

        if "post_logout_redirect_uri" in request:
            if "id_token_hint" not in request:
                raise InvalidRequest(
                    "If post_logout_redirect_uri then id_token_hint is a MUST")
        _cookie_name = self.endpoint_context.cookie_name["session"]
        try:
            part = self.endpoint_context.cookie_dealer.get_cookie_value(
                cookie, cookie_name=_cookie_name)
        except IndexError:
            raise InvalidRequest("Cookie error")
        except KeyError:
            part = None

        if part:
            # value is a base64 encoded JSON document
            _cookie_info = json.loads(as_unicode(b64d(as_bytes(part[0]))))
            logger.debug("Cookie info: {}".format(_cookie_info))
            _sid = _cookie_info["sid"]
        else:
            logger.debug("No relevant cookie")
            _sid = ""
            _cookie_info = {}

        if "id_token_hint" in request:
            logger.debug("ID token hint: {}".format(
                request[verified_claim_name("id_token_hint")]))

            auds = request[verified_claim_name("id_token_hint")]["aud"]
            _ith_sid = ""
            _sids = _sdb.sso_db.get_sids_by_sub(
                request[verified_claim_name("id_token_hint")]["sub"])

            if _sids is None:
                raise ValueError("Unknown subject identifier")

            for _isid in _sids:
                if _sdb[_isid]["authn_req"]["client_id"] in auds:
                    _ith_sid = _isid
                    break

            if not _ith_sid:
                raise ValueError("Unknown subject")

            if _sid:
                if _ith_sid != _sid:  # someone's messing with me
                    raise ValueError("Wrong ID Token hint")
            else:
                _sid = _ith_sid
        else:
            auds = []

        try:
            session = _sdb[_sid]
        except KeyError:
            raise ValueError("Can't find any corresponding session")

        client_id = session["authn_req"]["client_id"]
        # Does this match what's in the cookie ?
        if _cookie_info:
            if client_id != _cookie_info["client_id"]:
                logger.warning(
                    "Client ID in authz request and in cookie does not match")
                raise ValueError("Wrong Client")

        if auds:
            if client_id not in auds:
                raise ValueError("Incorrect ID Token hint")

        _cinfo = _cntx.cdb[client_id]

        # verify that the post_logout_redirect_uri if present are among the ones
        # registered

        try:
            _uri = request["post_logout_redirect_uri"]
        except KeyError:
            if _cntx.issuer.endswith("/"):
                _uri = "{}{}".format(_cntx.issuer,
                                     self.kwargs["post_logout_uri_path"])
            else:
                _uri = "{}/{}".format(_cntx.issuer,
                                      self.kwargs["post_logout_uri_path"])
            plur = False
        else:
            plur = True
            verify_uri(_cntx,
                       request,
                       "post_logout_redirect_uri",
                       client_id=client_id)

        payload = {
            "sid": _sid,
            "client_id": client_id,
            "user": session["authn_event"]["uid"],
        }

        # redirect user to OP logout verification page
        if plur and "state" in request:
            _uri = "{}?{}".format(_uri, urlencode({"state": request["state"]}))
            payload["state"] = request["state"]

        payload["redirect_uri"] = _uri

        logger.debug("JWS payload: {}".format(payload))
        # From me to me
        _jws = JWT(
            _cntx.keyjar,
            iss=_cntx.issuer,
            lifetime=86400,
            sign_alg=self.kwargs["signing_alg"],
        )
        sjwt = _jws.pack(payload=payload, recv=_cntx.issuer)

        location = "{}?{}".format(self.kwargs["logout_verify_url"],
                                  urlencode({"sjwt": sjwt}))
        return {"redirect_location": location}
def ec_construct_public(num):
    ecpn = ec.EllipticCurvePublicNumbers(num['x'], num['y'],
                                         NIST2SEC[as_unicode(num['crv'])]())
    return ecpn.public_key(default_backend())
def ec_construct_private(num):
    pub_ecpn = ec.EllipticCurvePublicNumbers(
        num['x'], num['y'], NIST2SEC[as_unicode(num['crv'])]())
    priv_ecpn = ec.EllipticCurvePrivateNumbers(num['d'], pub_ecpn)
    return priv_ecpn.private_key(default_backend())
Esempio n. 28
0
    def setup_auth(
        self,
        request: Optional[Union[Message, dict]],
        redirect_uri: str,
        cinfo: dict,
        cookie: List[dict] = None,
        acr: str = None,
        **kwargs,
    ):
        """

        :param request: The authorization/authentication request
        :param redirect_uri:
        :param cinfo: client info
        :param cookie: List of cookies
        :param acr: Default ACR, if nothing else is specified
        :param kwargs:
        :return:
        """

        res = self.pick_authn_method(request, redirect_uri, acr, **kwargs)

        authn = res["method"]
        authn_class_ref = res["acr"]

        client_id = request.get("client_id")
        _context = self.server_get("endpoint_context")
        try:
            _auth_info = kwargs.get("authn", "")
            if "upm_answer" in request and request["upm_answer"] == "true":
                _max_age = 0
            else:
                _max_age = max_age(request)
            identity, _ts = authn.authenticated_as(client_id,
                                                   cookie,
                                                   authorization=_auth_info,
                                                   max_age=_max_age)
        except (NoSuchAuthentication, TamperAllert):
            identity = None
            _ts = 0
        except ToOld:
            logger.info("Too old authentication")
            identity = None
            _ts = 0
        except UnknownToken:
            logger.info("Unknown Token")
            identity = None
            _ts = 0
        else:
            if identity:
                try:  # If identity['uid'] is in fact a base64 encoded JSON string
                    _id = b64d(as_bytes(identity["uid"]))
                except BadSyntax:
                    pass
                else:
                    identity = json.loads(as_unicode(_id))

                    try:
                        _csi = _context.session_manager[identity.get("sid")]
                    except Revoked:
                        identity = None
                    else:
                        if _csi.is_active() is False:
                            identity = None

        authn_args = authn_args_gather(request, authn_class_ref, cinfo,
                                       **kwargs)
        _mngr = _context.session_manager
        _session_id = ""

        # To authenticate or Not
        if not identity:  # No!
            logger.info("No active authentication")
            logger.debug("Known clients: {}".format(list(_context.cdb.keys())))

            if "prompt" in request and "none" in request["prompt"]:
                # Need to authenticate but not allowed
                return {
                    "error": "login_required",
                    "return_uri": redirect_uri,
                    "return_type": request["response_type"],
                }
            else:
                return {"function": authn, "args": authn_args}
        else:
            logger.info("Active authentication")
            if re_authenticate(request, authn):
                # demand re-authentication
                return {"function": authn, "args": authn_args}
            else:
                # I got back a dictionary
                user = identity["uid"]
                if "req_user" in kwargs:
                    if user != kwargs["req_user"]:
                        logger.debug("Wanted to be someone else!")
                        if "prompt" in request and "none" in request["prompt"]:
                            # Need to authenticate but not allowed
                            return {
                                "error": "login_required",
                                "return_uri": redirect_uri,
                            }
                        else:
                            return {"function": authn, "args": authn_args}

                if "sid" in identity:
                    _session_id = identity["sid"]

                    # make sure the client is the same
                    _uid, _cid, _gid = _mngr.decrypt_session_id(_session_id)
                    if request["client_id"] != _cid:
                        return {"function": authn, "args": authn_args}

                    grant = _mngr[_session_id]
                    if grant.is_active() is False:
                        return {"function": authn, "args": authn_args}
                    elif request != grant.authorization_request:
                        authn_event = _mngr.get_authentication_event(
                            session_id=_session_id)
                        if authn_event.is_valid(
                        ) is False:  # if not valid, do new login
                            return {"function": authn, "args": authn_args}

                        # create new grant
                        _session_id = _mngr.create_grant(
                            authn_event=authn_event,
                            auth_req=request,
                            user_id=user,
                            client_id=request["client_id"],
                        )

        if _session_id:
            authn_event = _mngr.get_authentication_event(
                session_id=_session_id)
            if authn_event.is_valid() is False:  # if not valid, do new login
                return {"function": authn, "args": authn_args}
        else:
            _session_id = self.create_session(request, identity["uid"],
                                              authn_class_ref, _ts, authn)

        return {"session_id": _session_id, "identity": identity, "user": user}
Esempio n. 29
0
    def authz_part2(self, request, session_id, **kwargs):
        """
        After the authentication this is where you should end up

        :param request: The Authorization Request
        :param session_id: Session identifier
        :param kwargs: possible other parameters
        :return: A redirect to the redirect_uri of the client
        """
        try:
            resp_info = self.post_authentication(request, session_id, **kwargs)
        except Exception as err:
            return self.error_response({}, "server_error", err)

        _context = self.server_get("endpoint_context")

        if "check_session_iframe" in _context.provider_info:
            salt = rndstr()
            try:
                authn_event = _context.session_manager.get_authentication_event(
                    session_id)
            except KeyError:
                return self.error_response({}, "server_error",
                                           "No such session")
            else:
                if authn_event.is_valid() is False:
                    return self.error_response({}, "server_error",
                                               "Authentication has timed out")

            _state = b64e(
                as_bytes(json.dumps({"authn_time":
                                     authn_event["authn_time"]})))

            _session_cookie_content = _context.new_cookie(
                name=_context.cookie_handler.name["session_management"],
                state=as_unicode(_state),
            )

            opbs_value = _session_cookie_content["value"]

            logger.debug(
                "compute_session_state: client_id=%s, origin=%s, opbs=%s, salt=%s",
                request["client_id"],
                resp_info["return_uri"],
                opbs_value,
                salt,
            )

            _session_state = compute_session_state(opbs_value, salt,
                                                   request["client_id"],
                                                   resp_info["return_uri"])

            if _session_cookie_content:
                if "cookie" in resp_info:
                    resp_info["cookie"].append(_session_cookie_content)
                else:
                    resp_info["cookie"] = [_session_cookie_content]

            resp_info["response_args"]["session_state"] = _session_state

        # Mix-Up mitigation
        resp_info["response_args"]["iss"] = _context.issuer
        resp_info["response_args"]["client_id"] = request["client_id"]

        return resp_info
Esempio n. 30
0
 def get_payload(self, self_signed_statement):
     _jws = as_unicode(self_signed_statement)
     _jwt = factory(_jws)
     return _jwt.jwt.payload()