Exemple #1
0
    def test_issued_software_statement_contains_kid(self):
        federation = Federation(self.signing_key)

        jws = federation.create_software_statement({})
        _jws = JWS()
        _jws.verify_compact(jws, keys=[self.signing_key])
        assert _jws.jwt.headers["kid"] == self.signing_key.kid
Exemple #2
0
    def check_jwks(self, entity):
        # all keys in JWKS has scoped kid
        assert all(key.kid.startswith(entity.name) for key in entity.jwks[""][0].keys())

        _jws = JWS()
        assert _jws.verify_compact(entity.signed_jwks, keys=[entity.intermediate_key])
        assert _jws.jwt.headers["kid"] == entity.intermediate_key.kid
 def _get_jwt_signature(self, params):
     try:
         jws = JWS(params, alg=self.jwt_algorithm)
         return jws.sign_compact(keys=self.issuer_private_keys)
     except NoSuitableSigningKeys:
         raise NoIssuerKey(
             "An issuer key wasn't loaded. Please run set_issuer() first.")
Exemple #4
0
def test_a_1_3b():
    _jwt = ("eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJl"
            "eHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0c"
            "nVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk")
    keys = [SYMKey(key=jwkest.intarr2bin(HMAC_KEY))]
    _jws2 = JWS()
    _jws2.verify_compact(_jwt, keys)
    def test_refresh_token(self):
        """
        A request to the Token Endpoint can also use a Refresh Token
        by using the grant_type value refresh_token, as described in
        Section 6 of OAuth 2.0 [RFC6749].
        """
        SIGKEYS = self._get_keys()

        # Retrieve refresh token
        code = self._create_code()
        post_data = self._auth_code_post_data(code=code.code)
        real_now = timezone.now
        with patch('oidc_provider.lib.utils.token.timezone.now') as now:
            now.return_value = real_now()
            response = self._post_request(post_data)

        response_dic1 = json.loads(response.content.decode('utf-8'))
        id_token1 = JWS().verify_compact(response_dic1['id_token'].encode('utf-8'), SIGKEYS)

        # Use refresh token to obtain new token
        post_data = self._refresh_token_post_data(response_dic1['refresh_token'])
        with patch('oidc_provider.lib.utils.token.timezone.now') as now:
            now.return_value = real_now() + timedelta(minutes=10)
            response = self._post_request(post_data)

        response_dic2 = json.loads(response.content.decode('utf-8'))
        id_token2 = JWS().verify_compact(response_dic2['id_token'].encode('utf-8'), SIGKEYS)

        self.assertNotEqual(response_dic1['id_token'], response_dic2['id_token'])
        self.assertNotEqual(response_dic1['access_token'], response_dic2['access_token'])
        self.assertNotEqual(response_dic1['refresh_token'], response_dic2['refresh_token'])

        # http://openid.net/specs/openid-connect-core-1_0.html#rfc.section.12.2
        self.assertEqual(id_token1['iss'], id_token2['iss'])
        self.assertEqual(id_token1['sub'], id_token2['sub'])
        self.assertNotEqual(id_token1['iat'], id_token2['iat'])
        self.assertEqual(id_token1['aud'], id_token2['aud'])
        self.assertEqual(id_token1['auth_time'], id_token2['auth_time'])
        self.assertEqual(id_token1.get('azp'), id_token2.get('azp'))

        # Refresh token can't be reused
        post_data = self._refresh_token_post_data(response_dic1['refresh_token'])
        response = self._post_request(post_data)
        self.assertIn('invalid_grant', response.content.decode('utf-8'))

        # Old access token is invalidated
        self.assertEqual(self._get_userinfo(response_dic1['access_token']).status_code, 401)
        self.assertEqual(self._get_userinfo(response_dic2['access_token']).status_code, 200)

        # Empty refresh token is invalid
        post_data = self._refresh_token_post_data('')
        response = self._post_request(post_data)
        self.assertIn('invalid_grant', response.content.decode('utf-8'))

        # No refresh token is invalid
        post_data = self._refresh_token_post_data('')
        del post_data['refresh_token']
        response = self._post_request(post_data)
        self.assertIn('invalid_grant', response.content.decode('utf-8'))
Exemple #6
0
def test_hmac_256():
    payload = b'Please take a moment to register today'
    keys = [SYMKey(key=jwkest.intarr2bin(HMAC_KEY))]
    _jws = JWS(payload, alg="HS256")
    _jwt = _jws.sign_compact(keys)
    info = JWS().verify_compact(_jwt, keys)

    assert info == payload.decode("utf-8")
def encode_id_token(payload, client):
    """
    Represent the ID Token as a JSON Web Token (JWT).
    Return a hash.
    """
    keys = get_client_alg_keys(client)
    _jws = JWS(payload, alg=client.jwt_alg)
    return _jws.sign_compact(keys)
def test_jws_1():
    msg = {"iss": "joe", "exp": 1300819380, "http://example.com/is_root": True}
    key = SYMKey(key=jwkest.intarr2bin(HMAC_KEY))
    _jws = JWS(msg, cty="JWT", alg="HS256", jwk=key.serialize())
    res = _jws.sign_compact()

    _jws2 = JWS(alg="HS256")
    _jws2.verify_compact(res, keys=[key])
    assert _jws2.msg == msg
Exemple #9
0
def test_hmac_from_keyrep():
    payload = "Please take a moment to register today"
    symkeys = [k for k in SIGKEYS if k.kty == "oct"]
    _jws = JWS(payload, alg="HS512")
    _jwt = _jws.sign_compact(symkeys)

    _rj = JWS()
    info = _rj.verify_compact(_jwt, symkeys)
    assert info == payload
