Пример #1
0
    def getPrivateKey(self, kid=None):
        """Get private key

        :param str kid: key ID

        :return: S_OK(obj)/S_ERROR()
        """
        result = self.getActiveKeys(kid)
        if not result["OK"]:
            return result
        jwks = result["Value"]
        if kid:
            strkey = jwks[0]["key"]
            return S_OK(JsonWebKey.import_key(json.loads(jwks[0]["key"])))
        newer = {}
        for jwk in jwks:
            if int(jwk["expires_at"]) > int(
                    newer.get("expires_at",
                              time.time() + (24 * 3600))):
                newer = jwk
        if not newer.get("key"):
            result = self.generateRSAKeys()
            if not result["OK"]:
                return result
            newer = result["Value"]
        return S_OK(JsonWebKey.import_key(json.loads(newer["key"])))
Пример #2
0
def jwks():
    from authlib.jose import JsonWebKey
    from authlib.jose import JWK_ALGORITHMS
    jwk = JsonWebKey(algorithms=JWK_ALGORITHMS)
    key = jwk.dumps(config['PUBLIC_KEY'], kty='RSA')
    key['kid'] = '1'
    return {"keys": [key]}
Пример #3
0
    def __init__(self):
        rsa = RSAKey.generate_key(key_size=4096, is_private=True)
        self.jwk_public_key = JsonWebKey.import_key(rsa.as_pem(is_private=False))
        self.jwk_private_key = JsonWebKey.import_key(rsa.as_pem(is_private=True))

        self._key_alg = 'RSA-OAEP-256'
        self._content_alg = 'A256GCM'
        self._compression_alg = 'DEF'
Пример #4
0
 def load_key(header, payload):
     jwk_set = JsonWebKey.import_key_set(self.fetch_jwk_set())
     try:
         return jwk_set.find_by_kid(header.get('kid'))
     except ValueError:
         # re-try with new jwk set
         jwk_set = JsonWebKey.import_key_set(
             self.fetch_jwk_set(force=True))
         return jwk_set.find_by_kid(header.get('kid'))
Пример #5
0
def jwks_schema() -> dict:
    from authlib.jose import JsonWebKey
    from authlib.jose import JWK_ALGORITHMS

    jwk = JsonWebKey(algorithms=JWK_ALGORITHMS)
    key = jwk.dumps(current_app.config['PUBLIC_KEY'], kty='RSA')
    key['kid'] = '1'

    return {'keys': [key]}
Пример #6
0
    def test_import_keys(self):
        rsa_pub_pem = read_file_path('rsa_public.pem')
        self.assertRaises(ValueError, JsonWebKey.import_key, rsa_pub_pem,
                          {'kty': 'EC'})

        key = JsonWebKey.import_key(raw=rsa_pub_pem, options={'kty': 'RSA'})
        self.assertIn('e', dict(key))
        self.assertIn('n', dict(key))

        key = JsonWebKey.import_key(raw=rsa_pub_pem)
        self.assertIn('e', dict(key))
        self.assertIn('n', dict(key))
Пример #7
0
def get_jwk():
    LOGGER.debug('Loading jwk from public key...')
    key_data = None
    with open(app_context().config['jwk_public_key_path'], 'rb') as _key_file:
        key_data = _key_file.read()
    _jwk = JsonWebKey(JWK_ALGORITHMS)
    _key_dict = _jwk.dumps(key_data,
                           kty='RSA',
                           use='sig',
                           alg='RS256',
                           kid="demo_key")
    return {'keys': [_key_dict]}
Пример #8
0
    def test_03_keyid(self):
        print("\n-----", sys._getframe().f_code.co_name, "-----")
        pem1 = "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIDSt1IOhS5ZmY6nkX/Wh7pT+Y45TmYxrwoc1pG72v387oAoGCCqGSM49\nAwEHoUQDQgAEdEsjD2i2LytHOjNxxc9PbFeqQ89aMLOfmdBbEoSOhZBukJ52EqQM\nhOdgHqyqD4hEyYxgDu3uIbKat+lEZEhb3Q==\n-----END EC PRIVATE KEY-----"
        keypair1 = bbclib.KeyPair()
        keypair1.mk_keyobj_from_private_key_pem(pem1)
        keyid1 = keypair1.get_key_id()

        pubkey = keypair1.get_public_key_in_pem()
        jwk = JsonWebKey(algorithms=JWK_ALGORITHMS)
        obj = jwk.dumps(pubkey, kty='EC')
        json_obj = json.dumps(obj, separators=(',', ':'), sort_keys=True)
        keyid2 = hashlib.sha256(json_obj.encode()).digest()
        assert keyid1 == keyid2
