Ejemplo n.º 1
0
def get_page(path, app, hub=True, **kw):
    if hub:
        prefix = app.hub.base_url
    else:
        prefix = app.base_url
    base_url = ujoin(public_host(app), prefix)
    return async_requests.get(ujoin(base_url, path), **kw)
Ejemplo n.º 2
0
def get_page(path, app, hub=True, **kw):
    if "://" in path:
        raise ValueError(
            "Not a hub page path: %r. Did you mean async_requests.get?" % path)
    if hub:
        prefix = app.hub.base_url
    else:
        prefix = app.base_url
    base_url = ujoin(public_host(app), prefix)
    return async_requests.get(ujoin(base_url, path), **kw)
Ejemplo n.º 3
0
def get_page(path, app, hub=True, **kw):
    if "://" in path:
        raise ValueError(
            "Not a hub page path: %r. Did you mean async_requests.get?" % path
        )
    if hub:
        prefix = app.hub.base_url
    else:
        prefix = app.base_url
    base_url = ujoin(public_host(app), prefix)
    return async_requests.get(ujoin(base_url, path), **kw)
Ejemplo n.º 4
0
 def username_from_token(self, token):
     """Turn a user token into a username"""
     uri = url_concat(ujoin(self.oauth_url, 'getcert'), {
         'oauth_token': token,
     })
     uri, _, _ = self.oauth_client.sign(uri)
     resp = yield self.client.fetch(uri)
     # FIXME: handle failure
     reply = resp.body.decode('utf8', 'replace')
     _, cert_txt = reply.split('\n', 1)
     cert = load_certificate(FILETYPE_PEM, cert_txt)
     username = None
     for i in range(cert.get_extension_count()):
         ext = cert.get_extension(i)
         if ext.get_short_name().decode('ascii', 'replace') == 'subjectAltName':
             data = ext.get_data()
             # cert starts with some weird bytes. Not sure why or if they are consistent
             username = data[4:].decode('utf8').lower()
             # workaround notebook bug not handling @
             username = username.replace('@', '.')
             break
     if username is None:
         raise ValueError("Failed to get username from cert: %s", cert_txt)
     
     return username, cert_txt
Ejemplo n.º 5
0
 def username_from_token(self, token):
     """Turn a user token into a username"""
     uri = url_concat(ujoin(self.oauth_url, 'getcert'), {
         'oauth_token': token,
     })
     uri, _, _ = self.oauth_client.sign(uri)
     resp = yield self.client.fetch(uri)
     # FIXME: handle failure
     reply = resp.body.decode('utf8', 'replace')
     _, cert_txt = reply.split('\n', 1)
     cert = load_certificate(FILETYPE_PEM, cert_txt)
     username = None
     for i in range(cert.get_extension_count()):
         ext = cert.get_extension(i)
         if ext.get_short_name().decode('ascii', 'replace') == 'subjectAltName':
             data = ext.get_data()
             # cert starts with some weird bytes. Not sure why or if they are consistent
             username = data[4:].decode('utf8').lower()
             # workaround notebook bug not handling @
             username = username.replace('@', '.')
             break
     if username is None:
         raise ValueError("Failed to get username from cert: %s", cert_txt)
     
     return username, cert_txt
Ejemplo n.º 6
0
 def get_user_token(self, token, verifier):
     """Get a user token from an oauth callback parameters"""
     uri = url_concat(ujoin(self.oauth_url, "token"), {"oauth_token": token, "oauth_verifier": verifier})
     uri, _, _ = self.oauth_client.sign(uri)
     resp = yield self.client.fetch(uri)
     # FIXME: handle failure
     reply = resp.body.decode("utf8", "replace")
     return parse_qs(reply)["oauth_token"][0]
Ejemplo n.º 7
0
def test_authed_user_bypasses_login(app):
    # A logged in user should go straight to the control panel
    cookies = app.login_user('river')
    r = requests.get(public_url(app), cookies=cookies)
    r.raise_for_status()
    url = public_url(app)
    print(url)
    print(app.hub.server.base_url)
    assert r.url == ujoin(url, app.hub.server.base_url, 'home')