Exemple #10
0
def test_jws_1():
    msg = {"iss": "joe", "exp": 1300819380, "http://example.com/is_root": True}
    jwk = SYMKey(key=jwkest.intarr2bin(HMAC_KEY))
    _jws = JWS(msg, cty="JWT", alg="HS256", jwk=json.dumps(jwk.to_dict()))
    res = _jws.sign_compact()

    _jws2 = JWS(alg="HS256")
    _jws2.verify_compact(res)
    assert _jws2.msg == msg
Exemple #11
0
def test_hmac_512():
    payload = "Please take a moment to register today"
    keys = [SYM_key(key="My hollow echo")]
    _jws = JWS(payload, alg="HS256")
    _jwt = _jws.sign_compact(keys)

    _rj = JWS()
    info = _rj.verify_compact(_jwt, keys)
    assert info == payload
Exemple #12
0
def test_dj_usage():
    key_string = open(full_path("./size2048.key"), 'r').read()
    key = RSA.importKey(key_string)
    payload = "Please take a moment to register today"
    keys = [RSAKey(key=key, kid=md5(key_string.encode('utf-8')).hexdigest())]
    _jws = JWS(payload, alg='RS256')
    sjwt = _jws.sign_compact(keys)
    _jwt = factory(sjwt)
    assert _jwt.jwt.headers['alg'] == 'RS256'
    def test_sign_registration_request(self):
        rp_root_key = rsa_key()
        rp = RP(None, rp_root_key, [], None, None)

        reg_req = FederationRegistrationRequest(**{"foo": "bar"})
        signed = rp._sign_registration_request(reg_req)
        _jws = JWS()
        assert _jws.is_jws(signed)
        assert _jws.jwt.headers["kid"] == rp.intermediate_key.kid
        assert SignedHttpRequest(rp.intermediate_key).verify(signed, body=reg_req.to_json())
def encode_id_token(payload):
    """
    Represent the ID Token as a JSON Web Token (JWT).

    Return a hash.
    """
    key_string = get_rsa_key().encode('utf-8')
    keys = [ RSAKey(key=importKey(key_string), kid=md5(key_string).hexdigest()) ]
    _jws = JWS(payload, alg='RS256')
    return _jws.sign_compact(keys)
Exemple #15
0
    def test_create_software_statement(self):
        registration_data = {
            "foo": "bar"
        }
        federation = Federation(self.signing_key)

        jws = federation.create_software_statement(registration_data)
        software_statement = JWS().verify_compact(jws, keys=[self.signing_key])

        assert all(item in software_statement.items() for item in registration_data.items())
Exemple #16
0
def test_signer_ps384():
    payload = "Please take a moment to register today"
    keys = [RSAKey(key=import_rsa_key_from_file(KEY))]
    #keys[0]._keytype = "private"
    _jws = JWS(payload, alg="PS384")
    _jwt = _jws.sign_compact(keys)

    _rj = JWS()
    info = _rj.verify_compact(_jwt, keys)
    assert info == payload
Exemple #17
0
def test_signer_es384():
    payload = "Please take a moment to register today"
    _key = ECKey().load_key(P384)
    keys = [_key]
    _jws = JWS(payload, alg="ES384")
    _jwt = _jws.sign_compact(keys)

    _rj = JWS()
    info = _rj.verify_compact(_jwt, keys)
    assert info == payload
Exemple #18
0
    def _to_jws(self, data: dict) -> str:
        """
        Converts data to a jws

        :param data: Data to be converted to jws
        :return: a signed jwt
        """
        algorithm = "RS256"
        _jws = JWS(json.dumps(data), alg=algorithm)
        return _jws.sign_compact([self.sign_key])
Exemple #19
0
def test_rs512():
    payload = "Please take a moment to register today"
    keys = [RSA_key(key=rsa_load(KEY))]
    keys[0]._keytype = "private"
    _jws = JWS(payload, alg="RS512")
    _jwt = _jws.sign_compact(keys)

    _rj = JWS()
    info = _rj.verify_compact(_jwt, keys)
    assert info == payload
    def to_jwt(self, key=None, algorithm="", lev=0):
        """
        Create a signed JWT representation of the class instance

        :param key: The signing key
        :param algorithm: The signature algorithm to use
        :return: A signed JWT
        """

        _jws = JWS(self.to_json(lev), alg=algorithm)
        return _jws.sign_compact(key)
Exemple #21
0
def test_signer_es256_verbose():
    payload = "Please take a moment to register today"
    _key = ECKey().load_key(P256)
    keys = [_key]
    _jws = JWS(payload, alg="ES256")
    _jwt = _jws.sign_compact(keys)

    _rj = JWS()
    info = _rj.verify_compact_verbose(_jwt, keys)
    assert info['msg'] == payload
    assert info['key'] == _key
Exemple #22
0
def test_1():
    claimset = {"iss": "joe", "exp": 1300819380, "http://example.com/is_root": True}

    _jws = JWS(claimset, cty="JWT")
    _jwt = _jws.sign_compact()

    _jr = JWS()
    _msg = _jr.verify_compact(_jwt, allow_none=True)
    print(_jr)
    assert _jr.jwt.headers["alg"] == "none"
    assert _msg == claimset
def encode_id_token(payload):
    """
    Represent the ID Token as a JSON Web Token (JWT).

    Return a hash.
    """
    keys = [ RSAKey(key=importKey(get_rsa_key())) ]
    _jws = JWS(payload, alg='RS256')
    _jwt = _jws.sign_compact(keys)

    return _jwt.decode('utf-8')
Exemple #24
0
def test_signer_ps512():
    payload = "Please take a moment to register today"
    # Key has to be big enough  > 512+512+2
    keys = [RSAKey(key=import_rsa_key_from_file(full_path("./size2048.key")))]
    #keys[0]._keytype = "private"
    _jws = JWS(payload, alg="PS521")
    _jwt = _jws.sign_compact(keys)

    _rj = JWS()
    info = _rj.verify_compact(_jwt, keys)
    assert info == payload