Пример #9
0
    def test_generate_keys(self):
        key = JsonWebKey.generate_key(kty='oct',
                                      crv_or_size=256,
                                      is_private=True)
        self.assertEqual(key['kty'], 'oct')

        key = JsonWebKey.generate_key(kty='EC', crv_or_size='P-256')
        self.assertEqual(key['kty'], 'EC')

        key = JsonWebKey.generate_key(kty='RSA', crv_or_size=2048)
        self.assertEqual(key['kty'], 'RSA')

        key = JsonWebKey.generate_key(kty='OKP', crv_or_size='Ed25519')
        self.assertEqual(key['kty'], 'OKP')
Пример #10
0
    def test_import_key_set(self):
        jwks_public = read_file_path('jwks_public.json')
        key_set1 = JsonWebKey.import_key_set(jwks_public)
        key1 = key_set1.find_by_kid('abc')
        self.assertEqual(key1['e'], 'AQAB')

        key_set2 = JsonWebKey.import_key_set(jwks_public['keys'])
        key2 = key_set2.find_by_kid('abc')
        self.assertEqual(key2['e'], 'AQAB')

        key_set3 = JsonWebKey.import_key_set(json_dumps(jwks_public))
        key3 = key_set3.find_by_kid('abc')
        self.assertEqual(key3['e'], 'AQAB')

        self.assertRaises(ValueError, JsonWebKey.import_key_set, 'invalid')
Пример #11
0
def generate_key_pair(filename, kid=None):
    """
    'kid' will default to the jwk thumbprint if not set explicitly.

    Reference: https://tools.ietf.org/html/rfc7638
    """
    options = {}
    if kid:
        options["kid"] = kid

    jwk = JsonWebKey.generate_key("RSA",
                                  2048,
                                  is_private=True,
                                  options=options)

    print(("Writing public key to %s.jwk" % filename))
    with open("%s.jwk" % filename, mode="w") as f:
        f.truncate(0)
        f.write(jwk.as_json())

    print(("Writing key ID to %s.kid" % filename))
    with open("%s.kid" % filename, mode="w") as f:
        f.truncate(0)
        f.write(jwk.as_dict()["kid"])

    print(("Writing private key to %s.pem" % filename))
    with open("%s.pem" % filename, mode="wb") as f:
        f.truncate(0)
        f.write(jwk.get_private_key().private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption(),
        ))
Пример #12
0
    def _create_token(
        self,
        type_token: str,
        exp_time: Optional[int],
        *,
        custom_claims,
    ) -> str:

        # Data section
        claims = {
            "iat": timezone.now(),
            "nbf": timezone.now(),
            "jti": str(uuid.uuid4()),
            "type": type_token,
            **custom_claims,
        }

        if exp_time:
            claims["exp"] = exp_time
        if self.issuer:
            claims["iss"] = self.issuer
        if self.audience:
            claims["aud"] = self.audience

        key = JsonWebKey.import_key(self.private_key)
        headers = {"alg": "RS256", "kid": key.thumbprint()}
        return jwt.encode(header=headers, payload=claims, key=key)
Пример #13
0
    def encrypted_script_response(
        self, opts: vpb.ExecuteScriptRequest.EncryptionOptions
    ) -> vpb.ExecuteScriptResponse:
        '''
        Returns a script repsonse with encrypted row batch fields, if they exist,
        and if the options are set.
        '''
        es_resp = self.execute_script_response

        if not es_resp.HasField("data"):
            return es_resp
        if opts is None:
            return es_resp

        # Now we encrypt the batch.
        rb = es_resp.data.batch.SerializeToString()
        key = JsonWebKey.import_key(json.loads(opts.jwk_key))
        encrypted_batch = JsonWebEncryption().serialize_compact(
            {
                'alg': opts.key_alg,
                'enc': opts.content_alg,
                'zip': opts.compression_alg,
            }, rb, key)

        # Make sure we only send the encrypted_batch through.
        es_resp.data.ClearField('batch')
        es_resp.data.encrypted_batch = encrypted_batch
        return es_resp