Ejemplo n.º 8
0
def test_authed_user_bypasses_login(app):
    # A logged in user should go straight to the control panel
    cookies = app.login_user('river')
    r = requests.get(public_url(app), cookies=cookies)
    r.raise_for_status()
    url = public_url(app)
    print(url)
    print(app.hub.server.base_url)
    assert r.url == ujoin(url, 'hub/home')
Ejemplo n.º 9
0
 def get_user_token(self, token, verifier):
     """Get a user token from an oauth callback parameters"""
     uri = url_concat(ujoin(self.oauth_url, 'token'), {
         'oauth_token': token,
         'oauth_verifier': verifier,
     })
     uri, _, _ = self.oauth_client.sign(uri)
     resp = yield self.client.fetch(uri)
     # FIXME: handle failure
     reply = resp.body.decode('utf8', 'replace')
     return parse_qs(reply)['oauth_token'][0]
Ejemplo n.º 10
0
def test_whitelist(app):
    url = public_url(app)
    r = requests.post(ujoin(url, 'hub/oauth_callback'),
                      data={
                          'username': '******',
                          'password': '******'
                      })
    assert r.status_code == 403
    text = ('Your username is not whitelisted on this server. '
            'Please contact the system administrator.')
    assert text in r.text
Ejemplo n.º 11
0
 def get_user_token(self, token, verifier):
     """Get a user token from an oauth callback parameters"""
     uri = url_concat(ujoin(self.oauth_url, 'token'), {
         'oauth_token': token,
         'oauth_verifier': verifier,
     })
     uri, _, _ = self.oauth_client.sign(uri)
     resp = yield self.client.fetch(uri)
     # FIXME: handle failure
     reply = resp.body.decode('utf8', 'replace')
     return parse_qs(reply)['oauth_token'][0]
Ejemplo n.º 12
0
 def get_oauth_token(self):
     """Get the temporary OAuth token"""
     uri = url_concat(
         ujoin(self.oauth_url, "initiate"), {"oauth_callback": self.callback_url, "certreq": self.certreq}
     )
     uri, _, _ = self.oauth_client.sign(uri)
     req = HTTPRequest(uri)
     # FIXME: handle failure (CILogon replies with 200 on failure)
     resp = yield self.client.fetch(req)
     reply = resp.body.decode("utf8", "replace")
     credentials = parse_qs(reply)
     return credentials["oauth_token"][0]
Ejemplo n.º 13
0
def test_github_login_no_auth(app, io_loop):
    # Test that login page uses GitHub OAuth
    print(app.hub.server.is_up())
    routes = io_loop.run_sync(app.proxy.get_routes)
    print(routes)
    print(app.hub.server)
    url = public_url(app)
    print(url)
    r = requests.get(url)
    r.raise_for_status()
    assert r.url == ujoin(url, app.hub.server.base_url, 'login')
    assert "Sign in with GitHub" in r.text
Ejemplo n.º 14
0
def test_github_login_no_auth(app, io_loop):
    # Test that login page uses GitHub OAuth
    print(app.hub.server.is_up())
    routes = io_loop.run_sync(app.proxy.get_routes)
    print(routes)
    print(app.hub.server)
    url = public_url(app)
    print(url)
    r = requests.get(url)
    r.raise_for_status()
    assert r.url == ujoin(url, 'hub/login')
    assert "Sign in with GitHub" in r.text
Ejemplo n.º 15
0
async def api_request(app,
                      *api_path,
                      method='get',
                      noauth=False,
                      bypass_proxy=False,
                      **kwargs):
    """Make an API request"""
    if bypass_proxy:
        # make a direct request to the hub,
        # skipping the proxy
        base_url = app.hub.url
    else:
        base_url = public_url(app, path='hub')
    headers = kwargs.setdefault('headers', {})

    if 'Authorization' not in headers and not noauth and 'cookies' not in kwargs:
        # make a copy to avoid modifying arg in-place
        kwargs['headers'] = h = {}
        h.update(headers)
        h.update(auth_header(app.db, kwargs.pop('name', 'admin')))

    if 'cookies' in kwargs:
        # for cookie-authenticated requests,
        # set Referer so it looks like the request originated
        # from a Hub-served page
        headers.setdefault('Referer', ujoin(base_url, 'test'))

    url = ujoin(base_url, 'api', *api_path)
    f = getattr(async_requests, method)
    if app.internal_ssl:
        kwargs['cert'] = (app.internal_ssl_cert, app.internal_ssl_key)
        kwargs["verify"] = app.internal_ssl_ca
    resp = await f(url, **kwargs)
    assert "frame-ancestors 'self'" in resp.headers['Content-Security-Policy']
    assert (ujoin(app.hub.base_url, "security/csp-report")
            in resp.headers['Content-Security-Policy'])
    assert 'http' not in resp.headers['Content-Security-Policy']
    if not kwargs.get('stream', False) and resp.content:
        assert resp.headers.get('content-type') == 'application/json'
    return resp