Exemple #25
0
def test_signer_es512():
    payload = "Please take a moment to register today"
    _key = ECKey().load_key(P521)
    keys = [_key]
    #keys[0]._keytype = "private"
    _jws = JWS(payload, alg="ES512")
    _jwt = _jws.sign_compact(keys)

    _rj = JWS()
    info = _rj.verify_compact(_jwt, keys)
    assert info == payload
Exemple #26
0
    def _verify(self, jws, keys):
        # type: (str, Sequence[Key]) -> Dict[str, Union[str, Lists[str]]]
        """
        Verify signature of JWS.

        :param jws: JWS to verify signature of
        :param keys: possible keys to verify the signature with
        :return: payload of the JWS
        """
        unpacked = JWS()
        unpacked.verify_compact(jws, keys=keys)
        return unpacked
Exemple #27
0
    def test_create_software_statement_with_policy(self):
        registration_data = {
            "foo": "bar"
        }
        policy_attributes = {"abc": "xyz"}
        federation = Federation(self.signing_key, policy=policy_attributes)

        jws = federation.create_software_statement(registration_data)
        software_statement = JWS().verify_compact(jws, keys=[self.signing_key])

        assert all(item in software_statement.items() for item in
                   (set(registration_data.items()) | set(policy_attributes.items())))
Exemple #28
0
    def test_full_flow(self, satosa_config_dict, oidc_frontend_config, saml_backend_config, idp_conf):
        user_id = "testuser1"

        # proxy config
        satosa_config_dict["FRONTEND_MODULES"] = [oidc_frontend_config]
        satosa_config_dict["BACKEND_MODULES"] = [saml_backend_config]
        satosa_config_dict["INTERNAL_ATTRIBUTES"]["attributes"] = {attr_name: {"openid": [attr_name],
                                                                               "saml": [attr_name]}
                                                                   for attr_name in USERS[user_id]}
        _, backend_metadata = create_entity_descriptors(SATOSAConfig(satosa_config_dict))

        # application
        test_client = Client(make_app(SATOSAConfig(satosa_config_dict)), BaseResponse)

        # get frontend OP config info
        provider_config = json.loads(test_client.get("/.well-known/openid-configuration").data.decode("utf-8"))

        # create auth req
        claims_request = ClaimsRequest(id_token=Claims(**{k: None for k in USERS[user_id]}))
        req_args = {"scope": "openid", "response_type": "id_token", "client_id": CLIENT_ID,
                    "redirect_uri": REDIRECT_URI, "nonce": "nonce",
                    "claims": claims_request.to_json()}
        auth_req = urlparse(provider_config["authorization_endpoint"]).path + "?" + urlencode(req_args)

        # make auth req to proxy
        proxied_auth_req = test_client.get(auth_req)
        assert proxied_auth_req.status == "303 See Other"

        # config test IdP
        backend_metadata_str = str(backend_metadata[saml_backend_config["name"]][0])
        idp_conf["metadata"]["inline"].append(backend_metadata_str)
        fakeidp = FakeIdP(USERS, config=IdPConfig().load(idp_conf, metadata_construction=False))

        # create auth resp
        req_params = dict(parse_qsl(urlparse(proxied_auth_req.data.decode("utf-8")).query))
        url, authn_resp = fakeidp.handle_auth_req(
            req_params["SAMLRequest"],
            req_params["RelayState"],
            BINDING_HTTP_REDIRECT,
            user_id,
            response_binding=BINDING_HTTP_REDIRECT)

        # make auth resp to proxy
        authn_resp_req = urlparse(url).path + "?" + urlencode(authn_resp)
        authn_resp = test_client.get("/" + authn_resp_req)
        assert authn_resp.status == "303 See Other"

        # verify auth resp from proxy
        resp_dict = dict(parse_qsl(urlparse(authn_resp.data.decode("utf-8")).fragment))
        signing_key = RSAKey(key=rsa_load(oidc_frontend_config["config"]["signing_key_path"]),
                             use="sig", alg="RS256")
        id_token_claims = JWS().verify_compact(resp_dict["id_token"], keys=[signing_key])
        assert all((k, v[0]) in id_token_claims.items() for k, v in USERS[user_id].items())
Exemple #29
0
def test_signing():
    kb = keybundle_from_local_file("file://jwk.json", "jwk", ["ver", "sig"])
    assert len(kb) == 1
    kj = KeyJar()
    kj.issuer_keys[""] = [kb]
    keys = kj.get_signing_key()
    payload = "Please take a moment to register today"
    _jws = JWS(payload, alg="RS512")
    try:
        _jwt = _jws.sign_compact(keys)
        assert False
    except (NoSuitableSigningKeys, WrongTypeOfKey):
        assert True
Exemple #30
0
    def _to_jws(self, data):
        """
        Converts data to a jws

        :type data: Any
        :rtype: str

        :param data: Data to be converted to jws
        :return: a jws
        """
        algorithm = "RS256"
        _jws = JWS(json.dumps(data), alg=algorithm)
        return _jws.sign_compact([self.sign_key])
Exemple #31
0
def validate_and_return_id_token(jws, nonce=None, validate_nonce=True):
    """ Validates the id_token according to the OpenID Connect specification. """
    shared_key = oidc_rp_settings.CLIENT_SECRET \
        if oidc_rp_settings.PROVIDER_SIGNATURE_ALG == 'HS256' \
        else oidc_rp_settings.PROVIDER_SIGNATURE_KEY  # RS256

    try:
        # Decodes the JSON Web Token and raise an error if the signature is invalid.
        id_token = JWS().verify_compact(force_bytes(jws),
                                        _get_jwks_keys(shared_key))
    except JWKESTException:
        return

    # Validates the claims embedded in the id_token.
    _validate_claims(id_token, nonce=nonce, validate_nonce=validate_nonce)

    return id_token
