Exemple #1
0
    def _func(self, environ):
        done = False
        _vkeys = environ["client"].keystore.get_keys("ver", owner=None)
        for item in environ["item"]:
            if self._status == self.status or done:
                break

            try:
                _idt = item["id_token"]
                if _idt is None:
                    continue
            except KeyError:
                continue

            idtoken = _idt
            for key, val in self._kwargs["claims"].items():
                if key == "max_age":
                    if idtoken["exp"] > (time_util.utc_time_sans_frac() + val):
                        self._status = self.status
                        diff = idtoken["exp"] - time_util.utc_time_sans_frac()
                        self._message = "exp to far in the future [%d]" % diff
                        break
                    else:
                        continue

                if val is None:
                    if key not in idtoken:
                        self._status = self.status
                        self._message = "'%s' was supposed to be there" % key
                        break
                elif val == {"essential":True}:
                    pass
                elif "values" in val:
                    if key not in idtoken:
                        self._status = self.status
                        self._message = "Missing value on '%s'" % key
                        break
                    else:
                        _val = idtoken[key]
                        if isinstance(_val, basestring):
                            if _val not in val["values"]:
                                self._status = self.status
                                self._message = "Wrong value on '%s'" % key
                                break
                        elif isinstance(_val, int):
                            if _val not in val["values"]:
                                self._status = self.status
                                self._message = "Wrong value on '%s'" % key
                                break
                        else:
                            for sval in _val:
                                if sval in val["values"]:
                                    continue
                            self._status = self.status
                            self._message = "Wrong value on '%s'" % key
                            break

            done = True

        return {}
Exemple #2
0
    def create_new_client(self, request):
        """

        :param request: The Client registration request
        :return: The client_id
        """

        _cinfo = request.to_dict()

        # create new id and secret
        _id = rndstr(12)
        while _id in self.cdb:
            _id = rndstr(12)

        _cinfo["client_id"] = _id
        _cinfo["client_secret"] = secret(self.seed, _id)
        _cinfo["client_id_issued_at"] = utc_time_sans_frac()
        _cinfo["client_secret_expires_at"] = utc_time_sans_frac() + \
            self.secret_lifetime

        # If I support client info endpoint
        if ClientInfoEndpoint in self.endp:
            _cinfo["registration_access_token"] = rndstr(32)
            _cinfo["registration_client_uri"] = "%s%s?client_id=%s" % (
                self.client_info_url, ClientInfoEndpoint.etype, _id)

        if "redirect_uris" in request:
            _cinfo["redirect_uris"] = self._uris_to_tuples(
                request["redirect_uris"])

        self.cdb[_id] = _cinfo

        return _id
Exemple #3
0
    def __call__(self, sid, sinfo=None, kid='', **kwargs):
        keys = self.keyjar.get_signing_key(alg2keytype(self.sign_alg),
                                           owner='', kid=kid)

        if not keys:
            raise NoSuitableSigningKeys('kid={}'.format(kid))

        key = keys[0]  # Might be more then one if kid == ''

        rt = ' '.join(sinfo['response_type'])
        try:
            exp = utc_time_sans_frac() + self.lifetime[rt]
        except KeyError:
            exp = utc_time_sans_frac() + self.lifetime['']

        _jti = '{}-{}'.format(self.type, uuid.uuid4().hex)
        _tok = TokenAssertion(
            iss=self.iss,
            azp=sinfo['client_id'],
            sub=sinfo['sub'],
            kid=key.kid,
            exp=exp,
            jti=_jti
        )

        self.db[_jti] = sid

        try:
            _tok['aud'] = kwargs['aud']
        except KeyError:
            pass

        return _tok.to_jwt([key], self.sign_alg)
    def update_registered_data(self, sws_id, sws_message, unpacked_request):
        client_id = unpacked_request["client_id"]

        if client_id not in self.cdb:
            client_secret = secret(self.seed, client_id)
            _rat = rndstr(32)
            reg_enp = ""
            for endp in self.endp:
                if endp == RegistrationEndpoint:
                    reg_enp = "%s%s" % (self.baseurl, endp.etype)
                    break

            self.cdb[client_id] = {
                "client_id": client_id,
                "client_secret": client_secret,
                "registration_access_token": _rat,
                "registration_client_uri": "%s?client_id=%s" % (reg_enp, client_id),
                "client_secret_expires_at": utc_time_sans_frac() + 86400,
                "client_id_issued_at": utc_time_sans_frac()}

            self.cdb[_rat] = client_id

        #TODO Why should this be ignored "redirect_uris", "policy_uri", "logo_uri", "tos_uri",?
        _cinfo = self.do_client_registration(sws_message.to_dict(),
                                             client_id,
                                             ignore=["redirect_uris",
                                                     "policy_uri",
                                                     "logo_uri",
                                                     "tos_uri",
                                                     "client_id",
                                                     "client_secret",
                                                     "registration_access_token",
                                                     "registration_client_uri",
                                                     "client_secret_expires_at",
                                                     "client_id_issued_at",
                                                     "software_statement"])
        if isinstance(_cinfo, Response):
            return _cinfo

        cinfo = self.cdb[client_id]

        args = dict([(k, v) for k, v in _cinfo.items()
                     if k in RegistrationRequest.c_param])

        for key, value in iteritems(args):
            cinfo[key] = value

        # Update cache
        cinfo[SWS_CACHE_KEY] = sws_id

        self.cdb[client_id] = cinfo
        try:
            self.cdb.sync()
        except AttributeError:  # Not all databases can be sync'ed
            pass