Ejemplo n.º 16
0
def test_whitelist(app):
    url = public_url(app)
    r = requests.post(
        ujoin(url, app.hub.server.base_url, 'oauth_callback'),
        data={
            'username': '******',
            'password': '******'
        }
    )
    assert r.status_code == 403
    text = ('Your username is not whitelisted on this server. '
            'Please contact the system administrator.')
    assert text in r.text
Ejemplo n.º 17
0
async def api_request(
    app, *api_path, method='get', noauth=False, bypass_proxy=False, **kwargs
):
    """Make an API request"""
    if bypass_proxy:
        # make a direct request to the hub,
        # skipping the proxy
        base_url = app.hub.url
    else:
        base_url = public_url(app, path='hub')
    headers = kwargs.setdefault('headers', {})

    if 'Authorization' not in headers and not noauth and 'cookies' not in kwargs:
        # make a copy to avoid modifying arg in-place
        kwargs['headers'] = h = {}
        h.update(headers)
        h.update(auth_header(app.db, kwargs.pop('name', 'admin')))

    if 'cookies' in kwargs:
        # for cookie-authenticated requests,
        # set Referer so it looks like the request originated
        # from a Hub-served page
        headers.setdefault('Referer', ujoin(base_url, 'test'))

    url = ujoin(base_url, 'api', *api_path)
    f = getattr(async_requests, method)
    if app.internal_ssl:
        kwargs['cert'] = (app.internal_ssl_cert, app.internal_ssl_key)
        kwargs["verify"] = app.internal_ssl_ca
    resp = await f(url, **kwargs)
    assert "frame-ancestors 'self'" in resp.headers['Content-Security-Policy']
    assert (
        ujoin(app.hub.base_url, "security/csp-report")
        in resp.headers['Content-Security-Policy']
    )
    assert 'http' not in resp.headers['Content-Security-Policy']
    if not kwargs.get('stream', False) and resp.content:
        assert resp.headers.get('content-type') == 'application/json'
    return resp
Ejemplo n.º 18
0
 def get_oauth_token(self):
     """Get the temporary OAuth token"""
     uri = url_concat(ujoin(self.oauth_url, "initiate"), {
         'oauth_callback': self.oauth_callback_url,
         'certreq': self.certreq,
     })
     uri, _, _ = self.oauth_client.sign(uri)
     req = HTTPRequest(uri)
     # FIXME: handle failure (CILogon replies with 200 on failure)
     resp = yield self.client.fetch(req)
     reply = resp.body.decode('utf8', 'replace')
     credentials = parse_qs(reply)
     return credentials['oauth_token'][0]
Ejemplo n.º 19
0
def public_url(app, user_or_service=None, path=''):
    """Return the full, public base URL (including prefix) of the given JupyterHub instance."""
    if user_or_service:
        if app.subdomain_host:
            host = user_or_service.host
        else:
            host = public_host(app)
        prefix = user_or_service.prefix
    else:
        host = public_host(app)
        prefix = Server.from_url(app.proxy.public_url).base_url
    if path:
        return host + ujoin(prefix, path)
    else:
        return host + prefix
Ejemplo n.º 20
0
def public_url(app, user_or_service=None, path=''):
    """Return the full, public base URL (including prefix) of the given JupyterHub instance."""
    if user_or_service:
        if app.subdomain_host:
            host = user_or_service.host
        else:
            host = public_host(app)
        prefix = user_or_service.prefix
    else:
        host = public_host(app)
        prefix = Server.from_url(app.proxy.public_url).base_url
    if path:
        return host + ujoin(prefix, path)
    else:
        return host + prefix
    def username_from_token(self, token):
        """Turn a user token into a username

        Username is stored differently than CILogon"""
        uri = url_concat(ujoin(self.oauth_url, 'getcert'), {
            'oauth_token': token,
        })
        uri, _, _ = self.oauth_client.sign(uri)
        resp = yield self.client.fetch(uri)
        # FIXME: handle failure
        reply = resp.body.decode('utf8', 'replace')
        username_string, cert_txt = reply.split('\n', 1)
        username_string_splitted = username_string.split('=', 1)

        if len(username_string_splitted) != 2:
            raise ValueError("Failed to get username from: %s", username_string)

        username = username_string_splitted[1]
        return username, cert_txt