Exemple #32
0
    def entities(self, entity_id=None, **kwargs):
        """
        Get the metadata for specific entity id (client_id in the case OpenIDConnect) or all known entities.
        """
        content_type = cherrypy.tools.accept.callable(
            media=MIME_TYPES_SUPPORTED)  # get the clients preferred mime type

        try:
            self.validator.validate(cherrypy.request)
        except MalformedRequestError as e:
            logger.info("Malformed request, reason: '{}'".format(str(e)))
            if e.http_status_code == 405:
                cherrypy.response.headers['Allow'] = 'GET'
            raise cherrypy.HTTPError(e.http_status_code, e.message)

        # Handle b64-encoded entity id's
        if entity_id is not None and entity_id.startswith("{b64}"):
            entity_id = base64.urlsafe_b64decode(entity_id[5:])

        # No entity id specified
        if entity_id is None:
            entity = self.metadata_store.all()
        else:
            try:
                entity = self.metadata_store[entity_id]
            except KeyError:
                _msg = "Unknown entity id '{}'".format(entity_id)
                logger.info(_msg)
                raise cherrypy.HTTPError(404, _msg)

        cherrypy.response.headers["Content-Type"] = MIME_TYPE_JSON
        cherrypy.response.headers["Cache-Control"] = "max-age={}".format(
            self.update_frequency)
        cherrypy.response.headers["Last-Modified"] = entity.last_modified

        data = json.dumps(entity.metadata)

        if content_type == MIME_TYPE_JWT:
            algorithm = kwargs.get(MDQHandler.SIGNING_ALG_QUERY_PARAM,
                                   None) or "none"
            data = JWS(data,
                       alg=algorithm).sign_compact(keys=self.signing_keys)
            cherrypy.response.headers["Content-Type"] = MIME_TYPE_JWT

        return data
Exemple #33
0
    def _consent_registration(self, consent_args):
        """
        Register a request at the consent service

        :type consent_args: dict
        :rtype: str

        :param consent_args: All necessary parameters for the consent request
        :return: Ticket received from the consent service
        """
        jws = JWS(json.dumps(consent_args), alg=self.signing_key.alg).sign_compact([self.signing_key])
        request = "{}/creq/{}".format(self.api_url, jws)
        res = requests.get(request)

        if res.status_code != 200:
            raise UnexpectedResponseError("Consent service error: %s %s", res.status_code, res.text)

        return res.text
Exemple #34
0
    def test_idtoken_sign_validation(self):
        """
        We MUST validate the signature of the ID Token according to JWS
        using the algorithm specified in the alg Header Parameter of
        the JOSE Header.
        """
        SIGKEYS = self._get_keys()
        RSAKEYS = [k for k in SIGKEYS if k.kty == 'RSA']

        code = self._create_code()

        post_data = self._auth_code_post_data(code=code.code)

        response = self._post_request(post_data)
        response_dic = json.loads(response.content.decode('utf-8'))

        id_token = JWS().verify_compact(
            response_dic['id_token'].encode('utf-8'), RSAKEYS)
Exemple #35
0
def test_1():
    claimset = {"iss": "joe",
                "exp": 1300819380,
                "http://example.com/is_root": True}

    _jws = JWS(claimset, cty="JWT")
    _jwt = _jws.sign_compact()

    _jr = JWS()
    _msg = _jr.verify_compact(_jwt, allow_none=True)
    print(_jr)
    assert _jr.jwt.headers["alg"] == 'none'
    assert _msg == claimset
Exemple #36
0
def test_no_alg_and_alg_none_same():
    payload = "Please take a moment to register today"
    _jws = JWS(payload, alg="none")

    # Create a JWS (signed JWT)
    _jwt0 = _jws.sign_compact([])

    # The class instance that sets up the signing operation
    _jws = JWS(payload)

    # Create a JWS (signed JWT)
    _jwt1 = _jws.sign_compact([])

    assert _jwt0 == _jwt1
Exemple #37
0
    def setUpClass(cls):
        cls.g_config = {}
        with open("../src/config/config.json") as j:
            cls.g_config = json.load(j)

        wkh = WellKnownHandler(cls.g_config["auth_server_url"], secure=False)
        cls.__TOKEN_ENDPOINT = wkh.get(TYPE_OIDC, KEY_OIDC_TOKEN_ENDPOINT)

        #Generate ID Token
        _rsakey = RSA.generate(2048)
        _private_key = _rsakey.exportKey()
        _public_key = _rsakey.publickey().exportKey()

        file_out = open("private.pem", "wb")
        file_out.write(_private_key)
        file_out.close()

        file_out = open("public.pem", "wb")
        file_out.write(_public_key)
        file_out.close()

        #Admin JWT
        _rsajwk = RSAKey(kid='RSA1', key=import_rsa_key(_private_key))
        _payload = { 
                    "iss": cls.g_config["client_id"],
                    "sub": cls.g_config["client_id"],
                    "aud": cls.__TOKEN_ENDPOINT,
                    "jti": datetime.datetime.today().strftime('%Y%m%d%s'),
                    "exp": int(time.time())+3600,
                    "isOperator": False
                }
        _jws = JWS(_payload, alg="RS256")
        cls.jwt_admin = _jws.sign_compact(keys=[_rsajwk])

        #ROTest user JWT
        _payload = { 
                    "iss": cls.g_config["client_id"],
                    "sub": "54d10251-6cb5-4aee-8e1f-f492f1105c94",
                    "aud": cls.__TOKEN_ENDPOINT,
                    "jti": datetime.datetime.today().strftime('%Y%m%d%s'),
                    "exp": int(time.time())+3600,
                    "isOperator": False
                }
        _jws = JWS(_payload, alg="RS256")
        cls.jwt_rotest = _jws.sign_compact(keys=[_rsajwk])

        cls.scopes = 'public_access'
        cls.resourceName = "TestROChangePEP"
        cls.PEP_HOST = "http://localhost:5566"