Exemple #5
0
    def create_authz_session(self, sub, areq, id_token=None, oidreq=None):
        """

        :param sub: Identifier for the user, this is the real identifier
        :param areq: The AuthorizationRequest instance
        :param id_token: An IDToken instance
        :param oidreq: An OpenIDRequest instance
        :return: The session identifier, which is the database key
        """

        sid = self.token.key(user=sub, areq=areq)
        access_grant = self.token(sid=sid)

        _dic = {
            "oauth_state": "authz",
            "local_sub": sub,
            "sub": sub,
            "code": access_grant,
            "code_used": False,
            "authzreq": areq.to_json(),
            "client_id": areq["client_id"],
            #"expires_in": self.grant_expires_in,
            "client_secret_expires_at": utc_time_sans_frac() + self.grant_expires_in,
            "client_id_issued_at": utc_time_sans_frac(),
            "revoked": False,
        }

        try:
            _val = areq["nonce"]
            if _val:
                _dic["nonce"] = _val
        except (AttributeError, KeyError):
            pass

        for key in ["redirect_uri", "state", "scope", "si_redirects"]:
            try:
                _dic[key] = areq[key]
            except KeyError:
                pass

        if id_token:
            _dic["id_token"] = id_token
        if oidreq:
            _dic["oidreq"] = oidreq.to_json()

        self._db[sid] = _dic
        self.uid2sid[sub] = sid
        return sid
Exemple #6
0
    def construct_AccessTokenRequest(self,
                                     request=AccessTokenRequest,
                                     request_args=None, extra_args=None,
                                     **kwargs):

        grant = self.get_grant(**kwargs)

        if not grant.is_valid():
            raise GrantExpired("Authorization Code to old %s > %s" % (
                utc_time_sans_frac(),
                grant.grant_expiration_time))

        if request_args is None:
            request_args = {}

        request_args["code"] = grant.code

        if "grant_type" not in request_args:
            request_args["grant_type"] = "authorization_code"

        if "client_id" not in request_args:
            request_args["client_id"] = self.client_id
        elif not request_args["client_id"]:
            request_args["client_id"] = self.client_id
        return self.construct_request(request, request_args, extra_args)
Exemple #7
0
    def filter_by_permission(authz, scope):
        """
        :param authz: An IntrospectionResponse instance
        :param scope: The scope that access is asked for
        """
        now = utc_time_sans_frac()
        try:
            assert now < authz["expires_at"]
        except KeyError:
            pass
        except AssertionError:
            return False

        for perm in authz["permissions"]:
            try:
                assert now < perm["expires_at"]
            except KeyError:
                pass
            except AssertionError:
                return False

            try:
                assert scope in perm["scopes"]
            except AssertionError:
                pass
            else:
                return True

        return False
Exemple #8
0
    def verify(self, **kwargs):
        super(IdToken, self).verify(**kwargs)

        if "aud" in self:
            if "client_id" in kwargs:
                # check that I'm among the recipients
                if kwargs["client_id"] not in self["aud"]:
                    raise NotForMe(
                        "{} not in aud:{}".format(kwargs["client_id"],
                                                  self["aud"]), self)

            # Then azp has to be present and be one of the aud values
            if len(self["aud"]) > 1:
                try:
                    assert "azp" in self
                except AssertionError:
                    raise VerificationError("azp missing", self)
                else:
                    try:
                        assert self["azp"] in self["aud"]
                    except AssertionError:
                        raise VerificationError(
                            "Mismatch between azp and aud claims", self)

        if "azp" in self:
            if "client_id" in kwargs:
                if kwargs["client_id"] != self["azp"]:
                    raise NotForMe(
                        "{} != azp:{}".format(kwargs["client_id"],
                                              self["azp"]), self)

        _now = time_util.utc_time_sans_frac()

        try:
            _skew = kwargs['skew']
        except KeyError:
            _skew = 0

        try:
            _exp = self['exp']
        except KeyError:
            raise MissingRequiredAttribute('exp')
        else:
            if (_now - _skew) > _exp:
                raise EXPError('Invalid expiration time')

        try:
            _storage_time = kwargs['nonce_storage_time']
        except KeyError:
            _storage_time = NONCE_STORAGE_TIME

        try:
            _iat = self['iat']
        except KeyError:
            raise MissingRequiredAttribute('iat')
        else:
            if (_iat + _storage_time) < (_now - _skew):
                raise IATError('Issued too long ago')

        return True
Exemple #9
0
    def permission_request_allowed(self, ticket, identity):
        """
        Verify that whatever permission requests the ticket represents
        they are now allow.

        :param ticket: The ticket
        :param identity: Who has the ticket
        :return: Dictionary, with permission request as key and
            identifiers of authz decisions that permits the requests as values.
        """

        _tinfo = self.rpt_factory.unpack(ticket)
        if self.is_expired(_tinfo):
            raise TicketError('expired',
                              '{} > {}'.format(utc_time_sans_frac(),
                                               _tinfo['exp']))

        try:
            prrs = self.permission_requests[ticket]
        except KeyError:
            logger.warning("Someone is using a ticket that doesn't exist")
            raise TicketError('invalid', ticket)
        else:
            result = {}
            for prr in prrs:
                owner = self.resource_set.owner(prr['resource_set_id'])
                _adids = self.authz_db.match(owner, identity, **prr.to_dict())
                if not _adids:
                    # all or nothing
                    raise TicketError('not_authorized')
                result[prr.to_json()] = _adids
            return result
