Giter Club home page Giter Club logo

jhub_cas_authenticator's Introduction

Jupyterhub CAS Authenticator

Authenticate to Jupyterhub using the CAS 3.0 protocol (https://apereo.github.io/cas/5.1.x/protocol/CAS-Protocol-Specification.html)

Installation

This package can be installed with pip either from a local git repository or from PyPi.

Installation from local git repository:

cd jhub_cas_authenticator
pip install .

Installation from PyPi:

pip install jhub_cas_authenticator

Alternately, you can add the local project folder must be on your PYTHONPATH.

Configuration

You should edit your :file:`jupyterhub_config.py` to set the authenticator class:

c.JupyterHub.authenticator_class = 'jhub_cas_authenticator.cas_auth.CASAuthenticator'

You will also need to add settings specific to the CAS authentication configuration:

# The CAS URL to redirect unauthenticated users to.
c.CASAuthenticator.cas_login_url = 'https://cas.example.net/cas/login'

# The service URL the CAS server will redirect the browser back to on successful authentication.
# If not set, this is set to the same URL the request comes in on.  This will work fine for
# simple deployments, but deployments behind a proxy or load banalncer will likely need to
# be adjusted so the CAS service redirects back to the *real* login URL for your Jupyterhub.
c.CASAuthenticator.cas_service_url = 'https://your-jupyterhub.tld/login'

# Path to CA certificates the CAS client will trust when validating a service ticket.
c.CASAuthenticator.cas_client_ca_certs = '/path/to/ca_certs.pem'

# The CAS endpoint for validating service tickets.
c.CASAuthenticator.cas_service_validate_url = 'https://cas.example.net/cas/p3/serviceValidate'

# A set of attribute name and value tuples a user must have to be allowed access.
c.CASAuthenticator.cas_required_attribs = {('memberOf', 'jupyterhub_users')}

Just-in-Time Account Creation

If your Jupyterhub spawner relies on local users to exist for the authenticated user, it can be useful to use CASLocalAuthenticator instead of CASAuthenticator. The former inherits from LocalAuthenticator and has the property create_system_users. You can use it like this:

c.JupyterHub.authenticator_class = 'jhub_cas_authenticator.cas_auth.CASLocalAuthenticator'
# The CAS URL to redirect unauthenticated users to.
c.CASLocalAuthenticator.cas_login_url = 'https://cas.example.net/cas/login'
# The CAS URL for logging out an authenticated user.
c.CASLocalAuthenticator.cas_logout_url = 'https://cas.example.net/cas/logout'
# The service URL the CAS server will redirect the browser back to on successful authentication.
# If not set, this is set to the same URL the request comes in on.  This will work fine for
# simple deployments, but deployments behind a proxy or load banalncer will likely need to
# be adjusted so the CAS service redirects back to the *real* login URL for your Jupyterhub.
c.CASLocalAuthenticator.cas_service_url = 'https://jupyterhub.example.net/login'
# Path to CA certificates the CAS client will trust when validating a service ticket.
c.CASLocalAuthenticator.cas_client_ca_certs = '/path/to/ca_certs.pem'
# The CAS endpoint for validating service tickets.
c.CASLocalAuthenticator.cas_service_validate_url = 'https://cas.example.net/cas/p3/serviceValidate'
# A set of attribute name and value tuples a user must have to be allowed access.
c.CASLocalAuthenticator.cas_required_attribs = {('memberOf', 'jupyterhub_users')}
# Allowed logins.
c.CASLocalAuthenticator.whitelist = {'waldbiec', 'carl', 'logan'}
# Create system users just-in-time.
c.CASLocalAuthenticator.create_system_users = True

jhub_cas_authenticator's People

Contributors

cwaldbieser avatar liffiton avatar niedhui avatar wna-se avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

jhub_cas_authenticator's Issues

Does jhub_cas_authenticator plugin support django-cas?

Hello cwaldbieser,

First of all thank you for this awesome plugin, I'd like to report an issue on our below jupyterhub-deploy-docker and django-cas-server configuration.

TLDR; after trying to login jupyterhub via django-cas using jhub_cas_authenticator which has been configured to retrieve username and password data from a postgresql database; cas_auth function always return 401 Unauthorized error and does not let the dockerspawner create a notebook container for jupyterhub.

Here's the version information :

Jupyterhub (v0.9.6) https://github.com/jupyterhub/jupyterhub-deploy-docker
jhub_cas_authenticator (installed via pip inside the jupyterhub docker container the latest version v1.0.2)
django-cas https://github.com/nitmir/django-cas-server (which provides CAS 3.0 implementation)

So after we setup django-cas on CAS domain and configured the jupyterhub_config.py file for the required endpoints when we navigate to our jupyterhub instance which is running on https://jupyter.ep3data.com/hub/login, it succesfully navigates us to the cas login page but after trying to login with a user defined in postgresql database source it always return 401 unauthorized errors. I will provide the debug logs from jupyterhub as well.

I have the following jupyterhub_config.py file for your reference :

# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.

# Configuration file for JupyterHub
import os

c = get_config()

c.JupyterHub.admin_access = True
c.Spawner.default_url = '/lab'

c.JupyterHub.log_level = 'DEBUG'
c.Spawner.debug = True

# We rely on environment variables to configure JupyterHub so that we
# avoid having to rebuild the JupyterHub container every time we change a
# configuration parameter.

# Spawn single-user servers as Docker containers
c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'
# Spawn containers from this image
c.DockerSpawner.container_image = os.environ['DOCKER_NOTEBOOK_IMAGE']
# JupyterHub requires a single-user instance of the Notebook server, so we
# default to using the `start-singleuser.sh` script included in the
# jupyter/docker-stacks *-notebook images as the Docker run command when
# spawning containers.  Optionally, you can override the Docker run command
# using the DOCKER_SPAWN_CMD environment variable.
spawn_cmd = os.environ.get('DOCKER_SPAWN_CMD', "start-singleuser.sh")
c.DockerSpawner.extra_create_kwargs.update({ 'command': spawn_cmd })
# Connect containers to this Docker network
network_name = os.environ['DOCKER_NETWORK_NAME']
c.DockerSpawner.use_internal_ip = True
c.DockerSpawner.network_name = network_name
# Pass the network name as argument to spawned containers
c.DockerSpawner.extra_host_config = { 'network_mode': network_name }
# Explicitly set notebook directory because we'll be mounting a host volume to
# it.  Most jupyter/docker-stacks *-notebook images run the Notebook server as
# user `jovyan`, and set the notebook directory to `/home/jovyan/work`.
# We follow the same convention.
notebook_dir = os.environ.get('DOCKER_NOTEBOOK_DIR') or '/home/jovyan/work'
c.DockerSpawner.notebook_dir = notebook_dir
# Mount the real user's Docker volume on the host to the notebook user's
# notebook directory in the container
c.DockerSpawner.volumes = { 'jupyterhub-user-{username}': notebook_dir }
# volume_driver is no longer a keyword argument to create_container()
# c.DockerSpawner.extra_create_kwargs.update({ 'volume_driver': 'local' })
# Remove containers once they are stopped
c.DockerSpawner.remove_containers = True
# For debugging arguments passed to spawned containers
c.DockerSpawner.debug = True

# User containers will access hub by container name on the Docker network
c.JupyterHub.hub_ip = 'jupyterhub'
c.JupyterHub.hub_port = 8080

# TLS config
c.JupyterHub.port = 443
c.JupyterHub.ssl_key = os.environ['SSL_KEY']
c.JupyterHub.ssl_cert = os.environ['SSL_CERT']

# Authenticate users with GitHub OAuth
# c.JupyterHub.authenticator_class = 'oauthenticator.GitHubOAuthenticator'
# c.GitHubOAuthenticator.oauth_callback_url = os.environ['OAUTH_CALLBACK_URL']

# c.JupyterHub.authenticator_class = 'nativeauthenticator.NativeAuthenticator'
# c.NativeAuthenticator.open_signup = True


c.JupyterHub.authenticator_class = 'jhub_cas_authenticator.cas_auth.CASLocalAuthenticator'
c.CASLocalAuthenticator.cas_login_url = 'https://cas.ep3data.com/cas/login'
c.CASLocalAuthenticator.cas_logout_url = 'https://cas.ep3data.com/cas/logout'

# c.Authenticator.admin_users = {'admin','test','aydintd'}
# The service URL the CAS server will redirect the browser back to on successful authentication.
# If not set, this is set to the same URL the request comes in on.  This will work fine for
# simple deployments, but deployments behind a proxy or load banalncer will likely need to
# be adjusted so the CAS service redirects back to the *real* login URL for your Jupyterhub.
c.CASLocalAuthenticator.cas_service_url = 'https://jupyter.ep3data.com/hub/login'

#c.CASLocalAuthenticator.cas_client_ca_certs = '/path/to/ca_certs.pem'
c.CASLocalAuthenticator.cas_service_validate_url = 'https://cas.ep3data.com/cas/p3/serviceValidate'
c.CASLocalAuthenticator.cas_required_attribs = {('memberOf', 'jupyterhub_users')}
c.CASLocalAuthenticator.whitelist = {'admin','test','aydintd','peterb','chirag'}
c.Authenticator.admin_users = {'admin','test'}
# c.CASLocalAuthenticator.create_system_users = True

# Persist hub data on volume mounted inside container
data_dir = os.environ.get('DATA_VOLUME_CONTAINER', '/data')

c.JupyterHub.cookie_secret_file = os.path.join(data_dir,
    'jupyterhub_cookie_secret')

c.JupyterHub.db_url = 'postgresql://postgres:{password}@{host}/{db}'.format(
    host=os.environ['POSTGRES_HOST'],
    password=os.environ['POSTGRES_PASSWORD'],
    db=os.environ['POSTGRES_DB'],
)

What I see in the jupyterhub debug logs during the login attempt is :

[I 2020-08-27 22:34:41.037 JupyterHub log:158] 302 GET /hub -> /hub/ (@184.69.65.66) 0.62ms
[I 2020-08-27 22:34:41.074 JupyterHub log:158] 302 GET /hub/ -> /hub/login (@184.69.65.66) 1.08ms
[D 2020-08-27 22:34:41.107 JupyterHub cas_auth:49] Has service ticket? False
[D 2020-08-27 22:34:41.107 JupyterHub cas_auth:57] Redirecting to CAS to get service ticket: https://cas.ep3data.com/cas/login?service=https%3A%2F%2Fjupyter.ep3data.com%2Fhub%2Flogin
[I 2020-08-27 22:34:41.108 JupyterHub log:158] 302 GET /hub/login -> https://cas.ep3data.com/cas/login?service=https%3A%2F%2Fjupyter.ep3data.com%2Fhub%2Flogin (@184.69.65.66) 1.19ms
[D 2020-08-27 22:34:55.909 JupyterHub cas_auth:49] Has service ticket? True
[D 2020-08-27 22:34:55.909 JupyterHub cas_auth:62] Validating service ticket ST-B49MY3E...
[D 2020-08-27 22:34:55.910 JupyterHub cas_auth:122] Validate URL: https://cas.ep3data.com/cas/p3/serviceValidate?service=https%3A%2F%2Fjupyter.ep3data.com%2Fhub%2Flogin&ticket=ST-B49MY3EmJEYYYe3yVvuKXaSYFurmHUBTW6oo3TdF7hLj5bBpJFRtoiKOJPh5A
[D 2020-08-27 22:35:15.911 JupyterHub cas_auth:130] Response was unsuccessful: None
[D 2020-08-27 22:35:15.911 JupyterHub base:890] No template for 401
[W 2020-08-27 22:35:15.912 JupyterHub log:158] 401 GET /hub/login?ticket=ST-B49MY3EmJEYYYe3yVvuKXaSYFurmHUBTW6oo3TdF7hLj5bBpJFRtoiKOJPh5A (@184.69.65.66) 20003.36ms
[D 2020-08-27 22:35:16.157 JupyterHub log:158] 304 GET /favicon.ico (@184.69.65.66) 1.06ms

What I see when I clicked on the ServiceValidation URL generated for this login I can see that the user authentication is actually succesful on the django-cas side before it expires :

<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
<cas:authenticationSuccess>
<cas:user>test</cas:user>
<cas:attributes>
<cas:authenticationDate>2020-08-27T22:34:55+00:00</cas:authenticationDate>
<cas:longTermAuthenticationRequestTokenUsed>false</cas:longTermAuthenticationRequestTokenUsed>
<cas:isFromNewLogin>true</cas:isFromNewLogin>
</cas:attributes>
<cas:attribute name="authenticationDate" value="2020-08-27T22:34:55+00:00"/>
<cas:attribute name="longTermAuthenticationRequestTokenUsed" value="false"/>
<cas:attribute name="isFromNewLogin" value="true"/>
</cas:authenticationSuccess>
</cas:serviceResponse>

So even it returns a successful authentication code, for some reason cas_auth function still returns .[.. cas_auth:130] Response was unsuccessful: None so that makes me think maybe the plugin does not support django-cas at all.

If you can share your insights on this issue here I'd be very appreciated and if we can make this work on our end I can provide a technical documentation on how to hookup jupyterhub + django-cas by using this plugin for the community!

Please let us know your thoughts!

find_child_element throughs a Value exception when CAS response contains comments

tag = etree.QName(child_elm)

The find_child_element function throughs an error when the XML response from the CAS server contains comment objects.
As a workaround I added a test before the line referenced above to check if the element is not a comment.

def find_child_element(elm, child_local_name):
    """
    Find an XML child element by local tag name.
    """
    for n in range(len(elm)):
        child_elm = elm[n]
        if not isinstance(child_elm, etree._Comment):
            tag = etree.QName(child_elm)
            if tag.localname == child_local_name:
                return child_elm
    return None

I am not sure if this is the best way to fix this issue.

not working

I did set in the jupyterhub_config.py following values:

c.JupyterHub.authenticator_class   = 'jhub_cas_authenticator.cas_auth.CASAuthenticator'
c.CASAuthenticator.cas_login_url   = 'https://myCASServer:port/cas/login'
c.CASAuthenticator.cas_logout_url  = 'https://myCASServer:port/cas/logout'
c.CASAuthenticator.cas_service_url = 'https://mypc:jupyterHubPort/login'
c.CASAuthenticator.cas_service_validate_url = 'https://myCASServer:port/cas/serviceValidate'

c.CASAuthenticator.cas_client_ca_certs       = '../bin/mycertificate.cer'
c.CASLocalAuthenticator.cas_required_attribs = {('memberOf', 'jupyterhub_users')}
c.CASLocalAuthenticator.whitelist            = {'myuserid'}
c.CASLocalAuthenticator.create_system_users  = True

On going to mypc:jupyterHubPort (with Ubuntu 22.04) the request runs for a long time and finally breaks with a timeout.

For another python program with Flask on the same computer I have following settings for the CAS that work properly:

    cas_client = CASClient(
        version=3,
        service_url=f'http://mypc:myotherport/login?next=%2Fapp',
        server_url='https://myCASServer:port/cas/',
        verify_ssl_certificate='../bin/mycertificate.cer'
    )

What is wrong with my settings.

Logout not implemented

When pressing a logout button in Jupyterhub, it logs out of Jupyterhub and redirects to the login url. The login URL redirects to the CAS login url, and if it hasn't been too long, that automatically redirects back to the Jupyterhub service and logs you in. So pressing "logout" results in some redirects that end up back at the same page, still logged in.

I could work on implementing logout and submit a pull request if it would help.

CASLocalAuthenticator does not create the users at login

I have installed a test server that uses CASLocalAuthenticator, with c.CASLocalAuthenticator.create_system_users = True

However, when a user correctly authenticates, it is not created in the system; and a get a 'getpwham(): name not found' error.

When I restart the jupyterhub server, then the users that did log before get created in the system, and then they can normally use the system, but what would make sense is to have them created at login time.

Logging

Hi,

how can I configure jupyterhub for see debug logs? I saw that in the code cas_auth.py there are some usefull logs.

Thanks.

Whitelist doesn't limit access

The authenticator whitelist doesn't seem to function for me. I've tried setting both c.Authenticator.whitelist and c.CASAuthenticator.whitelist in jupyterhub_config.py, and in both cases, a CAS-authenticated user who is not in the whitelist is able to log in.

I deleted the user from within Jupyterhub's admin interface before each test, as the docs suggest that a user in the database but not the config whitelist will still be able to log in. Is it possible that there is some other hidden state leftover from the user's previous login that overrides the whitelist, or is CASAuthenticator itself overriding the whitelist?

redirection loop

Dear cwaldbieser

We are trying to use your authenticator against the sso service of our university, but I get a redirection loop.

My configuration is as follows:

c.JupyterHub.authenticator_class = 'jhub_cas_authenticator.cas_auth.CASAuthenticator'
c.CASAuthenticator.cas_login_url = 'https:///login'
c.CASAuthenticator.cas_service_url = 'https://'
c.CASAuthenticator.cas_client_ca_certs = '/etc/ssl/certs/DigiCert_Assured_ID_Root_CA.pem'
c.CASAuthenticator.cas_service_validate_url = 'https:///serviceValidate'
c.CASAuthenticator.cas_required_attribs = set()

What happens is that when a goes to our jupyterhub server, it is redirected to the university sso page (as expected), enters the credentials and then is redirected back to our site with a ?ticket=.... parameter in the url.

I imagined that the ticket parameter should then be parsed by the authenticator to check if it is valid or not. However, the code responsible for that (the get method of cas_auth.py) does not get the full url: the ticket parameter is stripped from it.

Am I doing something wrong or is there some bug in the code?

Deprecate 'whitelist' and replace with 'allowed_users`

If I follow the example in the README, and set

c.CASLocalAuthenticator.whitelist = {'foo'}

I get a warning

jupyterhub-jupyterhub-1  | [W 2023-03-17 16:34:31.450 JupyterHub auth:175] CASLocalAuthenticator.whitelist is deprecated in JupyterHub 1.2, use CASLocalAuthenticator.allowed_users instead

However, if I replace whitelist with allowed_users, while the error message goes away, the server is now open to any user, since jhub_cas_authenticator is only checking the "whitelist" variable.

I propose that the check against whitelist is replace with a check against either variable.

401 : Unauthorized CAS

401_1

Hi im not able to start a server when I login. My CAS server shows, I complete with my user and password and succes, then I got stuck in that screen.
login

Thats logs

config_1

Thats my config.py

I already use CASAuthenticator (not Local) same problem.
I use normally with PAM authenticator, but I need massive user configuration

jupyterhub can't correctly recognized User

I use k8s deployer jupytehub and cas, But I login it. Jupyterhub return 401 error
jupyterhub and cas configure:

c.JupyterHub.authenticator_class = 'jhub_cas_authenticator.cas_auth.CASAuthenticator' c.CASAuthenticator.cas_login_url= https://xlab.cmbchina.biz:8443/login
c.CASAuthenticator.cas_service_validate_url= http://10.105.254.73:8080/cas/p3/serviceValidate
c.CASAuthenticator.cas_service_url=https://xlab.cmbchina.biz:8443/jupyterhub/login
c.CASAuthenticator.cas_required_attribs = {('memberOf', '+ jupyterhub_users')}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.