Exemple #38
0
    def validate_and_return_id_token(self, jws):
        """
        Validates the id_token according to the spec.

        http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation.
        """
        try:
            # Decode the JWT and raise an error if the sig is invalid.
            # Make sure to specify the expected algorithm to prevent attacks
            # that used an RSA public key as an HMAC secret key.
            id_token = JWS().verify_compact(
                jws.encode('utf-8'),
                keys=self.get_jwks_keys(),
                sigalg=self.setting('TOKEN_SIGNING_ALGORITHM'))
        except JWKESTException as e:
            raise AuthTokenError(
                self, ('User info error: Signature verification failed. '
                       'Reason: {0}'.format(e)))
        self.validate_id_token_claims(id_token)
        return id_token
    def test_existing_account_linking_with_known_known_uuid(self, account_linking_config, internal_response, context):
        uuid = "uuid"
        data = {
            "idp": internal_response.auth_info.issuer,
            "id": internal_response.user_id,
            "redirect_endpoint": self.account_linking.base_url + "/account_linking/handle_account_linking"
        }
        key = RSAKey(key=rsa_load(account_linking_config["sign_key"]), use="sig", alg="RS256")
        jws = JWS(json.dumps(data), alg=key.alg).sign_compact([key])
        responses.add(
            responses.GET,
            "%s/get_id?jwt=%s" % (account_linking_config["api_url"], jws),
            status=200,
            body=uuid,
            content_type="text/html",
            match_querystring=True
        )

        self.account_linking.process(context, internal_response)
        assert internal_response.user_id == uuid
Exemple #40
0
def bundle2keyjar():
    url = 'https://localhost:8080/bundle'
    r = requests.get(url, verify=False)
    assert r.status_code == 200
    _bundle = r.text

    url = 'https://localhost:8080/bundle/sigkey'
    r = requests.get(url, verify=False)
    assert r.status_code == 200
    _sigkey_jwks = json.loads(as_unicode(r.text))

    kj = KeyJar()
    kj.import_jwks(_sigkey_jwks, '')

    _ver_bundle = JWS().verify_compact(_bundle, kj.get_verify_key())

    jwks_dir = _ver_bundle['bundle']
    for iss, jwks in jwks_dir.items():
        kj.import_jwks(jwks, iss)

    return kj
def verify_id(token):
    global jwks_uri

    header, claims, signature = token.split('.')
    header = b64d(header)
    claims = b64d(claims)

    if not signature:
        raise ValueError('Invalid Token')

    if header['alg'] not in ['HS256', 'RS256']:
        raise ValueError('Unsupported signing method')

    if header['alg'] == 'RS256':
        signing_keys = load_jwks_from_url(jwks_uri)
    else:
        signing_keys = [SYMKey(key=str(CLIENT_SECRET))]

    id_token = JWS().verify_compact(token, signing_keys)
    id_token['header_info'] = header
    return id_token
Exemple #42
0
def validate_and_return_id_token(jws, nonce=None, validate_nonce=True):
    """ Validates the id_token according to the OpenID Connect specification. """
    log_prompt = "Validate ID Token: {}"
    logger.debug(log_prompt.format('Get shared key'))
    shared_key = settings.AUTH_OPENID_CLIENT_ID \
        if settings.AUTH_OPENID_PROVIDER_SIGNATURE_ALG == 'HS256' \
        else settings.AUTH_OPENID_PROVIDER_SIGNATURE_KEY  # RS256

    try:
        # Decodes the JSON Web Token and raise an error if the signature is invalid.
        logger.debug(log_prompt.format('Verify compact jwk'))
        id_token = JWS().verify_compact(force_bytes(jws), _get_jwks_keys(shared_key))
    except JWKESTException as e:
        logger.debug(log_prompt.format('Verify compact jwkest exception: {}'.format(str(e))))
        return

    # Validates the claims embedded in the id_token.
    logger.debug(log_prompt.format('Validate claims'))
    _validate_claims(id_token, nonce=nonce, validate_nonce=validate_nonce)

    return id_token
