def test_get_key(self): hs_key = jwk.get_key("HS256") assert hs_key == HMACKey assert issubclass(hs_key, Key) assert issubclass(jwk.get_key("RS256"), Key) assert issubclass(jwk.get_key("ES256"), Key) assert jwk.get_key("NONEXISTENT") is None
def test_get_key(self): hs_key = jwk.get_key("HS256") assert hs_key == jwk.HMACKey assert issubclass(hs_key, Key) assert issubclass(jwk.get_key("RS256"), Key) assert issubclass(jwk.get_key("ES256"), Key) assert jwk.get_key("NONEXISTENT") is None
def pkcs11_jws_verify(token: str) -> Optional[str]: """ Perform JWS Sign with a key stored in an PKCS#11 token. This requires temporarily switching the key class for the algorithm in the token. See the documentation for pkcs11_jws_sign for more details. :return: The signed payload from the token, or None if verify is not supported """ headers = jws.get_unverified_headers(token) _alg = headers['alg'] # First, check if verify for this algorithm is supported by the token (current YubiKey can # sign with ECDSA, but not verify). # We have to do it in this hackish manner since the JOSE library will ignore any exceptions # from the verify method and just turn everything into an # JWSError('Signature verification failed.') exception. _p11key = P11Key('', _alg, P11Key_params) with _p11key.token.open(user_pin=_p11key.p11.pin) as session: _p11key._load_key(session) info = _p11key.token.slot.get_mechanism_info(_p11key._mechanism) logger.debug('Token mechanism info:\n{}'.format(info)) if pkcs11.MechanismFlag.VERIFY not in info.flags: logger.info( 'Verify is not a supported operation for algorithm {} using the PKCS#11 token' .format(_p11key._algorithm)) return None orig_key = jwk.get_key(_alg) try: # First check if verify is a supported operation using this al jwk.register_key(_alg, P11Key) res = jws.verify( token, '', algorithms=[jwk.ALGORITHMS.ES256, jwk.ALGORITHMS.RS256]) except: raise finally: jwk.register_key(_alg, orig_key) return res
def pkcs11_jws_sign(data, key=None, headers=None) -> str: """ Perform JWS Sign with a key stored in an PKCS#11 token. This requires some trickery - temporary switch out the key class for the algorithm to P11Key before calling jws.sign. It is not possible to just register a new algorithm, say ECP11, because the algorithm is included in the JWT and the consumer of the JWT would expect ES256 (or similar) and not know how to handle ECP11. :return: A signed JWT """ global P11Key_params _p11key = P11Key('', '', P11Key_params) _alg = _p11key.get_jwk_alg() orig_key = jwk.get_key(_alg) try: jwk.register_key(_alg, P11Key) res = jws.sign(data, key, algorithm=_alg, headers=headers) except: raise finally: jwk.register_key(_alg, orig_key) return res
def __init__(self): """Initialize the default configuration.""" self.CORS_ORIGINS = os.environ['ALLOWED_ORIGINS'].split(',') self.RSA_PRIVATE_KEY = pathlib.Path('keys/rsa').read_text() self.ALGORITHM = 'RS512' self.RSA_PUBLIC_KEY = jwk.get_key(self.ALGORITHM)( self.RSA_PRIVATE_KEY, self.ALGORITHM, ).public_key().to_dict() self.JWT_VALIDITY = timedelta(minutes=10) self.REFRESH_TOKEN_VALIDITY = timedelta(days=30) self.SENTRY_DSN = os.environ.get('SENTRY_DSN') self.APISPEC_TITLE = "iam" self.APISPEC_SWAGGER_UI_URL = "/" self.BASIC_AUTH_USERNAME = os.environ['BASIC_AUTH_USERNAME'] self.BASIC_AUTH_PASSWORD = os.environ['BASIC_AUTH_PASSWORD'] self.FEAT_TOGGLE_LOCAL_AUTH = bool( os.environ['FEAT_TOGGLE_LOCAL_AUTH']) self.SQLALCHEMY_DATABASE_URI = ( f"postgresql://{os.environ['DB_USERNAME']}:" f"{os.environ['DB_PASSWORD']}@{os.environ['DB_HOST']}:" f"{os.environ['DB_PORT']}/{os.environ['DB_NAME']}" f"?connect_timeout=10") self.SQLALCHEMY_TRACK_MODIFICATIONS = False self.FEAT_TOGGLE_FIREBASE = bool(os.environ['FEAT_TOGGLE_FIREBASE']) self.FIREBASE_CLIENT_CERT_URL = os.environ.get( 'FIREBASE_CLIENT_CERT_URL') self.FIREBASE_CLIENT_EMAIL = os.environ.get('FIREBASE_CLIENT_EMAIL') self.FIREBASE_CLIENT_ID = os.environ.get('FIREBASE_CLIENT_ID') self.FIREBASE_PRIVATE_KEY = os.environ.get('FIREBASE_PRIVATE_KEY') self.FIREBASE_PRIVATE_KEY_ID = os.environ.get( 'FIREBASE_PRIVATE_KEY_ID') self.FIREBASE_PROJECT_ID = os.environ.get('FIREBASE_PROJECT_ID') self.SENDGRID_API_KEY = os.environ.get('SENDGRID_API_KEY') self.LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'formatters': { 'simple': { 'format': "%(asctime)s [%(levelname)s] [%(name)s] " "%(filename)s:%(funcName)s:%(lineno)d | " "%(message)s" }, }, 'handlers': { 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', 'formatter': 'simple', }, }, 'loggers': { # All loggers will by default use the root logger below (and # hence be very verbose). To silence spammy/uninteresting log # output, add the loggers here and increase the loglevel. 'parso': { 'level': 'INFO', 'handlers': ['console'], 'propagate': False, } }, 'root': { 'level': 'DEBUG', 'handlers': ['console'], }, }
def test_register_key(self): assert jwk.register_key("ALG", jwk.Key) assert jwk.get_key("ALG") == jwk.Key with pytest.raises(TypeError): assert jwk.register_key("ALG", object)
def test_get_aes_key(self): assert issubclass(jwk.get_key("A256CBC-HS512"), Key)
def test_get_key(self): assert jwk.get_key("HS256") == jwk.HMACKey assert jwk.get_key("RS256") == jwk.RSAKey assert jwk.get_key("ES256") == jwk.ECKey assert jwk.get_key("NONEXISTENT") == None