def update_token_info(self, state_info, response): """ Add information about an access token to the state information :param state_info: The state information :param response: A response, typically a access token request response. :return: The updated state information """ # Fetch the information I have about an access tokens right now. # The response I'm dealing with may be a refresh token response # in which case I already have information base on a previous response. try: _tinfo = state_info['token'] except KeyError: _tinfo = {} # If the response doesn't contain an access token then there is # nothing to be done try: _token = response['access_token'] except KeyError: pass else: _tinfo['access_token'] = _token # if there is an access token then look for other claims # that I need to store. # calculate when the token will expire based on present time # and how long it's valid. try: _exp = int(response['expires_in']) except KeyError: # If no new expires_in is given use an old one if available try: _tinfo['exp'] = utc_time_sans_frac() + _tinfo['expires_in'] except KeyError: pass else: _tinfo['exp'] = utc_time_sans_frac() + _exp _tinfo['expires_in'] = _exp # extra info for claim in ['token_type', 'scope']: try: _tinfo[claim] = response[claim] except KeyError: pass state_info['token'] = _tinfo return state_info
def create_state(self, receiver, request): """ Construct a state value. In this class it's just a random string. Also store information about the request using the state value as key. :param receiver: Who is the receiver of a request with this state value. :param request: The request :return: a random string """ _state = rndstr(24) _now = utc_time_sans_frac() # gather the information I want to store _state_info = { 'client_id': self.client_id, 'as': receiver, 'iat': _now } # Add the request to the info if isinstance(request, Message): _state_info.update(request.to_dict()) else: _state_info.update(request) # store the info self[_state] = _state_info return _state
def is_expired(self): now = utc_time_sans_frac() if self.exp < now: return True if self.sup: return self.sup.is_expired() else: return False
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)
def test_example(self): at = AuthnToken( iss='https://example.com', sub='https://example,org', aud=['https://example.org/token'], # Array of strings or string jti='abcdefghijkl', exp=utc_time_sans_frac() + 3600, ) assert at.verify()
def pack_init(self): """ Gather initial information for the payload. :return: A dictionary with claims and values """ argv = {'iss': self.iss, 'iat': utc_time_sans_frac()} if self.lifetime: argv['exp'] = argv['iat'] + self.lifetime return argv
def valid_client_info(cinfo, when=0): """ Check if the client_secret has expired :param cinfo: A :py:class:`oiccli.client_info.ClientInfo` instance :param when: A time stamp against which the expiration time is to be checked :return: True if the client_secret is still valid """ eta = cinfo.get('client_secret_expires_at', 0) now = when or utc_time_sans_frac() if eta != 0 and eta < now: return False return True
def test_id_token(): _now = time_util.utc_time_sans_frac() idt = IdToken( **{ "sub": "553df2bcf909104751cfd8b2", "aud": ["5542958437706128204e0000", "554295ce3770612820620000"], "auth_time": 1441364872, "azp": "554295ce3770612820620000", "at_hash": "L4Ign7TCAD_EppRbHAuCyw", "iat": _now, "exp": _now + 3600, "iss": "https://sso.qa.7pass.ctf.prosiebensat1.com" }) idt.verify()
def evaluate_metadata_statement(self, metadata, keyjar=None): """ Computes the resulting metadata statement from a compounded metadata statement. If something goes wrong during the evaluation an exception is raised :param metadata: The compounded metadata statement as a dictionary :return: A list of :py:class:`fedoidc.operator.LessOrEqual` instances, one per FO. """ # start from the innermost metadata statement and work outwards res = dict([(k, v) for k, v in metadata.items() if k not in IgnoreKeys]) les = [] if 'metadata_statements' in metadata: for fo, ms in metadata['metadata_statements'].items(): if isinstance(ms, str): ms = json.loads(ms) for _le in self.evaluate_metadata_statement(ms): if isinstance(ms, Message): le = LessOrEqual(sup=_le, **ms.to_dict()) else: # Must be a dict le = LessOrEqual(sup=_le, **ms) if le.is_expired(): logger.error( 'This metadata statement has expired: {}'.format(ms) ) logger.info('My time: {}'.format(utc_time_sans_frac())) continue le.eval(res) les.append(le) return les else: # this is the innermost try: _iss = metadata['iss'] except: le = LessOrEqual() le.eval(res) else: le = LessOrEqual(iss=_iss, exp=metadata['exp']) le.eval(res) les.append(le) return les
def assertion_jwt(client_id, keys, audience, algorithm, lifetime=600): """ Create a signed Json Web Token containing some information. :param client_id: The Client ID :param keys: Signing keys :param audience: Who is the receivers for this assertion :param algorithm: Signing algorithm :param lifetime: The lifetime of the signed Json Web Token :return: A Signed Json Web Token """ _now = utc_time_sans_frac() at = AuthnToken(iss=client_id, sub=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)
def get_token_info(self, state, now=0): """ Get information about a access token bound to a specific state value :param state: The state value :param now: A timestamp used to verify if the token is expired or not :return: Token information """ _tinfo = self[state]['token'] try: _exp = _tinfo['exp'] except KeyError: pass else: if not now: now = utc_time_sans_frac() if now > _exp: raise ExpiredToken('Passed best before') return _tinfo
def verify(self, **kwargs): super(JsonWebToken, self).verify(**kwargs) _now = utc_time_sans_frac() try: _skew = kwargs['skew'] except KeyError: _skew = 0 try: _exp = self['exp'] except KeyError: pass else: if (_now - _skew) > _exp: raise EXPError('Invalid expiration time') try: _nbf = self['nbf'] except KeyError: pass else: if _nbf > (_now - _skew): raise EXPError('Not valid yet') try: _aud = self['aud'] except KeyError: pass else: try: if kwargs['aud'] not in _aud: raise NotForMe('Not among intended audience') except KeyError: pass return True
from oicmsg.oic import RegistrationResponse from oicmsg.oic import address_deser from oicmsg.oic import claims_deser from oicmsg.oic import claims_ser from oicmsg.oic import msg_ser sys.path.append( os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))) __author__ = 'Roland Hedberg' CLIENT_ID = "client_1" IDTOKEN = IdToken(iss="http://oic.example.org/", sub="sub", aud=CLIENT_ID, exp=utc_time_sans_frac() + 300, nonce="N0nce", iat=time.time()) KC_SYM_S = KeyBundle({ "kty": "oct", "key": "abcdefghijklmnop".encode("utf-8"), "use": "sig", "alg": "HS256" }) def query_string_compare(query_str1, query_str2): return parse_qs(query_str1) == parse_qs(query_str2) def _eq(l1, l2):
def pack_init(self, lifetime=0): self['iat'] = utc_time_sans_frac() if lifetime: self['exp'] = self['iat'] + lifetime
def verify(self, **kwargs): super(IdToken, self).verify(**kwargs) try: if kwargs['iss'] != self['iss']: raise IssuerMismatch('{} != {}'.format(kwargs['iss'], self['iss'])) except KeyError: pass 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: if "azp" in self: if self["azp"] not in self["aud"]: raise VerificationError( "Mismatch between azp and aud claims", self) else: raise VerificationError("azp missing", 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
def valid_client_info(cinfo, when=0): eta = cinfo.get('client_secret_expires_at', 0) now = when or utc_time_sans_frac() if eta != 0 and eta < now: return False return True
def test_utc_time(): utc_now = utc_time_sans_frac() expected_utc_now = int( (datetime.utcnow() - datetime(1970, 1, 1)).total_seconds()) assert utc_now == expected_utc_now
from oicmsg.oic import IdToken from oicmsg.time_util import utc_time_sans_frac sys.path.insert(0, '.') BASE_PATH = os.path.abspath( os.path.join(os.path.dirname(__file__), "data/keys")) _key = rsa_load(os.path.join(BASE_PATH, "rsa.key")) KC_RSA = KeyBundle({"key": _key, "kty": "RSA", "use": "sig"}) CLIENT_ID = "client_1" IDTOKEN = IdToken(iss="http://oic.example.org/", sub="sub", aud=CLIENT_ID, exp=utc_time_sans_frac() + 86400, nonce="N0nce", iat=time.time()) class TestClient(object): @pytest.fixture(autouse=True) def create_client(self): self.redirect_uri = "http://example.com/redirect" conf = { 'redirect_uris': ['https://example.com/cli/authz_cb'], 'client_id': 'client_1', 'client_secret': 'abcdefghijklmnop' } self.client = Client(client_authn_method=CLIENT_AUTHN_METHOD, config=conf)