-
Notifications
You must be signed in to change notification settings - Fork 132
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #384 from kevin-bates/use-jupyter-server
Use jupyter server as base provider
- Loading branch information
Showing
37 changed files
with
1,792 additions
and
1,769 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
coverage: | ||
status: | ||
project: | ||
default: | ||
target: auto | ||
threshold: 5% | ||
patch: | ||
default: | ||
target: 50% | ||
range: 80..100 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
# Copyright (c) Jupyter Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||
|
||
import os | ||
import logging | ||
import pytest | ||
from binascii import hexlify | ||
from traitlets.config import Config | ||
from kernel_gateway.gatewayapp import KernelGatewayApp | ||
|
||
pytest_plugins = ["pytest_jupyter.jupyter_core", "pytest_jupyter.jupyter_server"] | ||
|
||
|
||
@pytest.fixture(scope="function") | ||
def jp_configurable_serverapp( | ||
jp_nbconvert_templates, # this fixture must precede jp_environ | ||
jp_environ, | ||
jp_server_config, | ||
jp_argv, | ||
jp_http_port, | ||
jp_base_url, | ||
tmp_path, | ||
jp_root_dir, | ||
jp_logging_stream, | ||
jp_asyncio_loop, | ||
io_loop, | ||
): | ||
"""Starts a Jupyter Server instance based on | ||
the provided configuration values. | ||
The fixture is a factory; it can be called like | ||
a function inside a unit test. Here's a basic | ||
example of how use this fixture: | ||
.. code-block:: python | ||
def my_test(jp_configurable_serverapp): | ||
app = jp_configurable_serverapp(...) | ||
... | ||
""" | ||
KernelGatewayApp.clear_instance() | ||
|
||
def _configurable_serverapp( | ||
config=jp_server_config, | ||
base_url=jp_base_url, | ||
argv=jp_argv, | ||
http_port=jp_http_port, | ||
**kwargs, | ||
): | ||
c = Config(config) | ||
|
||
if "auth_token" not in c.KernelGatewayApp and not c.IdentityProvider.token: | ||
default_token = hexlify(os.urandom(4)).decode("ascii") | ||
c.IdentityProvider.token = default_token | ||
|
||
app = KernelGatewayApp.instance( | ||
# Set the log level to debug for testing purposes | ||
log_level="DEBUG", | ||
port=http_port, | ||
port_retries=0, | ||
base_url=base_url, | ||
config=c, | ||
**kwargs, | ||
) | ||
app.log.propagate = True | ||
app.log.handlers = [] | ||
# Initialize app without httpserver | ||
if jp_asyncio_loop.is_running(): | ||
app.initialize(argv=argv, new_httpserver=False) | ||
else: | ||
|
||
async def initialize_app(): | ||
app.initialize(argv=argv, new_httpserver=False) | ||
|
||
jp_asyncio_loop.run_until_complete(initialize_app()) | ||
# Reroute all logging StreamHandlers away from stdin/stdout since pytest hijacks | ||
# these streams and closes them at unfortunate times. | ||
stream_handlers = [h for h in app.log.handlers if isinstance(h, logging.StreamHandler)] | ||
for handler in stream_handlers: | ||
handler.setStream(jp_logging_stream) | ||
app.log.propagate = True | ||
app.log.handlers = [] | ||
app.start_app() | ||
return app | ||
|
||
return _configurable_serverapp | ||
|
||
|
||
@pytest.fixture(autouse=True) | ||
def jp_server_cleanup(jp_asyncio_loop): | ||
yield | ||
app: KernelGatewayApp = KernelGatewayApp.instance() | ||
try: | ||
jp_asyncio_loop.run_until_complete(app.async_shutdown()) | ||
except (RuntimeError, SystemExit) as e: | ||
print("ignoring cleanup error", e) | ||
if hasattr(app, "kernel_manager"): | ||
app.kernel_manager.context.destroy() | ||
KernelGatewayApp.clear_instance() | ||
|
||
|
||
@pytest.fixture | ||
def jp_auth_header(jp_serverapp): | ||
"""Configures an authorization header using the token from the serverapp fixture.""" | ||
return {"Authorization": f"token {jp_serverapp.identity_provider.token}"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
# Copyright (c) Jupyter Development Team. | ||
# Distributed under the terms of the Modified BSD License. | ||
"""Gateway Identity Provider interface | ||
This defines the _authentication_ layer of Jupyter Server, | ||
to be used in combination with Authorizer for _authorization_. | ||
""" | ||
from traitlets import default | ||
from tornado import web | ||
|
||
from jupyter_server.auth.identity import IdentityProvider, User | ||
from jupyter_server.base.handlers import JupyterHandler | ||
|
||
|
||
class GatewayIdentityProvider(IdentityProvider): | ||
""" | ||
Interface for providing identity management and authentication for a Gateway server. | ||
""" | ||
|
||
@default("token") | ||
def _token_default(self): | ||
return self.parent.auth_token | ||
|
||
@property | ||
def auth_enabled(self): | ||
if not self.token: | ||
return False | ||
return True | ||
|
||
def should_check_origin(self, handler: JupyterHandler) -> bool: | ||
"""Should the Handler check for CORS origin validation? | ||
Origin check should be skipped for token-authenticated requests. | ||
Returns: | ||
- True, if Handler must check for valid CORS origin. | ||
- False, if Handler should skip origin check since requests are token-authenticated. | ||
""" | ||
# Always check the origin unless operator configured gateway to allow any | ||
return handler.settings["kg_allow_origin"] != "*" | ||
|
||
def generate_anonymous_user(self, handler: web.RequestHandler) -> User: | ||
"""Generate a random anonymous user. | ||
For use when a single shared token is used, | ||
but does not identify a user. | ||
""" | ||
name = display_name = f"Anonymous" | ||
initials = "An" | ||
color = None | ||
return User(name.lower(), name, display_name, initials, None, color) | ||
|
||
def is_token_authenticated(self, handler: web.RequestHandler) -> bool: | ||
"""The default authentication flow of Gateway is token auth. | ||
The only other option is no auth | ||
""" | ||
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.