cwaldbieser / jhub_cas_authenticator

CAS authenticator for Jupyterhub
GNU General Public License v3.0
22 stars 12 forks source link

redirection loop #4

Closed miguelmarco closed 6 years ago

miguelmarco commented 6 years ago

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?

cwaldbieser commented 6 years ago

@miguelmarco , could you tell me if you are using a release or if you are using HEAD from the master branch of the repository?

I expect the cas_login_url really ought to have a FQDN, though your observations suggest that is not a problem. The cas_service_url likewise should be the fully qualified URL that will be sent to the CAS service as the "service" parameter. The cas_service_validate_url should be the FQ URL for the CAS protocol v3 service validate endpoint. If your university uses an older CAS that only supports CAS protocol v2, then https://youruni.example.edu/cas/serviceValidate may work if you don't need attributes back, though I haven't tested.

NOTE: CAS server versions are typically different than ther CAS protocol versions. The current Apereo CAS server v5.x series supports CAS protocol v2 and v2. The older Apereo CAS server v3.x series only supported CAS protocol v2.

If you can get access to the CAS logs from your institution's CAS server, that would be the best way to troubleshoot. If the logs indicate that the service ticket was presented, but it failed to be validated, that tells you there is a problem with the ticket. If the ticket is never presented, it could be a bug in the code or a client configuration issue.

You could also try configuring your Jupyterhub to authenticate against a test CAS instance. You could stand up your own Apereo CAS, or there are other options for testing.

Let me know what you find out.

miguelmarco commented 6 years ago

Thanks for the answer, I finally found the culprit: I forgot to add a /login at the end of the cas_login_url.

Another problem I had then was that the users did authenticate, but did not exist in the system so the spawning failed. I modified a couple lines of code in the request handler to create them on the fly. For the moment I have done it in a hacky way (i.e. directly hardcoding the system command to create the user), but if you would like to add this functionality, I could try to polish it and send a pull request.

Best,

Miguel

cwaldbieser commented 6 years ago

Miguel,

Maybe you could inherit from LocalAuthenticator like in the REMOTE_USER authenticator (see line 43)?

I also wanted to follow up-- did you use the code from GitHub master, or install from PyPi? I have a couple outstanding issues I wanted to verify before cutting another release, and knowing that I'm not the only person who has success with the code increases my confidence that the bugs have been squashed.

miguelmarco commented 6 years ago

I dodn't try to inherit from another authenticator, since I assumed that the relevant methods would be overwritten by the cas authenticator.

I pip-installed the authenticator.

cwaldbieser commented 6 years ago

I think LocalAuthenticator can be used as a mixin to get the functionality to create local users. See for example, oauthenticator's code (around line 107). The base class (starting around line 390) looks like it just subclasses Authenticator and adds some implementation for letting you manage local system users.

You could ask on the Jupyterhub Google Groups list if you're not sure. I'd take it as a PR if you'd be willing to test it out and let me know how it works.

miguelmarco commented 6 years ago

I tried inheriting from LocalAuthenticator as you suggested (either directly inheriting or createing a mixin class). Both approaches have the same problem: user is not created.

The code that I added to create the user when it logs in is not in the authenticator class, but in the CASLoginHandler. More precisely, in the getmethod. Right after the succesful login is sent to the log (line 54). As I said, it is quite hacky... but it seems to work

cwaldbieser commented 6 years ago

Well, send me the PR. I'll try to get a test environment set up in the next couple days and try it out.

cwaldbieser commented 6 years ago

I've set up a test environment in the meantime. I inherited from LocalAuthenticator, and local users were created on the test system for me. I think you need to make sure you set the appropriate config flag-- c.CASLocalAuthenticator.create_system_users = True is what did the trick for me.

Hope that helps. In the meantime, I've pushed a new release to PyPi that has this change plus some other improvements.