Exemple #10
0
    def key(self, user="", areq=None):
        """
        Return a key (the session id) that are based on some session
        connected data

        :param user: User id
        :param areq: The authorization request
        :return: A hash
        """
        csum = hmac.new(self.secret.encode("utf-8"), digestmod=hashlib.sha224)
        csum.update(("%s" % utc_time_sans_frac()).encode("utf-8"))
        csum.update(("%f" % random.random()).encode("utf-8"))
        if user:
            csum.update(user.encode("utf-8"))

        if areq:
            try:
                csum.update(areq["state"].encode("utf-8"))
            except KeyError:
                pass

            try:
                for val in areq["scope"]:
                    csum.update(val.encode("utf-8"))
            except KeyError:
                pass

            try:
                csum.update(areq["redirect_uri"].encode("utf-8"))
            except KeyError:
                pass

        return csum.hexdigest()  # 56 bytes long, 224 bits
Exemple #11
0
    def filter_by_permission(intro, scope=None):
        """
        :param intro: An IntrospectionResponse instance
        :param scope: The scope that access is asked for
        :return: list of resource_set_description ids
        :rtype: list
        """

        rsids = []
        now = utc_time_sans_frac()
        try:
            assert now < intro["exp"]
        except KeyError:
            pass
        except AssertionError:
            return False

        for perm in intro["permissions"]:
            try:
                assert now < perm["exp"]
            except KeyError:
                pass
            except AssertionError:
                continue

            try:
                assert scope in perm["scopes"]
            except AssertionError:
                pass
            else:
                rsids.append(perm["resource_set_id"])

        return rsids
    def test_get_session_management_id(self):
        now = utc_time_sans_frac()
        smid = "session_management_id"
        idval = {
            "nonce": "KUEYfRM2VzKDaaKD",
            "sub": "EndUserSubject",
            "iss": "https://example.com",
            "exp": now + 3600,
            "iat": now,
            "aud": self.consumer.client_id,
            "sid": smid,
        }
        idts = IdToken(**idval)

        _signed_jwt = idts.to_jwt(key=KC_RSA.keys(), algorithm="RS256")

        _state = "state"
        self.consumer.sdb[_state] = {
            "redirect_uris": ["https://example.org/cb"]
        }
        resp = AuthorizationResponse(id_token=_signed_jwt, state=_state)
        self.consumer.consumer_config["response_type"] = ["id_token"]
        self.consumer.parse_authz(resp.to_urlencoded())
        assert self.consumer.sso_db["state"]["smid"] == smid
        assert session_get(self.consumer.sso_db, "smid", smid) == [_state]
Exemple #13
0
    def key(self, user="", areq=None):
        csum = hmac.new(self.secret, digestmod=hashlib.sha224)
        csum.update("%s" % utc_time_sans_frac())
        csum.update("%f" % random.random())
        if user:
            csum.update(user)

        if areq:
            try:
                csum.update(areq["state"])
            except KeyError:
                pass

            try:
                for val in areq["scope"]:
                    csum.update(val)
            except KeyError:
                pass

            try:
                csum.update(areq["redirect_uri"])
            except KeyError:
                pass

        return csum.hexdigest()  # 56 bytes long, 224 bits
Exemple #14
0
    def key(self, user="", areq=None):
        csum = hmac.new(self.secret, digestmod=hashlib.sha224)
        csum.update("%s" % utc_time_sans_frac())
        csum.update("%f" % random.random())
        if user:
            csum.update(user)

        if areq:
            try:
                csum.update(areq["state"])
            except KeyError:
                pass

            try:
                for val in areq["scope"]:
                    csum.update(val)
            except KeyError:
                pass

            try:
                csum.update(areq["redirect_uri"])
            except KeyError:
                pass

        return csum.digest()  # 28 bytes long, 224 bits
Exemple #15
0
def assertion_jwt(cli, keys, audience, algorithm, lifetime=600):
    _now = utc_time_sans_frac()

    at = AuthnToken(iss=cli.client_id, sub=cli.client_id,
                    aud=audience, jti=rndstr(32),
                    exp=_now + lifetime, iat=_now)
    return at.to_jwt(key=keys, algorithm=algorithm)
Exemple #16
0
    def registration_endpoint(self, data):
        req = self.parse_registration_request(data)

        client_secret = rndstr()
        expires = utc_time_sans_frac() + self.registration_expires_in
        if req["type"] == "client_associate":
            client_id = rndstr(10)

            self.client[client_id] = {
                "client_secret": client_secret,
                "info": req.to_dict(),
                "expires": expires
            }
        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 = RegistrationResponseCARS(client_id=client_id,
                                    client_secret=client_secret,
                                    expires_at=expires)

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

        return response
Exemple #17
0
    def construct_AccessTokenRequest(self,
                                     request=AccessTokenRequest,
                                     request_args=None, extra_args=None,
                                     **kwargs):

        grant = self.get_grant(**kwargs)

        if not grant.is_valid():
            raise GrantExpired("Authorization Code to old %s > %s" % (
                utc_time_sans_frac(),
                grant.grant_expiration_time))

        if request_args is None:
            request_args = {}

        request_args["code"] = grant.code

        # MUST be same state as for the AuthReq
        shash = base64.urlsafe_b64encode(
                hashlib.sha256(kwargs['state'].encode('utf8')).digest())
        request_args['state_hash'] = shash.decode('ascii')

        if "grant_type" not in request_args:
            request_args["grant_type"] = "authorization_code"

        if "client_id" not in request_args:
            request_args["client_id"] = self.client_id
        elif not request_args["client_id"]:
            request_args["client_id"] = self.client_id
        return self.construct_request(request, request_args, extra_args)
