mirror of
https://github.com/jupyterhub/jupyterhub.git
synced 2025-10-18 07:23:00 +00:00
get OAuth working with subdomains
needs a lot of host passing around
This commit is contained in:
@@ -1059,6 +1059,7 @@ class JupyterHub(Application):
|
|||||||
db=self.db, orm=orm_service,
|
db=self.db, orm=orm_service,
|
||||||
domain=domain, host=host,
|
domain=domain, host=host,
|
||||||
hub_api_url=self.hub.api_url,
|
hub_api_url=self.hub.api_url,
|
||||||
|
hub=self.hub,
|
||||||
)
|
)
|
||||||
|
|
||||||
traits = service.traits(input=True)
|
traits = service.traits(input=True)
|
||||||
@@ -1093,6 +1094,7 @@ class JupyterHub(Application):
|
|||||||
base_url=service.prefix,
|
base_url=service.prefix,
|
||||||
)
|
)
|
||||||
self.db.add(server)
|
self.db.add(server)
|
||||||
|
|
||||||
client_store.add_client(
|
client_store.add_client(
|
||||||
client_id=service.oauth_client_id,
|
client_id=service.oauth_client_id,
|
||||||
client_secret=service.api_token,
|
client_secret=service.api_token,
|
||||||
|
@@ -20,7 +20,6 @@ import requests
|
|||||||
from tornado.gen import coroutine
|
from tornado.gen import coroutine
|
||||||
from tornado.log import app_log
|
from tornado.log import app_log
|
||||||
from tornado.httputil import url_concat
|
from tornado.httputil import url_concat
|
||||||
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
|
|
||||||
from tornado.web import HTTPError, RequestHandler
|
from tornado.web import HTTPError, RequestHandler
|
||||||
|
|
||||||
from traitlets.config import Configurable
|
from traitlets.config import Configurable
|
||||||
@@ -112,13 +111,9 @@ class HubAuth(Configurable):
|
|||||||
Only used if JupyterHub is spreading servers across subdomains.
|
Only used if JupyterHub is spreading servers across subdomains.
|
||||||
"""
|
"""
|
||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
|
@default('hub_host')
|
||||||
host = Unicode('',
|
def _default_hub_host(self):
|
||||||
help="""The public host of this service/server
|
return os.getenv('JUPYTERHUB_HOST', '')
|
||||||
|
|
||||||
Only used if JupyterHub is spreading servers across subdomains.
|
|
||||||
"""
|
|
||||||
).tag(config=True)
|
|
||||||
|
|
||||||
base_url = Unicode(os.getenv('JUPYTERHUB_SERVICE_PREFIX') or '/',
|
base_url = Unicode(os.getenv('JUPYTERHUB_SERVICE_PREFIX') or '/',
|
||||||
help="""The base URL prefix of this application
|
help="""The base URL prefix of this application
|
||||||
@@ -378,7 +373,7 @@ class HubAuth(Configurable):
|
|||||||
|
|
||||||
class HubOAuth(HubAuth):
|
class HubOAuth(HubAuth):
|
||||||
"""HubAuth using OAuth for login instead of cookies set by the Hub.
|
"""HubAuth using OAuth for login instead of cookies set by the Hub.
|
||||||
|
|
||||||
.. versionadded: 0.8
|
.. versionadded: 0.8
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -432,7 +427,7 @@ class HubOAuth(HubAuth):
|
|||||||
).tag(config=True)
|
).tag(config=True)
|
||||||
@default('oauth_redirect_uri')
|
@default('oauth_redirect_uri')
|
||||||
def _default_redirect(self):
|
def _default_redirect(self):
|
||||||
return self.host + url_path_join(self.base_url, 'oauth_callback')
|
return os.getenv('JUPYTERHUB_OAUTH_CALLBACK_URL') or url_path_join(self.base_url, 'oauth_callback')
|
||||||
|
|
||||||
oauth_authorization_url = Unicode('/hub/api/oauth2/authorize',
|
oauth_authorization_url = Unicode('/hub/api/oauth2/authorize',
|
||||||
help="The URL to redirect to when starting the OAuth process",
|
help="The URL to redirect to when starting the OAuth process",
|
||||||
@@ -625,7 +620,14 @@ class HubOAuthenticated(HubAuthenticated):
|
|||||||
|
|
||||||
|
|
||||||
class HubOAuthCallbackHandler(HubOAuthenticated, RequestHandler):
|
class HubOAuthCallbackHandler(HubOAuthenticated, RequestHandler):
|
||||||
"""OAuth Callback handler"""
|
"""OAuth Callback handler
|
||||||
|
|
||||||
|
Finishes the OAuth flow, setting a cookie to record the user's info.
|
||||||
|
|
||||||
|
Should be registered at SERVICE_PREFIX/oauth_callback
|
||||||
|
|
||||||
|
.. versionadded: 0.8
|
||||||
|
"""
|
||||||
|
|
||||||
@coroutine
|
@coroutine
|
||||||
def get(self):
|
def get(self):
|
||||||
|
@@ -43,27 +43,25 @@ from getpass import getuser
|
|||||||
import pipes
|
import pipes
|
||||||
import shutil
|
import shutil
|
||||||
from subprocess import Popen
|
from subprocess import Popen
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
from tornado import gen
|
|
||||||
|
|
||||||
from traitlets import (
|
from traitlets import (
|
||||||
HasTraits,
|
HasTraits,
|
||||||
Any, Bool, Dict, Unicode, Instance,
|
Any, Bool, Dict, Unicode, Instance,
|
||||||
default, observe,
|
default,
|
||||||
)
|
)
|
||||||
from traitlets.config import LoggingConfigurable
|
from traitlets.config import LoggingConfigurable
|
||||||
|
|
||||||
from .. import orm
|
from .. import orm
|
||||||
from ..traitlets import Command
|
from ..traitlets import Command
|
||||||
from ..spawner import LocalProcessSpawner, set_user_setuid
|
from ..spawner import LocalProcessSpawner, set_user_setuid
|
||||||
from ..utils import url_path_join, new_token
|
from ..utils import url_path_join
|
||||||
|
|
||||||
class _MockUser(HasTraits):
|
class _MockUser(HasTraits):
|
||||||
name = Unicode()
|
name = Unicode()
|
||||||
server = Instance(orm.Server, allow_none=True)
|
server = Instance(orm.Server, allow_none=True)
|
||||||
state = Dict()
|
state = Dict()
|
||||||
service = Instance(__module__ + '.Service')
|
service = Instance(__module__ + '.Service')
|
||||||
|
host = Unicode()
|
||||||
|
|
||||||
# We probably shouldn't use a Spawner here,
|
# We probably shouldn't use a Spawner here,
|
||||||
# but there are too many concepts to share.
|
# but there are too many concepts to share.
|
||||||
@@ -190,6 +188,7 @@ class Service(LoggingConfigurable):
|
|||||||
|
|
||||||
domain = Unicode()
|
domain = Unicode()
|
||||||
host = Unicode()
|
host = Unicode()
|
||||||
|
hub = Any()
|
||||||
proc = Any()
|
proc = Any()
|
||||||
|
|
||||||
# handles on globals:
|
# handles on globals:
|
||||||
@@ -257,10 +256,12 @@ class Service(LoggingConfigurable):
|
|||||||
api_token=self.api_token,
|
api_token=self.api_token,
|
||||||
oauth_client_id=self.oauth_client_id,
|
oauth_client_id=self.oauth_client_id,
|
||||||
cwd=self.cwd,
|
cwd=self.cwd,
|
||||||
|
hub=self.hub,
|
||||||
user=_MockUser(
|
user=_MockUser(
|
||||||
name=self.user,
|
name=self.user,
|
||||||
service=self,
|
service=self,
|
||||||
server=self.orm.server,
|
server=self.orm.server,
|
||||||
|
host=self.host,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
self.spawner.start()
|
self.spawner.start()
|
||||||
|
@@ -27,7 +27,7 @@ from traitlets import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from .traitlets import Command, ByteSpecification
|
from .traitlets import Command, ByteSpecification
|
||||||
from .utils import random_port
|
from .utils import random_port, url_path_join
|
||||||
|
|
||||||
|
|
||||||
class Spawner(LoggingConfigurable):
|
class Spawner(LoggingConfigurable):
|
||||||
@@ -431,6 +431,10 @@ class Spawner(LoggingConfigurable):
|
|||||||
env['JUPYTERHUB_ADMIN_ACCESS'] = '1'
|
env['JUPYTERHUB_ADMIN_ACCESS'] = '1'
|
||||||
# OAuth settings
|
# OAuth settings
|
||||||
env['JUPYTERHUB_CLIENT_ID'] = self.oauth_client_id
|
env['JUPYTERHUB_CLIENT_ID'] = self.oauth_client_id
|
||||||
|
env['JUPYTERHUB_HOST'] = self.hub.host
|
||||||
|
if self.user.server:
|
||||||
|
env['JUPYTERHUB_OAUTH_CALLBACK_URL'] = self.user.host + \
|
||||||
|
url_path_join(self.user.server.base_url, 'oauth_callback')
|
||||||
|
|
||||||
# Put in limit and guarantee info if they exist.
|
# Put in limit and guarantee info if they exist.
|
||||||
# Note that this is for use by the humans / notebook extensions in the
|
# Note that this is for use by the humans / notebook extensions in the
|
||||||
|
Reference in New Issue
Block a user