Пример #14
0
def _load_keys_from_url(url, verify=True):
    """
    Expects something on this form:
        {"keys":
            [
                {
                    "kty":"EC",
                    "crv":"P-256",
                    "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
                    "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
                    "use":"enc",
                    "kid":"1"
                },
                {
                    "kty":"RSA",
                    "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFb....."
                    "e":"AQAB",
                    "kid":"2011-04-29"
                }
            ]
        }
    """

    keys = []
    r = request("GET", url, allow_redirects=True, verify=verify)
    if r.status_code == 200:
        keys_dict = json.loads(r.text)
        for key_spec in keys_dict["keys"]:
            key = JsonWebKey.import_key(key_spec)
            keys.append(key)
    else:
        raise Exception("Error loading JWK set - HTTP GET error: %s" %
                        r.status_code)

    return keys
def userinfo():
    req = flask.request
    log_request('GET-USERINFO', req)
    access_token = req.headers.get('Authorization', None)
    # TODO: if not access_token

    # TODO: Validate access-token

    log.info("GET-USERINFO: Access token: '{}'".format(access_token))

    access_token_parts = access_token.split()
    if access_token_parts[0].lower() != 'bearer' or len(access_token_parts) != 2:
        return flask.render_template('error.html', text='Invalid authorization')

    access_token = access_token_parts[1]

    # FIXME
    with open('jwt-key.pub', 'rb') as f:
        key_data = f.read()
    pub_key = JsonWebKey.import_key(key_data, {'kty': 'RSA'})

    access_token_json = jwt.decode(access_token, pub_key)
    scope = access_token_json['scope']

    # TODO: Validate audience in access token covers /userinfo
    log.info("GET-USERINFO: Access token audience: '{}'".format(access_token_json['aud']))

    log.info("GET-USERINFO: Scope '{}'".format(scope))

    claims = dict()
    # See https://openid.net/specs/openid-connect-basic-1_0.html#StandardClaims for what claims to include in access token
    if 'profile' in scope:
        claims['name'] = 'Name of user is {}'.format(access_token_json['sub'].capitalize())

    return claims
Пример #16
0
def generate_service_key(service,
                         expiration_date,
                         kid=None,
                         name="",
                         metadata=None,
                         rotation_duration=None):
    """
    'kid' will default to the jwk thumbprint if not set explicitly.

    Reference: https://tools.ietf.org/html/rfc7638
    """
    options = {}
    if kid:
        options["kid"] = kid

    jwk = JsonWebKey.generate_key("RSA",
                                  2048,
                                  is_private=True,
                                  options=options)
    kid = jwk.as_dict()["kid"]

    key = create_service_key(
        name,
        kid,
        service,
        jwk.as_dict(),
        metadata or {},
        expiration_date,
        rotation_duration=rotation_duration,
    )
    return (jwk.get_private_key(), key)
Пример #17
0
    def _validate(self):
        """
        Reference: https://docs.docker.com/registry/spec/manifest-v2-1/#signed-manifests
        """
        if not self._signatures:
            return

        payload_str = self._payload
        for signature in self._signatures:
            protected = signature[DOCKER_SCHEMA1_PROTECTED_KEY]
            sig = signature[DOCKER_SCHEMA1_SIGNATURE_KEY]

            jwk = JsonWebKey.import_key(
                signature[DOCKER_SCHEMA1_HEADER_KEY]["jwk"])
            jws = JsonWebSignature(
                algorithms=[signature[DOCKER_SCHEMA1_HEADER_KEY]["alg"]])

            obj_to_verify = {
                DOCKER_SCHEMA1_PROTECTED_KEY: protected,
                DOCKER_SCHEMA1_SIGNATURE_KEY: sig,
                DOCKER_SCHEMA1_HEADER_KEY: {
                    "alg": signature[DOCKER_SCHEMA1_HEADER_KEY]["alg"]
                },
                "payload": base64url_encode(payload_str),
            }

            try:
                data = jws.deserialize_json(obj_to_verify,
                                            jwk.get_public_key())
            except (BadSignatureError, UnsupportedAlgorithmError):
                raise InvalidSchema1Signature()

            if not data:
                raise InvalidSchema1Signature()
Пример #18
0
 def fetch_keys(self):
     if not self.key_url:
         return
     response = requests.get(self.key_url)
     if response.ok:
         data = response.json()
         self._keyset = JsonWebKey.import_key_set(data)