Exemple #43
0
def test_1():
    claimset = {
        "iss": "joe",
        "exp": 1300819380,
        "http://example.com/is_root": True
    }

    _jws = JWS(claimset, cty="JWT")
    _jwt = _jws.sign_compact()

    _jr = JWS()
    _jr.verify_compact(_jwt)
    print _jr
    assert _jr.alg == u'none'
    assert _jr.msg == {
        "iss": "joe",
        "exp": 1300819380,
        "http://example.com/is_root": True
    }
 def _handle_webauthn_response(self, context):
     saved_state = context.state[self.name]
     internal_response = InternalData.from_dict(saved_state)
     message = {
         "user_id": internal_response["attributes"][self.user_id][0],
         "nonce": internal_response['nonce'],
         "time": str(int(time.time()))
     }
     message_json = json.dumps(message)
     jws = JWS(message_json,
               alg=self.signing_key.alg).sign_compact([self.signing_key])
     request = self.api_url + "/" + jws
     response = requests.get(request)
     response_dict = json.loads(response.text)
     if response_dict["result"] != "okay" or not hmac.compare_digest(
             response_dict["nonce"], internal_response["nonce"]):
         raise Exception("Authentication was unsuccessful.")
     if "authn_context_class_ref" in context.state:
         internal_response["auth_info"]["auth_class_ref"] = context.state[
             "authn_context_class_ref"]
     return super().process(context, internal_response)
    def test_full_flow(self, account_linking_config, internal_response,
                       context):
        ticket = "ticket"
        with responses.RequestsMock() as rsps:
            rsps.add(responses.GET,
                     "%s/get_id" % account_linking_config["api_url"],
                     status=404,
                     body=ticket,
                     content_type="text/html")
            result = self.account_linking.process(context, internal_response)
        assert isinstance(result, Redirect)
        assert result.message.startswith(
            account_linking_config["redirect_url"])

        data = {
            "idp":
            internal_response.auth_info.issuer,
            "id":
            internal_response.subject_id,
            "redirect_endpoint":
            self.account_linking.base_url +
            "/account_linking/handle_account_linking"
        }
        key = RSAKey(key=rsa_load(account_linking_config["sign_key"]),
                     use="sig",
                     alg="RS256")
        jws = JWS(json.dumps(data), alg=key.alg).sign_compact([key])
        uuid = "uuid"
        with responses.RequestsMock() as rsps:
            # account is linked, 200 OK
            rsps.add(responses.GET,
                     "%s/get_id?jwt=%s" %
                     (account_linking_config["api_url"], jws),
                     status=200,
                     body=uuid,
                     content_type="text/html",
                     match_querystring=True)
            internal_response = self.account_linking._handle_al_response(
                context)
        assert internal_response.subject_id == uuid
    def create_jwt(self, user):
        """
        Creates a signed (JWS) ID token.

        Returns:
            str: JWS
        """
        key = SYMKey(key=self.site.siteconfiguration.oauth_settings['SOCIAL_AUTH_EDX_OAUTH2_SECRET'])
        now = datetime.datetime.utcnow()
        expiration_datetime = now + datetime.timedelta(seconds=3600)
        issue_datetime = now
        payload = {
            'iss': self.site.siteconfiguration.lms_url_root,
            'administrator': False,
            'iat': timegm(issue_datetime.utctimetuple()),
            'sub': str(uuid.uuid4()),
            'preferred_username': user.username,
            'aud': self.site.siteconfiguration.oauth_settings['SOCIAL_AUTH_EDX_OAUTH2_KEY'],
            'exp': timegm(expiration_datetime.utctimetuple()),
        }
        access_token = JWS(payload, jwk=key, alg='HS512').sign_compact()
        return access_token
Exemple #47
0
    def create_id_token(self, user):
        """
        Creates a signed (JWS) ID token.

        Returns:
            str: JWS
        """
        key = SYMKey(key=self.site.siteconfiguration.
                     oauth_settings['SOCIAL_AUTH_EDX_OIDC_SECRET'])
        now = datetime.datetime.utcnow()
        expiration_datetime = now + datetime.timedelta(seconds=3600)
        issue_datetime = now
        payload = {
            'iss':
            self.site.siteconfiguration.oauth2_provider_url,
            'administrator':
            False,
            'iat':
            timegm(issue_datetime.utctimetuple()),
            'given_name':
            user.first_name,
            'sub':
            str(uuid.uuid4()),
            'preferred_username':
            user.username,
            'aud':
            self.site.siteconfiguration.
            oauth_settings['SOCIAL_AUTH_EDX_OIDC_KEY'],
            'email':
            user.email,
            'exp':
            timegm(expiration_datetime.utctimetuple()),
            'name':
            user.get_full_name(),
            'family_name':
            user.last_name,
        }
        access_token = JWS(payload, jwk=key, alg='HS512').sign_compact()
        return access_token
    def test_scope_is_ignored_for_auth_code(self):
        """
        Scope is ignored for token respones to auth code grant type.
        """
        SIGKEYS = self._get_keys()
        for code_scope in [['openid'], ['openid', 'email']]:
            code = self._create_code(code_scope)

            post_data = self._auth_code_post_data(
                code=code.code, scope=['openid', 'profile'])

            response = self._post_request(post_data)
            response_dic = json.loads(response.content.decode('utf-8'))

            self.assertEqual(response.status_code, 200)

            id_token = JWS().verify_compact(response_dic['id_token'].encode('utf-8'), SIGKEYS)

            if 'email' in code_scope:
                self.assertIn('email', id_token)
            else:
                self.assertNotIn('email', id_token)
Exemple #49
0
        def _decode_jwt(verify_expiration):
            """
            Helper method to decode a JWT with the ability to
            verify the expiration of said token
            """
            keys = KEYS()
            if should_be_asymmetric_key:
                keys.load_jwks(settings.JWT_AUTH['JWT_PUBLIC_SIGNING_JWK_SET'])
            else:
                keys.add({'key': secret_key, 'kty': 'oct'})

            _ = JWS().verify_compact(access_token.encode('utf-8'), keys)

            return jwt.decode(
                access_token,
                secret_key,
                algorithms=[settings.JWT_AUTH['JWT_ALGORITHM']],
                audience=audience,
                issuer=issuer,
                verify_expiration=verify_expiration,
                options={'verify_signature': False},
            )
Exemple #50
0
def test_rs256_rm_signature():
    payload = "Please take a moment to register today"
    keys = [RSAKey(key=import_rsa_key_from_file(KEY))]
    # keys[0]._keytype = "private"
    _jws = JWS(payload, alg="RS256")
    _jwt = _jws.sign_compact(keys)

    p = _jwt.split('.')
    _jwt = '.'.join(p[:-1])

    _rj = JWS()
    try:
        _ = _rj.verify_compact(_jwt, keys)
    except jwkest.WrongNumberOfParts:
        pass
    else:
        assert False
    def create_jws_access_token(self,
                                expires_in=3600,
                                issuer=None,
                                key=None,
                                alg='RS512'):
        """
        Creates a signed (JWS) access token.

        Arguments:
            expires_in (int): Number of seconds after which the token expires.
            issuer (str): Issuer of the token.
            key (jwkest.jwk.Key): Key used to sign the token.
            alg (str): Signing algorithm.

        Returns:
            str: JWS
        """
        key = key or self.key
        now = datetime.datetime.utcnow()
        expiration_datetime = now + datetime.timedelta(seconds=expires_in)
        issue_datetime = now
        payload = {
            'iss': issuer or self.url_root,
            'administrator': False,
            'iat': timegm(issue_datetime.utctimetuple()),
            'given_name': 'Joe',
            'sub': 'e3bfe0e4e7c6693efba9c3a93ee7f31b',
            'preferred_username': self.expected_username,
            'aud': 'InkocujLikyucsEdwiWatdebrEackmevLakDuifKooshkakWow',
            'scopes': ['read', 'write', 'profile', 'email', 'user_id'],
            'email': '*****@*****.**',
            'exp': timegm(expiration_datetime.utctimetuple()),
            'name': 'Joe Smith',
            'family_name': 'Smith',
            'user_id': '1',
        }
        access_token = JWS(payload, jwk=key, alg=alg).sign_compact()
        return access_token