Exemple #18
0
    def construct_AccessTokenRequest(self,
                                     request=AccessTokenRequest,
                                     request_args=None,
                                     extra_args=None,
                                     **kwargs):

        grant = self.get_grant(**kwargs)

        if not grant.is_valid():
            raise GrantExpired(
                "Authorization Code to old %s > %s" %
                (utc_time_sans_frac(), grant.grant_expiration_time))

        if request_args is None:
            request_args = {}

        request_args["code"] = grant.code

        try:
            request_args['state'] = kwargs['state']
        except KeyError:
            pass

        if "grant_type" not in request_args:
            request_args["grant_type"] = "authorization_code"

        if "client_id" not in request_args:
            request_args["client_id"] = self.client_id
        elif not request_args["client_id"]:
            request_args["client_id"] = self.client_id
        return self.construct_request(request, request_args, extra_args)
Exemple #19
0
def assertion_jwt(cli, keys, audience, algorithm, lifetime=600):
    _now = utc_time_sans_frac()

    at = AuthnToken(iss=cli.client_id, sub=cli.client_id,
                    aud=audience, jti=rndstr(16),
                    exp=_now + lifetime, iat=_now)
    return at.to_jwt(key=keys, algorithm=algorithm)
Exemple #20
0
    def __call__(self, sid="", ttype="", **kwargs):
        """
        Return a token.

        :param ttype: Type of token
        :param prev: Previous token, if there is one to go from
        :param sid: Session id
        :return:
        """
        if not ttype and self.type:
            ttype = self.type
        else:
            ttype = "A"

        tmp = ""
        rnd = ""
        while rnd == tmp:  # Don't use the same random value again
            rnd = rndstr(32)  # Ultimate length multiple of 16

        issued_at = "{}".format(utc_time_sans_frac())
        if ttype == "R":
            # kwargs["sinfo"] is a dictionary and we do not want updates...
            self.token_storage[sid] = copy.deepcopy(kwargs["sinfo"])

        return base64.b64encode(
            self.crypt.encrypt(lv_pack(rnd, ttype, sid,
                                       issued_at).encode())).decode("utf-8")
Exemple #21
0
    def test_faulty_idtoken(self):
        _now = time_util.utc_time_sans_frac()
        idval = {
            "nonce": "KUEYfRM2VzKDaaKD",
            "sub": "EndUserSubject",
            "iss": "https://alpha.cloud.nds.rub.de",
            "exp": _now + 3600,
            "iat": _now,
            "aud": "TestClient",
        }
        idts = IdToken(**idval)
        key = SYMKey(key="TestPassword")
        _signed_jwt = idts.to_jwt(key=[key], algorithm="HS256")

        # Mess with the signed id_token
        p = _signed_jwt.split(".")
        p[2] = "aaa"
        _faulty_signed_jwt = ".".join(p)

        _info = {
            "access_token": "accessTok",
            "id_token": _faulty_signed_jwt,
            "token_type": "Bearer",
            "expires_in": 3600,
        }

        at = AccessTokenResponse(**_info)
        with pytest.raises(BadSignature):
            at.verify(key=[key])
Exemple #22
0
    def filter_by_permission(intro, scope=None):
        """
        :param intro: An IntrospectionResponse instance
        :param scope: The scope that access is asked for
        :return: list of resource_set_description ids
        :rtype: list
        """

        rsids = []
        now = utc_time_sans_frac()
        try:
            assert now < intro["exp"]
        except KeyError:
            pass
        except AssertionError:
            return False

        for perm in intro["permissions"]:
            try:
                assert now < perm["exp"]
            except KeyError:
                pass
            except AssertionError:
                continue

            try:
                assert scope in perm["scopes"]
            except AssertionError:
                pass
            else:
                rsids.append(perm["resource_set_id"])

        return rsids
Exemple #23
0
    def construct_AccessTokenRequest(self,
                                     request: Type[AccessTokenRequest] = None,
                                     request_args=None,
                                     extra_args=None,
                                     **kwargs) -> AccessTokenRequest:

        if request is None:
            request = self.message_factory.get_request_type("token_endpoint")
        if request_args is None:
            request_args = {}
        if request is not ROPCAccessTokenRequest:
            grant = self.get_grant(**kwargs)

            if not grant.is_valid():
                raise GrantExpired(
                    "Authorization Code to old %s > %s" %
                    (utc_time_sans_frac(), grant.grant_expiration_time))

            request_args["code"] = grant.code

        try:
            request_args["state"] = kwargs["state"]
        except KeyError:
            pass

        if "grant_type" not in request_args:
            request_args["grant_type"] = "authorization_code"

        if "client_id" not in request_args:
            request_args["client_id"] = self.client_id
        elif not request_args["client_id"]:
            request_args["client_id"] = self.client_id
        return self.construct_request(request, request_args, extra_args)
Exemple #24
0
    def key(self, user="", areq=None):
        """
        Return a key (the session id) that are based on some session
        connected data

        :param user: User id
        :param areq: The authorization request
        :return: A hash
        """
        csum = hmac.new(self.secret.encode("utf-8"), digestmod=hashlib.sha224)
        csum.update(("%s" % utc_time_sans_frac()).encode("utf-8"))
        csum.update(("%f" % random.random()).encode("utf-8"))
        if user:
            csum.update(user.encode("utf-8"))

        if areq:
            try:
                csum.update(areq["state"].encode("utf-8"))
            except KeyError:
                pass

            try:
                for val in areq["scope"]:
                    csum.update(val.encode("utf-8"))
            except KeyError:
                pass

            try:
                csum.update(areq["redirect_uri"].encode("utf-8"))
            except KeyError:
                pass

        return csum.hexdigest()  # 56 bytes long, 224 bits