Пример #19
0
 def load_key(header, _):
     alg = header.get("alg")
     if alg in ["HS256", "HS384", "HS512"]:
         # For HS256: client secret is used for id_token signing
         return self.client_secret
     elif alg in ["RS256", "RS384", "RS512"]:
         jwk_set = JsonWebKey.import_key_set(self.fetch_jwk_set())
         try:
             return jwk_set.find_by_kid(header.get("kid"))
         except ValueError:
             # re-try with new jwk set
             jwk_set = JsonWebKey.import_key_set(
                 self.fetch_jwk_set(force=True))
             return jwk_set.find_by_kid(header.get("kid"))
     else:
         raise RuntimeError(f"Unsupported id_token algorithm: '{alg}'")
Пример #20
0
    def verifyToken(self, accessToken=None, jwks=None):
        """Verify access token

        :param str accessToken: access token
        :param dict jwks: JWKs

        :return: dict
        """
        # Define an access token
        if not accessToken:
            accessToken = self.token["access_token"]
        # Renew a JWKs of an identity provider if needed
        if not jwks:
            result = self.updateJWKs()
            if not result["OK"]:
                return result
            jwks = self.jwks
        if not jwks:
            return S_ERROR("JWKs not found.")
        # Try to decode and verify an access token
        self.log.debug("Try to decode token %s with JWKs:\n" % accessToken, pprint.pformat(jwks))
        try:
            return S_OK(jwt.decode(accessToken, JsonWebKey.import_key_set(jwks)))
        except Exception as e:
            self.log.exception(e)
            return S_ERROR(repr(e))
Пример #21
0
def dummy_key_pair():

    key = ec.generate_private_key(ec.SECP256R1(), backend=default_backend())

    private_key = key.private_bytes(serialization.Encoding.PEM,
                                    serialization.PrivateFormat.PKCS8,
                                    serialization.NoEncryption())
    public_key = key.public_key().public_bytes(
        serialization.Encoding.OpenSSH, serialization.PublicFormat.OpenSSH)

    PRIVATE_KEY = JsonWebKey.import_key(private_key, {'kty': 'EC'})
    PUBLIC_KEY = JsonWebKey.import_key(public_key, {'kty': 'EC'})

    keys = {'PUBLIC_KEY': PUBLIC_KEY, 'PRIVATE_KEY': PRIVATE_KEY}

    return keys
Пример #22
0
    async def parse_id_token(self, token, nonce, claims_options=None):
        """Return an instance of UserInfo from token's ``id_token``."""
        claims_params = dict(
            nonce=nonce,
            client_id=self.client_id,
        )
        if 'access_token' in token:
            claims_params['access_token'] = token['access_token']
            claims_cls = CodeIDToken
        else:
            claims_cls = ImplicitIDToken

        metadata = await self.load_server_metadata()
        if claims_options is None and 'issuer' in metadata:
            claims_options = {'iss': {'values': [metadata['issuer']]}}

        alg_values = metadata.get('id_token_signing_alg_values_supported')
        if not alg_values:
            alg_values = ['RS256']

        jwt = JsonWebToken(alg_values)

        jwk_set = await self.fetch_jwk_set()
        try:
            claims = jwt.decode(
                token['id_token'],
                key=JsonWebKey.import_key_set(jwk_set),
                claims_cls=claims_cls,
                claims_options=claims_options,
                claims_params=claims_params,
            )
        except ValueError:
            jwk_set = await self.fetch_jwk_set(force=True)
            claims = jwt.decode(
                token['id_token'],
                key=JsonWebKey.import_key_set(jwk_set),
                claims_cls=claims_cls,
                claims_options=claims_options,
                claims_params=claims_params,
            )

        # https://github.com/lepture/authlib/issues/259
        if claims.get('nonce_supported') is False:
            claims.params['nonce'] = None
        claims.validate(leeway=120)
        return UserInfo(claims)
Пример #23
0
 def test_dumps_okp_private_key(self):
     key = read_file_path('ed25519-pkcs8.pem')
     jwk = JsonWebKey(RFC8037_ALGORITHMS)
     self.assertRaises(ValueError, jwk.dumps, key)
     obj = jwk.dumps(key, 'OKP')
     self.assertEqual(obj['kty'], 'OKP')
     self.assertEqual(obj['crv'], 'Ed25519')
     self.assertIn('d', obj)