Exemple #52
0
    def _get_uuid(self, context, issuer, id):
        """
        Ask the account linking service for a uuid.
        If the given issuer/id pair is not linked, then the function will return a ticket.
        This ticket should be used for linking the issuer/id pair to the user account

        :type context: satosa.context.Context
        :type issuer: str
        :type id: str
        :rtype: (int, str)

        :param context: The current context
        :param issuer: the issuer used for authentication
        :param id: the given id
        :return: response status code and message
            (200, uuid) or (404, ticket)
        """
        data = {
            "idp": issuer,
            "id": id,
            "redirect_endpoint": "%s/account_linking%s" % (self.base_url, self.endpoint)
        }
        jws = JWS(json.dumps(data), alg=self.signing_key.alg).sign_compact([self.signing_key])

        try:
            request = "{}/get_id?jwt={}".format(self.api_url, jws)
            response = requests.get(request)
        except Exception as con_exc:
            msg = "Could not connect to account linking service"
            satosa_logging(logger, logging.CRITICAL, msg, context.state, exc_info=True)
            raise SATOSAAuthenticationError(context.state, msg) from con_exc

        if response.status_code not in [200, 404]:
            msg = "Got status code '%s' from account linking service" % (response.status_code)
            satosa_logging(logger, logging.CRITICAL, msg, context.state)
            raise SATOSAAuthenticationError(context.state, msg)

        return response.status_code, response.text
    def test_authorization_code(self):
        """
        We MUST validate the signature of the ID Token according to JWS
        using the algorithm specified in the alg Header Parameter of
        the JOSE Header.
        """
        SIGKEYS = self._get_keys()
        code = self._create_code()

        post_data = self._auth_code_post_data(code=code.code)

        response = self._post_request(post_data)
        response_dic = json.loads(response.content.decode('utf-8'))

        id_token = JWS().verify_compact(response_dic['id_token'].encode('utf-8'), SIGKEYS)

        token = Token.objects.get(user=self.user)
        self.assertEqual(response_dic['access_token'], token.access_token)
        self.assertEqual(response_dic['refresh_token'], token.refresh_token)
        self.assertEqual(response_dic['token_type'], 'bearer')
        self.assertEqual(response_dic['expires_in'], 720)
        self.assertEqual(id_token['sub'], str(self.user.id))
        self.assertEqual(id_token['aud'], self.client.client_id)
Exemple #54
0
    def jwtValidate(self, token):
        """
        jwt方式解析token

        :param token: 需要解析的token.
        :type field: str
        :returns: 解析成功返回None;解析失败返回错误信息.
        :rtype: object

        .. versionadded:: 1.0
        """
        parts = token.split('.')
        if len(parts) != 3:
            raise BadSignature('Invalid JWT. Only JWS supported.')
        header = json.loads(base64_urldecode(parts[0]))
        payload = json.loads(base64_urldecode(parts[1]))
        # 校验 issuer
        if self.expectedIssuer != payload['iss']:
            return "Invalid issuer %s, expected %s" % (payload['iss'],
                                                       self.expectedIssuer)
        # 校验 client_id
        if payload["aud"]:
            if (isinstance(payload["aud"], str) and payload["aud"] !=
                    self.clientId) or self.clientId not in payload['aud']:
                return "Invalid audience %s, expected %s" % (payload['aud'],
                                                             self.clientId)
        # 校验过期时间
        if int(time.time()) >= int(payload['exp']):
            return "Token has expired"
        # 校验生效时间
        if int(time.time()) <= int(payload['iat']):
            return "Token issued in the past"

        jws = JWS(alg=header['alg'])
        try:
            jws.verify_compact(token, self.jwks)
            return
        except Exception as e:
            # 第一次解析异常时,更新jwks信息重新解析
            try:
                self.jwks = self.load_keys()
                jws.verify_compact(token, self.jwks)
                return
            except Exception as e:
                return 'Invalid token!'
    def test_idtoken_sign_validation(self):
        """
        We MUST validate the signature of the ID Token according to JWS
        using the algorithm specified in the alg Header Parameter of
        the JOSE Header.
        """
        # Get public key from discovery.
        request = self.factory.get(reverse('oidc_provider:jwks'))
        response = JwksView.as_view()(request)
        jwks_dic = json.loads(response.content.decode('utf-8'))
        SIGKEYS = KEYS()
        SIGKEYS.load_dict(jwks_dic)
        RSAKEYS = [k for k in SIGKEYS if k.kty == 'RSA']

        code = self._create_code()

        post_data = self._post_data(code=code.code)

        response = self._post_request(post_data)
        response_dic = json.loads(response.content.decode('utf-8'))

        id_token = JWS().verify_compact(
            response_dic['id_token'].encode('utf-8'), RSAKEYS)