Exemple #25
0
    def check_permission(authzdesc, oper):
        """
        :param authzdesc: An AuthzDescription instance
        :param oper: The operation (HTTP method)
        """
        now = utc_time_sans_frac()
        try:
            assert now < authzdesc["expires_at"]
        except KeyError:
            pass
        except AssertionError:
            return False

        for perm in authzdesc["permissions"]:
            try:
                assert now < perm["expires_at"]
            except KeyError:
                pass
            except AssertionError:
                return False

            try:
                assert OPER2SCOPE[oper] in perm["scopes"]
            except AssertionError:
                pass
            else:
                return True

        return False
Exemple #26
0
    def pack(self, kid='', owner='', **kwargs):
        keys = self.keyjar.get_signing_key(jws.alg2keytype(self.sign_alg),
                                           owner=owner, kid=kid)

        if not keys:
            raise NoSuitableSigningKeys('kid={}'.format(kid))

        key = keys[0]  # Might be more then one if kid == ''

        iat = utc_time_sans_frac()
        if not 'exp' in kwargs:
            kwargs['exp'] = iat + self.lifetime

        try:
            _encrypt = kwargs['encrypt']
        except KeyError:
            _encrypt = self.encrypt
        else:
            del kwargs['encrypt']

        _jwt = self.message_type(iss=self.iss, iat=iat, **kwargs)

        if 'jti' in self.message_type.c_param:
            try:
                _jti = kwargs['jti']
            except:
                _jti = uuid.uuid4().hex

            _jwt['jti'] = _jti

        _jws = _jwt.to_jwt([key], self.sign_alg)
        if _encrypt:
            return self._encrypt(_jws)
        else:
            return _jws
Exemple #27
0
    def create_new_client(self, request, restrictions):
        """

        :param request: The Client registration request
        :param restrictions: Restrictions on the client
        :return: The client_id
        """

        _cinfo = request.to_dict()

        self.match_client_request(_cinfo)

        # create new id and secret
        _id = rndstr(12)
        while _id in self.cdb:
            _id = rndstr(12)

        _cinfo["client_id"] = _id
        _cinfo["client_secret"] = secret(self.seed, _id)
        _cinfo["client_id_issued_at"] = utc_time_sans_frac()
        _cinfo["client_secret_expires_at"] = utc_time_sans_frac() + \
                                             self.secret_lifetime

        # If I support client info endpoint
        if ClientInfoEndpoint in self.endp:
            _cinfo["registration_access_token"] = rndstr(32)
            _cinfo["registration_client_uri"] = "%s%s%s?client_id=%s" % (
                self.name, self.client_info_url, ClientInfoEndpoint.etype,
                _id)

        if "redirect_uris" in request:
            _cinfo["redirect_uris"] = self._uris_to_tuples(
                request["redirect_uris"])

        self.load_keys(request, _id, _cinfo["client_secret"])

        try:
            _behav = self.behavior['client_registration']
        except KeyError:
            pass
        else:
            self.verify_correct(_cinfo, _behav)

        self.set_token_policy(_id, _cinfo)
        self.cdb[_id] = _cinfo

        return _id
Exemple #28
0
    def set(self, token, permissions=""):
        now = utc_time_sans_frac()

        _info = {"expires_at": now + self.lifetime, "issued_at": now}
        if permissions:
            _info["permissions"] = permissions

        self.db[token] = _info
Exemple #29
0
def assertion_jwt(cli, keys, audience, algorithm, lifetime=600):
    _now = utc_time_sans_frac()

    at = AuthnToken(iss=cli.client_id, sub=cli.client_id,
                    aud=audience, jti=rndstr(32),
                    exp=_now + lifetime, iat=_now)
    logger.debug('AuthnToken: {}'.format(at.to_dict()))
    return at.to_jwt(key=keys, algorithm=algorithm)
Exemple #30
0
 def is_expired(self, token, when=None):
     """Return if token is still valid."""
     if when is None:
         now = utc_time_sans_frac()
     else:
         now = when
     eat = self.expires_at(token)
     return bool(now > eat)
Exemple #31
0
 def is_expired(self, token, when=None):
     """Return if token is still valid."""
     if when is None:
         now = utc_time_sans_frac()
     else:
         now = when
     eat = self.expires_at(token)
     return bool(now > eat)
Exemple #32
0
    def register_permission(self, owner, rpt, rsid, scopes):
        now = utc_time_sans_frac()
        perm = AuthzDescription(resource_set_id=rsid,
                                scopes=scopes,
                                exp=now + self.session.lifetime,
                                iat=now)

        self.permit.set_accepted(owner, rpt, perm)
Exemple #33
0
    def valid(self, token):
        info = self.unpack(token)

        if info['jti'] in self.db:
            if info['exp'] >= utc_time_sans_frac():
                return True

        return False
Exemple #34
0
    def create_new_client(self, request, restrictions):
        """

        :param request: The Client registration request
        :param restrictions: Restrictions on the client
        :return: The client_id
        """

        _cinfo = request.to_dict()

        self.match_client_request(_cinfo)

        # create new id and secret
        _id = rndstr(12)
        while _id in self.cdb:
            _id = rndstr(12)

        _cinfo["client_id"] = _id
        _cinfo["client_secret"] = secret(self.seed, _id)
        _cinfo["client_id_issued_at"] = utc_time_sans_frac()
        _cinfo["client_secret_expires_at"] = utc_time_sans_frac(
        ) + self.secret_lifetime

        # If I support client info endpoint
        if ClientInfoEndpoint in self.endp:
            _cinfo["registration_access_token"] = rndstr(32)
            _cinfo["registration_client_uri"] = "%s%s%s?client_id=%s" % (
                self.name, self.client_info_url, ClientInfoEndpoint.etype, _id)

        if "redirect_uris" in request:
            _cinfo["redirect_uris"] = self._uris_to_tuples(
                request["redirect_uris"])

        self.load_keys(request, _id, _cinfo["client_secret"])

        try:
            _behav = self.behavior['client_registration']
        except KeyError:
            pass
        else:
            self.verify_correct(_cinfo, _behav)

        self.set_token_policy(_id, _cinfo)
        self.cdb[_id] = _cinfo

        return _id