Ejemplo n.º 22
0
    def username_from_token(self, token):
        """Turn a user token into a username"""
        uri = url_concat(ujoin(self.oauth_url, "getcert"), {"oauth_token": token})
        uri, _, _ = self.oauth_client.sign(uri)
        resp = yield self.client.fetch(uri)
        # FIXME: handle failure
        reply = resp.body.decode("utf8", "replace")
        _, cert_txt = reply.split("\n", 1)

        cert = load_certificate(FILETYPE_PEM, cert_txt)
        username = None
        for i in range(cert.get_extension_count()):
            ext = cert.get_extension(i)
            if ext.get_short_name().decode("ascii", "replace") == "subjectAltName":
                data = ext.get_data()
                username = data[4:].decode("utf8").lower()
                # workaround notebook bug not handling @
                username = username.replace("@", ".")
                return username
    def get_oauth_token(self):
        """Get the temporary OAuth token

        Compared to the CILogonOAuthenticator we also set the lifetime and do
        more logging, everything else is the same"""
        uri = url_concat(ujoin(self.oauth_url, "initiate"), {
            'oauth_callback': self.oauth_callback_url,
            'certreq': self.certreq,
            'certlifetime': 3600*24*10
        })
        self.log.info("OAuth initiate URI: %s", str(uri))
        uri, _, _ = self.oauth_client.sign(uri)
        self.log.info("OAuth initiate URI signed: %s", str(uri))
        req = HTTPRequest(uri)
        # FIXME: handle failure (CILogon replies with 200 on failure)
        resp = yield self.client.fetch(req)
        reply = resp.body.decode('utf8', 'replace')
        credentials = parse_qs(reply)
        self.log.info("Parsed credentials: %s", str(credentials))
        return credentials['oauth_token'][0]
Ejemplo n.º 24
0
    def username_from_token(self, token):
        """Turn a user token into a username

        Username is stored differently than CILogon"""
        uri = url_concat(ujoin(self.oauth_url, 'getcert'), {
            'oauth_token': token,
        })
        uri, _, _ = self.oauth_client.sign(uri)
        resp = yield self.client.fetch(uri)
        # FIXME: handle failure
        reply = resp.body.decode('utf8', 'replace')
        username_string, cert_txt = reply.split('\n', 1)
        username_string_splitted = username_string.split('=', 1)

        if len(username_string_splitted) != 2:
            raise ValueError("Failed to get username from: %s",
                             username_string)

        username = username_string_splitted[1]
        return username, cert_txt
Ejemplo n.º 25
0
    def get_oauth_token(self):
        """Get the temporary OAuth token

        Compared to the CILogonOAuthenticator we also set the lifetime and do
        more logging, everything else is the same"""
        uri = url_concat(
            ujoin(self.oauth_url, "initiate"), {
                'oauth_callback': self.oauth_callback_url,
                'certreq': self.certreq,
                'certlifetime': 3600 * 24 * 10
            })
        self.log.info("OAuth initiate URI: %s", str(uri))
        uri, _, _ = self.oauth_client.sign(uri)
        self.log.info("OAuth initiate URI signed: %s", str(uri))
        req = HTTPRequest(uri)
        # FIXME: handle failure (CILogon replies with 200 on failure)
        resp = yield self.client.fetch(req)
        reply = resp.body.decode('utf8', 'replace')
        credentials = parse_qs(reply)
        self.log.info("Parsed credentials: %s", str(credentials))
        return credentials['oauth_token'][0]
Ejemplo n.º 26
0
 def login_url(self, base_url):
     return ujoin(base_url, 'oauth_login')
Ejemplo n.º 27
0
 def login_url(self, base_url):
     return ujoin(base_url, "oauth_login")