Пример #24
0
def get_jwk():
    LOGGER.debug('Loading jwk from public key...')
    key_data = None
    with open(app_context().config['jwk_public_key_path'], 'rb') as _key_file:
        key_data = _key_file.read()
    LOGGER.debug(key_data)
    key = JsonWebKey.import_key(key_data, {'kty': 'RSA'})
    return {'keys': [{**key.as_dict(), 'kid': 'demo_key'}]}
Пример #25
0
 def test_loads_okp_public_key(self):
     obj = {
         "x": "AD9E0JYnpV-OxZbd8aN1t4z71Vtf6JcJC7TYHT0HDbg",
         "crv": "Ed25519",
         "kty": "OKP"
     }
     jwk = JsonWebKey(RFC8037_ALGORITHMS)
     key = jwk.loads(obj)
     new_obj = jwk.dumps(key)
     self.assertEqual(obj['x'], new_obj['x'])
Пример #26
0
def refresh_token():
    req = flask.request
    session_cookie = req.cookies.get(SESSION_COOKIE_NAME)
    session_id = session_cookie
    if session_id in sessions:
        session = sessions[session_id]
    else:
        return flask.make_response(flask.redirect(own_url, code=303))

    log.info('Refresh token, session {}'.format(session_id))

    data = {
        'refresh_token': session['refresh_token'],
        'grant_type': 'refresh_token'
    }
    headers = {
        'Authorization':
        'Basic ' + encode_client_creds(client_id, client_secret),
        'Content-type': 'application/x-www-form-urlencoded'
    }

    log.info("Refresh token from url: '{}'".format(oauth2_token_url))
    response = requests.post(oauth2_token_url, data=data, headers=headers)
    log_response('REFRESH-TOKEN', response)

    if response.status_code != 200:
        return 'Failed with status {}: {}'.format(response.status_code,
                                                  response.text)

    response_json = response.json()
    for token_type in ['id_token', 'access_token', 'refresh_token']:
        if token_type in response_json:
            log.info("Got {} token '{}'".format(token_type,
                                                response_json[token_type]))

    if 'id_token' in response_json:
        id_token = response_json['id_token']

        token_pub_jwk_json = token_get_jwk(id_token)
        token_pub_jwk = JsonWebKey.import_key(token_pub_jwk_json)

        claims = jwt.decode(id_token, token_pub_jwk)

        session['id_token'] = id_token,
        session['id_token_claims'] = claims

    if 'access_token' in response_json:
        session['access_token'] = response_json['access_token']

    if 'refresh_token' in response_json:
        session['refresh_token'] = response_json['refresh_token']
    sessions[session_cookie] = session

    resp = flask.make_response(flask.redirect(own_url, code=303))
    return resp
Пример #27
0
 def test_loads_okp_private_key(self):
     obj = {
         'x': '11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo',
         'd': 'nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A',
         'crv': 'Ed25519',
         'kty': 'OKP'
     }
     jwk = JsonWebKey(RFC8037_ALGORITHMS)
     key = jwk.loads(obj)
     new_obj = jwk.dumps(key)
     self.assertEqual(obj['d'], new_obj['d'])
Пример #28
0
    def test_dumps_okp_public_key(self):
        key = read_file_path('ed25519-ssh.pub')
        jwk = JsonWebKey(RFC8037_ALGORITHMS)
        self.assertRaises(ValueError, jwk.dumps, key)

        obj = jwk.dumps(key, 'OKP')
        self.assertEqual(obj['kty'], 'OKP')
        self.assertEqual(obj['crv'], 'Ed25519')

        key = read_file_path('ed25519-pub.pem')
        obj = jwk.dumps(key, 'OKP')
        self.assertEqual(obj['kty'], 'OKP')
        self.assertEqual(obj['crv'], 'Ed25519')
Пример #29
0
def signing_key():
    jwk = JsonWebKey.generate_key("RSA", 2048, is_private=True)
    return {
        "id":
        "somekey",
        "private_key":
        jwk.get_private_key().private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption(),
        ),
        "jwk":
        jwk.as_dict(),
    }
Пример #30
0
    def readToken(self, token):
        """Decode self token

        :param str token: token to decode

        :return: S_OK(dict)/S_ERROR()
        """
        result = self.db.getKeySet()
        if not result["OK"]:
            return result
        try:
            return S_OK(jwt.decode(token, JsonWebKey.import_key_set(result["Value"].as_dict())))
        except Exception as e:
            sLog.exception(e)
            return S_ERROR(repr(e))