Exemple #35
0
 def is_expired(self):
     now = utc_time_sans_frac()
     if self.exp < now:
         logger.debug('is_expired: {} < {}'.format(self.exp, now))
         return True
     if self.sup:
         return self.sup.is_expired()
     else:
         return False
Exemple #36
0
    def update_to_token(self, token=None, issue_refresh=True, id_token="",
                        oidreq=None, key=None):
        """

        :param token: The access grant
        :param issue_refresh: If a refresh token should be issued
        :param id_token: An IDToken instance
        :param oidreq: An OpenIDRequest instance
        :param key: The session key. One of token or key must be given.
        :return: The session information as a dictionary
        """
        if token:
            (typ, key) = self.token.type_and_key(token)

            if typ != "A":  # not a access grant
                raise WrongTokenType("Not a grant token")

            dic = self._db[key]

            if dic["code_used"]:
                raise Exception("Access code already used!!")
            _at = self.token("T", token)
            dic["code_used"] = True
        else:
            dic = self._db[key]
            _at = self.token("T", sid=key)

        dic["access_token"] = _at
        dic["access_token_scope"] = "?"
        dic["oauth_state"] = "token"
        dic["token_type"] = "Bearer"
        dic["client_secret_expires_at"] = utc_time_sans_frac() + self.token_expires_in
        dic["expires_in"] = self.token_expires_in
        dic["client_id_issued_at"] = utc_time_sans_frac()
        if id_token:
            dic["id_token"] = id_token
        if oidreq:
            dic["oidreq"] = oidreq

        if issue_refresh:
            dic["refresh_token"] = self.token("R", token)

        self._db[key] = dic
        return dic
Exemple #37
0
    def upgrade_to_token(self, token=None, issue_refresh=False, id_token="",
                         oidreq=None, key=None, access_grant=""):
        """

        :param token: The access grant
        :param issue_refresh: If a refresh token should be issued
        :param id_token: An IDToken instance
        :param oidreq: An OpenIDRequest instance
        :param key: The session key. One of token or key must be given.
        :return: The session information as a dictionary
        """
        if token:
            try:
                (typ, key) = self.token.type_and_key(token)
            except (ValueError, TypeError):
                (typ, key) = self.token.type_and_key(access_grant)
                token = access_grant

            if typ != "A":  # not a access grant
                raise WrongTokenType("Not a grant token")

            dic = self._db[key]

            if dic["code_used"]:
                raise AccessCodeUsed()
            _at = self.token("T", token)
            dic["code_used"] = True
        else:
            dic = self._db[key]
            _at = self.token("T", sid=key)

        dic["access_token"] = _at
        dic["access_token_scope"] = "?"
        dic["oauth_state"] = "token"
        dic["token_type"] = "Bearer"
        dic["expires_in"] = self.token_expires_in
        dic["token_expires_at"] = utc_time_sans_frac() + self.token_expires_in
        if id_token:
            dic["id_token"] = id_token
        if oidreq:
            dic["oidreq"] = oidreq

        if issue_refresh:
            authn_event = dic.get('authn_event')
            if authn_event:
                uid = authn_event.uid
            else:
                uid = None
            refresh_token = self._refresh_db.create_token(dic['client_id'], uid,
                                                          dic.get('scope'),
                                                          dic['sub'],
                                                          dic['authzreq'])
            dic["refresh_token"] = refresh_token

        self._db[key] = dic
        return dic
Exemple #38
0
    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")
Exemple #39
0
def valid_client_info(cinfo):
    try:
        eta = cinfo['client_secret_expires_at']
    except KeyError:
        pass
    else:
        if eta < utc_time_sans_frac():
            return False

    return True
    def validate_id_token(self, id_token, nonce):
        """http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation"""
        # see oic.Client.verify_id_token
        assert id_token["iss"] == self.client.provider_info["issuer"]
        assert self.client.client_id in id_token["aud"]
        if len(id_token["aud"]) > 1:
            assert "azp" in id_token and id_token["azp"] == self.client.client_id

        assert time_util.utc_time_sans_frac() < id_token["exp"]
        assert id_token["nonce"] == nonce
    def verify(self, **kwargs):
        super(IdToken, self).verify(**kwargs)

        if "aud" in self:
            if "client_id" in kwargs:
                # check that I'm among the recipients
                if kwargs["client_id"] not in self["aud"]:
                    raise NotForMe("", self)

            # Then azp has to be present and be one of the aud values
            if len(self["aud"]) > 1:
                try:
                    assert "azp" in self
                except AssertionError:
                    raise VerificationError("azp missing", self)
                else:
                    try:
                        assert self["azp"] in self["aud"]
                    except AssertionError:
                        raise VerificationError(
                            "Mismatch between azp and aud claims", self)

        if "azp" in self:
            if "client_id" in kwargs:
                if kwargs["client_id"] != self["azp"]:
                    raise NotForMe("", self)

        _now = time_util.utc_time_sans_frac()
        try:
            _skew = kwargs['skew']
        except KeyError:
            _skew = 0

        try:
            _exp = self['exp']
        except KeyError:
            raise MissingRequiredAttribute('exp')
        else:
            if (_now - _skew) > _exp:
                raise EXPError('Invalid expiration time')

        try:
            _storage_time = kwargs['nonce_storage_time']
        except KeyError:
            _storage_time = NONCE_STORAGE_TIME

        try:
            _iat = self['iat']
        except KeyError:
            raise MissingRequiredAttribute('iat')
        else:
            if (_iat + _storage_time) < (_now - _skew):
                raise IATError('Issued too long ago')

        return True