Exemple #56
0
    def prepare_access_token_body(self,
                                  client_key=None,
                                  tamper_message=False,
                                  expiration_datetime=None,
                                  issue_datetime=None,
                                  nonce=None,
                                  issuer=None):
        """
        Prepares a provider access token response. Arguments:

        client_id       -- (str) OAuth ID for the client that requested
                                 authentication.
        expiration_time -- (datetime) Date and time after which the response
                                      should be considered invalid.
        """

        body = {'access_token': 'foobar', 'token_type': 'bearer'}
        client_key = client_key or self.client_key
        now = datetime.datetime.utcnow()
        expiration_datetime = expiration_datetime or \
                              (now + datetime.timedelta(seconds=30))
        issue_datetime = issue_datetime or now
        nonce = nonce or 'a-nonce'
        issuer = issuer or self.issuer
        id_token = self.get_id_token(
            client_key, timegm(expiration_datetime.utctimetuple()),
            timegm(issue_datetime.utctimetuple()), nonce, issuer)

        body['id_token'] = JWS(id_token, jwk=self.key,
                               alg='RS256').sign_compact()
        if tamper_message:
            header, msg, sig = body['id_token'].split('.')
            id_token['sub'] = '1235'
            msg = b64encode_item(id_token).decode('utf-8')
            body['id_token'] = '.'.join([header, msg, sig])

        return json.dumps(body)
def _verify_response(response):
    if not config.no_jwt and response.status_code < 300:
        now = datetime.utcnow().timestamp()
        jwt_token = response.headers.get('X-JWT')
        if jwt_token is None:
            raise Exception("No response header X-JWT")
        jwt = JWS().verify_compact(jwt_token, sig_keys)
        if config.verbose:
            print("Response JWT Claims:")
            print(json.dumps(jwt, indent=2))
            print()
        if jwt['jti'] != jti:
            raise Exception(
                "Unexpected response jti. Expected {} but received {}".format(
                    jti, jwt['jti']))
        if jwt['iss'] != config.audience:
            raise Exception(
                "Unexpected response issuer. Expected {} but received {}".
                format(audience, jwt['iss']))
        if jwt['aud'] != config.issuer:
            raise Exception(
                "Unexpected response audience. Expected {} but received {}".
                format(issuer, jwt['aud']))
        if jwt['nbf'] < now - config.leeway:
            raise Exception("Response nbf is out of bounds.")
        if jwt['exp'] > now + config.leeway:
            raise Exception("Response is expired.")
        if jwt['response']['status_code'] != response.status_code:
            raise Exception(
                "Unexpected response stats_code. Expected {} but received {}".
                format(response.status_code, jwt['response']['status_code']))
        hashes = dict(S256='sha256', S384='sha384', S512='sha512')
        hasher = hashlib.new(hashes[jwt['response']['body_hash_alg']])
        hasher.update(response.content)
        body_hash = hasher.hexdigest()
        if jwt['response']['body_hash'] != body_hash:
            raise Exception("Unexpected response body_hash")
Exemple #58
0
    def process(self, context, internal_response):
        """
        Manage account linking and recovery

        :type context: satosa.context.Context
        :type internal_response: satosa.internal.InternalData
        :rtype: satosa.response.Response

        :param context:
        :param internal_response:
        :return: response
        :
        """

        status_code, message = self._get_uuid(context, internal_response.auth_info.issuer, internal_response.subject_id)

        data = {
            "issuer": internal_response.auth_info.issuer,
            "redirect_endpoint": "%s/account_linking%s" % (self.base_url, self.endpoint)
        }

        # Store the issuer subject_id/sub because we'll need it in handle_al_response
        internal_response.attributes['issuer_user_id'] = internal_response.subject_id
        if status_code == 200:
            satosa_logging(logger, logging.INFO, "issuer/id pair is linked in AL service",
                           context.state)
            internal_response.subject_id = message
            data['user_id'] = message
            if self.id_to_attr:
                internal_response.attributes[self.id_to_attr] = [message]
        else:
            satosa_logging(logger, logging.INFO, "issuer/id pair is not linked in AL service. Got a ticket",
                           context.state)
            data['ticket'] = message
        jws = JWS(json.dumps(data), alg=self.signing_key.alg).sign_compact([self.signing_key])
        context.state[self.name] = internal_response.to_dict()
        return Redirect("%s/%s" % (self.redirect_url, jws))
Exemple #59
0
def test_signer_protected_headers():
    payload = "Please take a moment to register today"
    _key = ECKey().load_key(P256)
    keys = [_key]
    _jws = JWS(payload, alg="ES256")
    protected = dict(header1=u"header1 is protected",
        header2="header2 is protected too", a=1)
    _jwt = _jws.sign_compact(keys, protected=protected)

    exp_protected = protected.copy()
    exp_protected['alg'] = 'ES256'
    enc_header, enc_payload, sig = _jwt.split('.')
    assert json.loads(b64d(enc_header.encode("utf-8")).decode("utf-8")) == exp_protected
    assert b64d(enc_payload.encode("utf-8")).decode("utf-8") == payload

    _rj = JWS()
    info = _rj.verify_compact(_jwt, keys)
    assert info == payload
Exemple #60
0
def get_request_with_key(message):
    '''
    This url path is called after authentication took place to check the result of it
    '''
    message = JWS().verify_compact(message, keys=[public_key])
    satosa_request = Request(message)
    request = database.get_request(satosa_request.nonce)
    response = ""
    if not request or request.userId != satosa_request.userId or request.success == 0 or int(
            request.time) + 300 < int(satosa_request.time):
        response = cfg['responses']['failure']
    elif request.success == 1:
        database.make_invalid(request)
        response = cfg['responses']['success']
    elif request.success == 2:
        response = cfg['responses']['invalid-request']
    else:
        response = "error"
    response_dict = {
        "result": response,
        "current_time": str(int(time.time())),
        "nonce": satosa_request.nonce
    }
    return json.dumps(response_dict)