CosigNego is a Python library (usable from the shell) which bridges the gap between Cosign and Kerberos (actually GSSAPI via SPNEGO) authentication. It's customised for use on Informatics sites due to limitations in the way Cosign and/or SPNEGO work together.

DICE USERS: This is not a supported service. We would be pleased to receive feedback and discuss its uses, but this tool is available on a Not-A-Service basis only.

The Problem

Our managed clients (and most Kerberised self-managed clients) can bypass the password dialog presented by our Cosign service using a trick on the cosign login page itself. Specifically the Cosign server attempts to access an SPNEGO-protected resource using a Javascript HTTP (HEAD) Request. If this succeeds (demonstrating that the user agent supports SPNEGO and has valid credentials) the Javascript initiates a redirect to an SPNEGO-protected version of the login CGI, allowing appropriate cookies to be set.

The trick seems to be implemented using Javascript because there does not appear to be any other means of conditionally redirecting users from the cosign 'landing' page as provided by cosign client webservers and the downsides of this are obvious: the functionality is being implemented in-band, using a mechanism only supported by browsers which are able and willing to interpret and execute Javascript. Otherwise it requires prior knowledge of the two different, "secret" (well, effectively so to any client which doesn't talk Javascript) locations in order to pass. A particular problem is that it's difficult even to detect automatically whether or not you're authorised, given that the user agent will end up with a 200 no matter what.

We haven't found anynone who has solved this in a standard way. An obvious answer would be to attempt Negotiate-Auth (SPNEGO) and fall back to Basic (as might IIS in a managed environment), but that doesn't work for authentication schemes which involve requesting a username and password in-band using a CGI form. In this method, as far as the browser sees things, you're falling back to no authentication if Negotiate fails, given that the "error" response necessarily presents the login form with status 200. Is this suggestive that the authentication model is broken by design? It's not clear to me...

Solutions

So, the interim solution is my CosigNego library. This has been provided with the arbitrary SPNEGO paths required to dance around Cosign, and can be supplied with alternatives for use with other similar systems (though it's entirely untested for this purpose and will likely require modification). This is a client-side hack, though; really this library should be following a standard routine (if not a Standard), but there seems to be a gap where one should be.

Some other solutions (that we haven't tried, or really researched) include:

  • Some sort of conditional redirect magic on the Apache server hosting the Cosign login servers. This could direct all users to the SPNEGO page and, on error, bounce them back to the "human" login page.
  • Modifying Cosign to return its login dialog within an HTTP 401, in a path which would return the WWW-Authenticate: Negotiate header expected by an SPNEGO client. This should render cosign correct in HTTP terms and permit both machine and human to authenticate.
  • A companion to WWW-Authenticate: Negotiate which allows multiple methods (Inline perhaps)?
  • Some other header-based trickery: HTTP 300 to denote multiple options!?
  • (Getting desperate) A standardised descriptor file in the root, say /negotiate.(txt|yml|json|xml|format-du-jour) , pointing to the alternative Negotiate location.

Usage

Shipped on DICE as the Python library cosignego with commandline utilities authGET, authPOST and authHTTP. As of version 0.5c:

 (Common to all)

Blends Cosign and Kerberos (SPNEGO) authentication into a yummy soup.
Allows CURL-style GET and POST requests against a URL as provided on the commandline.

Environment
-----------

This script uses the following environment variables to control its behaviour:

$COSIGN_COOKIEFILE
    This is the file in which the script will maintain its cosign cookie file.
    This contains SENSITIVE MATERIAL as it allows others to impersonate you using
    cosign and should be kept safe.

    If this is set to None then the cookie will never be stored locally, but you
    will need to perform the authentication dance every time you use the script.

$COSIGN_SPNEGO_HOST
    The host on which to attempt SPNEGO authentication to automatically retrieve
    cosign cookies.

$COSIGN_COOKIE_PATH
    The path to visit to preauthenticate using SPNEGO.

$COSIGN_SPNEGO_PATH
    The path to visit once authenticated to retrieve your cosign cookies.


 $ authGET --help  or authGET --longhelp (or authPOST, or authHTTP)


Command-Line Utilities
----------------------
The package provides three utilities:

authGET [url] 
    Performs a GET of a cosign-protected URL.
    With no arguments, just obtains cookies.

authPOST url [data=value [...]]
    Performs a POST of a cosign-protected URL.
    Performs a preliminary GET against the same URL to obtain cookies.

authHTTP [--request METHOD] [--preload] url [data=value [...]]
    Performs an arbitrary HTTP request of a cosign-protected URL.
    Requires a URL.

Performinga GET with k=v parameters is planned but currently unsupported.

All three commands support the same parameters; the principal difference is
that authPOST will perform a preliminary GET on the Cosign-protected URL before
attempting its POST.

Scripted usage:

 $ python -c 'import cosignego; help(cosignego.cosignego)'

DESCRIPTION
    CosigNego: Proof-of-concept combining Cosign and SPNEGO.

    class CosigNego
     |  Methods defined here:
     |  
     |  __init__(self, loginhost, cookiefile)
     |  
     |  getCookie(self, path)
     |      Gets a Cosign cookie using SPNEGO
     |  
     |  loadCosignURL(self, url=None, data=None, method='GET', preload=False)
     |      Loads a Cosign-protected URL by pre authenticating with kerberos.
     |      data: urlencoded data (to be used with method=POST), or None
     |      method: one of the standard HTTP request types.
     |      preload: perform an initial GET prior to a POST if required.
     |  
     [...]

Clients / Use Cases

These can be found in my homedir if they haven't been deployed already:
  • wakeweb
  • nagios-ack
  • cw3m (uses own script curl2w3m to convert cookies to w3m format)
  • Theon UI server API test client (very incomplete)

Future uses

Actually most of these would be better served by dedicated kerberised HTTP APIs:
  • RT commandline client wrapper
  • HTTP-based getpapers, submit (replacing NFS).

Future Improvements

  • Stop counting redirects and start looking at the redirected page for success/failure report.
  • Rewrite as handler for urllib2 and/or requests
  • Handle straightforward Negotiate resources, generically, too.
  • Optionally fall back to password POST
    • Better SSL handling required for this!

-- GrahamDutton - Apr 2013 — Mar 2018

Topic revision: r7 - 23 Mar 2018 - 00:41:47 - GrahamDutton
 
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback
This Wiki uses Cookies