Exemple #42
0
def test_is_valid():
    sdb = SessionDB(BASE_URL)
    ae1 = AuthnEvent("sub")
    sid = sdb.create_authz_session(ae1, AREQ)
    grant = sdb[sid]["code"]

    assert sdb.is_valid(grant)

    _dict = sdb.upgrade_to_token(grant)
    assert sdb.is_valid(grant) is False
    token1 = _dict["access_token"]
    assert sdb.is_valid(token1)

    rtoken = _dict["refresh_token"]
    assert sdb.is_valid(rtoken)

    dict2 = sdb.refresh_token(rtoken)
    token2 = dict2["access_token"]
    assert sdb.is_valid(token2)

    # replace refresh_token

    dict2["refresh_token"] = token2
    assert sdb.is_valid(rtoken) is False

    # mess with the time-line

    dict2["token_expires_at"] = utc_time_sans_frac() - 86400
    assert sdb.is_valid(token2) is False

    # replace access_token

    dict2["access_token"] = token1
    assert sdb.is_valid(token2) is False

    ae = AuthnEvent("another:user")
    sid = sdb.create_authz_session(ae, AREQ)
    grant = sdb[sid]["code"]

    gdict = sdb[grant]
    gdict["token_expires_at"] = utc_time_sans_frac() - 86400
    assert sdb.is_valid(grant) is False
Exemple #43
0
def test_is_valid():
    sdb = SessionDB(BASE_URL)
    ae1 = AuthnEvent("sub")
    sid = sdb.create_authz_session(ae1, AREQ)
    grant = sdb[sid]["code"]

    assert sdb.is_valid(grant)

    _dict = sdb.upgrade_to_token(grant)
    assert sdb.is_valid(grant) is False
    token1 = _dict["access_token"]
    assert sdb.is_valid(token1)

    rtoken = _dict["refresh_token"]
    assert sdb.is_valid(rtoken)

    dict2 = sdb.refresh_token(rtoken)
    token2 = dict2["access_token"]
    assert sdb.is_valid(token2)

    # replace refresh_token

    dict2["refresh_token"] = token2
    assert sdb.is_valid(rtoken) is False
    
    # mess with the time-line

    dict2["token_expires_at"] = utc_time_sans_frac() - 86400
    assert sdb.is_valid(token2) is False

    # replace access_token

    dict2["access_token"] = token1
    assert sdb.is_valid(token2) is False

    ae = AuthnEvent("another:user")
    sid = sdb.create_authz_session(ae, AREQ)
    grant = sdb[sid]["code"]

    gdict = sdb[grant]
    gdict["token_expires_at"] = utc_time_sans_frac() - 86400
    assert sdb.is_valid(grant) is False
Exemple #44
0
    def test_do_user_info_request_with_access_token_refresh(self):
        self.client.userinfo_endpoint = "http://oic.example.org/userinfo"

        token = self.client.get_token(state=self.client.state, scope="openid")
        token.token_expiration_time = utc_time_sans_frac() - 86400

        resp = self.client.do_user_info_request(state=self.client.state)
        assert resp.type() == "OpenIDSchema"
        assert _eq(resp.keys(),
                   ['name', 'email', 'verified', 'nickname', 'sub'])
        assert resp["name"] == "Melody Gardot"
Exemple #45
0
    def test_do_user_info_request_with_access_token_refresh(self):
        self.client.userinfo_endpoint = "http://oic.example.org/userinfo"

        token = self.client.get_token(state=self.client.state, scope="openid")
        token.token_expiration_time = utc_time_sans_frac() - 86400

        resp = self.client.do_user_info_request(state=self.client.state)
        assert resp.type() == "OpenIDSchema"
        assert _eq(resp.keys(), ['name', 'email', 'verified', 'nickname',
                                 'sub'])
        assert resp["name"] == "Melody Gardot"
Exemple #46
0
    def set(self, token, permissions=""):
        now = utc_time_sans_frac()

        _info = {
            "expires_at": now + self.lifetime,
            "issued_at": now,
        }
        if permissions:
            _info["permissions"] = permissions

        self.db[token] = _info
Exemple #47
0
    def test_construct_access_token_req_override(self):
        grant = Grant()
        grant.code = "AbCdEf"
        grant.grant_expiration_time = time_util.utc_time_sans_frac() + 30
        self.client.grant = {"xyz": grant}

        atr = self.client.construct_AccessTokenRequest(state="xyz")

        assert atr["grant_type"] == "authorization_code"
        assert atr["code"] == "AbCdEf"
        assert atr["redirect_uri"] == self.redirect_uri
Exemple #48
0
    def test_no_sub_or_sid(self):
        lt = LogoutToken(
            iss="https://example.com",
            aud=["https://rp.example.org"],
            events={BACK_CHANNEL_LOGOUT_EVENT: {}},
            iat=utc_time_sans_frac(),
            jti=rndstr(16),
        )

        with pytest.raises(ValueError):
            lt.verify()
    def validate_id_token(self, id_token, nonce):
        """http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation"""
        # see oic.Client.verify_id_token
        assert id_token["iss"] == self.client.provider_info["issuer"]
        assert self.client.client_id in id_token["aud"]
        if len(id_token["aud"]) > 1:
            assert "azp" in id_token and id_token[
                "azp"] == self.client.client_id

        assert time_util.utc_time_sans_frac() < id_token["exp"]
        assert id_token["nonce"] == nonce
Exemple #50
0
    def test_construct_access_token_req_override(self):
        grant = Grant()
        grant.code = "AbCdEf"
        grant.grant_expiration_time = time_util.utc_time_sans_frac() + 30
        self.client.grant = {"xyz": grant}

        atr = self.client.construct_AccessTokenRequest(state="xyz")

        assert atr["grant_type"] == "authorization_code"
        assert atr["code"] == "AbCdEf"
        assert atr["redirect_uri"] == self.redirect_uri
Exemple #51
0
    def test_with_sid(self):
        lt = LogoutToken(
            iss="https://example.com",
            aud=["https://rp.example.org"],
            events={BACK_CHANNEL_LOGOUT_EVENT: {}},
            iat=utc_time_sans_frac(),
            jti=rndstr(16),
            sid=rndstr(),
        )

        assert lt.verify()
Exemple #52
0
    def test_wrong_event_content(self):
        lt = LogoutToken(
            iss="https://example.com",
            aud=["https://rp.example.org"],
            events={BACK_CHANNEL_LOGOUT_EVENT: {"foo": "bar"}},
            jti=rndstr(16),
            iat=utc_time_sans_frac(),
            sub="https://example.com/sub",
        )

        with pytest.raises(ValueError):
            lt.verify()
Exemple #53
0
    def test_wrong_iss(self):
        lt = LogoutToken(
            iss="https://example.com",
            aud=["https://rp.example.org"],
            events={BACK_CHANNEL_LOGOUT_EVENT: {}},
            iat=utc_time_sans_frac(),
            jti=rndstr(16),
            sub="https://example.com/sub",
        )

        with pytest.raises(NotForMe):
            lt.verify(iss="https://rp.example.org")
Exemple #54
0
    def test_wrong_event(self):
        lt = LogoutToken(
            iss="https://example.com",
            aud=["https://rp.example.org"],
            events={"http://schemas.openid.net/event/other}": {}},
            jti=rndstr(16),
            iat=utc_time_sans_frac(),
            sub="https://example.com/sub",
        )

        with pytest.raises(ValueError):
            lt.verify()
Exemple #55
0
    def test_with_sub(self):
        # All the required claims. Note there must be a sub, a sid or both
        lt = LogoutToken(
            iss="https://example.com",
            aud=["https://rp.example.org"],
            events={BACK_CHANNEL_LOGOUT_EVENT: {}},
            iat=utc_time_sans_frac(),
            jti=rndstr(16),
            sub="https://example.com/sub",
        )

        assert lt.verify()
 def _get_client_assertion(self):
     return jwt.encode(
         {
             "iss": self.client.client_id,
             "sub": self.client.client_id,
             "aud": self.client.token_endpoint,
             "jti": str(uuid.uuid4()),
             "exp": utc_time_sans_frac() + 120,
         },
         key=self.private_key,
         algorithm="RS512",
     ).decode("utf-8")
Exemple #57
0
    def test_with_nonce(self):
        lt = LogoutToken(
            iss="https://example.com",
            aud=["https://rp.example.org"],
            events={BACK_CHANNEL_LOGOUT_EVENT: {}},
            iat=utc_time_sans_frac(),
            jti=rndstr(16),
            nonce=rndstr(16),
        )

        with pytest.raises(MessageException):
            lt.verify()
Exemple #58
0
    def upgrade_to_token(self,
                         token=None,
                         issue_refresh=True,
                         id_token="",
                         oidreq=None,
                         key=None,
                         access_grant=""):
        """

        :param token: The access grant
        :param issue_refresh: If a refresh token should be issued
        :param id_token: An IDToken instance
        :param oidreq: An OpenIDRequest instance
        :param key: The session key. One of token or key must be given.
        :return: The session information as a dictionary
        """
        if token:
            try:
                (typ, key) = self.token.type_and_key(token)
            except (ValueError, TypeError):
                (typ, key) = self.token.type_and_key(access_grant)
                token = access_grant

            if typ != "A":  # not a access grant
                raise WrongTokenType("Not a grant token")

            dic = self._db[key]

            if dic["code_used"]:
                raise AccessCodeUsed()
            _at = self.token("T", token)
            dic["code_used"] = True
        else:
            dic = self._db[key]
            _at = self.token("T", sid=key)

        dic["access_token"] = _at
        dic["access_token_scope"] = "?"
        dic["oauth_state"] = "token"
        dic["token_type"] = "Bearer"
        dic["expires_in"] = self.token_expires_in
        dic["token_expires_at"] = utc_time_sans_frac() + self.token_expires_in
        if id_token:
            dic["id_token"] = id_token
        if oidreq:
            dic["oidreq"] = oidreq

        if issue_refresh:
            dic["refresh_token"] = self.token("R", token)

        self._db[key] = dic
        return dic
Exemple #59
0
    def test_wrong_iat(self):
        # Issued sometime in the future
        lt = LogoutToken(
            iss="https://example.com",
            aud=["https://rp.example.org"],
            events={BACK_CHANNEL_LOGOUT_EVENT: {}},
            iat=utc_time_sans_frac() + 86400,
            jti=rndstr(16),
            sub="https://example.com/sub",
        )

        with pytest.raises(ValueError):
            lt.verify()