index.html 0000644 0001171 0001630 00000004622 12307076344 011155 0 ustar bwk fac
If your project is going to require users to log in with a Princeton netid, you should use this code, which has the great advantage that the user's password is sent only to a trusted third party (i.e., not you) that determines securely whether it is a valid Princeton netid and does not return to your code unless it is.
Your system might display a welcome page like this one, with a login link that points to the authentication page. After a successful call to CASClient's Authenticate(), the authentication page would set a session cookie indicating successful login and redirect to a page inside the site.
Here is a PHP version:
The PHP client code is here and the PHP test script is here.
Here is a Python version:
The Python client code is here, the Python CGI script is here, and the test program is here.
Here is a Java version:
The Java client code is here, the Java CGI script is here, and the test program is here.
The PHP version is by Alex Halderman '03, with contributions from Avi Flamholz '07 and Scott Karlin *03; thanks to all of them. The Python version is bwk's transliteration from the PHP. The Java version is by Bob Dondero, as is the corrected PHP version; many thanks to him as well.
A pretty cryptic description of the underlying system is found at this OIT site. CAStest.php 0000755 0001171 0001630 00000000356 11347716117 011204 0 ustar bwk fac Authenticate(); echo "Hello from the other side, $netid."; echo "
Think of this as the main page of your application ";
echo "after $netid has been authenticated.";
?>
CASClient.php 0000755 0001171 0001630 00000010071 11733615032 011427 0 ustar bwk fac Validate($_GET['ticket']);
if ($netid)
return $netid; // successful login
echo "
Got 'ticket' but wasn't valid"; // DEBUG
exit;
}
// No valid ticket; redirect the browser to the login page to get one
$login_url = $this->cas_url . 'login'
. '?service=' . urlencode($this->ServiceURL());
//header('HTTP/1.1 302 Found');
header('Location: ' . $login_url);
header('Status-line: HTTP/1.1 307 Temporary Redirect');
header('');
exit;
}
// Validates a login ticket by contacting the CAS server. If
// valid, returns the user's NetID; otherwise, returns false.
function Validate($ticket)
{
$validate_url = $this->cas_url . 'validate'
. '?service=' . urlencode($this->ServiceURL())
. '&ticket=' . urlencode($_GET['ticket']);
$r = $this->SecureGetURL($validate_url);
// echo "
sizeof(r)=", sizeof($r), "\n"; // DEBUG
// echo "
r[0] = '" . $r[0] . "'\n"; // DEBUG
// echo "
r[1] = '" . $r[1] . "'\n"; // DEBUG
if (2 == sizeof($r) && 'yes' == trim($r[0]))
return trim($r[1]); // ticket was valid, return NetID
return false;
}
// Returns the URL of the current page after stripping out the ticket=
// parameter added by the CAS server.
function ServiceURL()
{
$url = 'http' . (($_SERVER['HTTPS'] == 'on') ? 's' : '') .
'://' . $_SERVER['HTTP_HOST'];
if (!($_SERVER['HTTPS'] == 'on' && $_SERVER['SERVER_PORT'] == '443') &&
!($_SERVER['HTTPS'] != 'on' && $_SERVER['SERVER_PORT'] == '80'))
$url .= ':' . $_SERVER['SERVER_PORT'];
$url .= $_SERVER['REQUEST_URI'];
$url = preg_replace('/ticket=[^&]*&?/', '', $url);
return preg_replace('/\?&?$|&$/', '', $url);
}
// Retrieves content from a specified URL and returns an array
// where each element corresponds to a line of the content.
// Unlike PHP's built in 'file' function, it verifies the server's
// SSL certificate when retrieving an HTTPS URL.
function SecureGetURL($url)
{
function_exists('curl_init')
or die('CASClient requires PHP to be built with CURL support.');
$h = curl_init($url)
or die('CASClient cannot initialize CURL.');
// verify that the server's certificate corresponds to its hostname
curl_setopt($h, CURLOPT_SSL_VERIFYHOST, 2);
// verify that the certificate was issued by a trusted authority
//curl_setopt($h, CURLOPT_CAINFO, "cacert.pem");
//curl_setopt($h, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($h, CURLOPT_SSL_VERIFYPEER, false);
// return the content as a string
curl_setopt($h, CURLOPT_RETURNTRANSFER, true);
$c = curl_exec($h);
$cerr = curl_error($h); // DEBUG
curl_close($h);
if (false !== $c)
return explode("\n", trim($c));
echo "
curl_error = '" . $cerr . "'\n"; // DEBUG
echo "
SecureGetURL returning false\n"; // DEBUG
return false;
}
}
// Sample usage:
//
// require 'CASClient.php';
// $C = new CASClient();
// $netid = $C->Authenticate();
// echo "Howdy, $netid.";
CAStestpy.cgi 0000755 0001171 0001630 00000000256 12255654775 011541 0 ustar bwk fac #!/bin/sh
PATH=/bin:/usr/local/python/current/bin:/usr/bin:/usr/local/bin:$PATH
export PATH
#echo 'Content-Type: text/html'
#echo
#uname -a
#which python
python CAStest.py
CASClient.py 0000755 0001171 0001630 00000003517 11346305211 011272 0 ustar bwk fac import sys, os, cgi, urllib, re
form = cgi.FieldStorage()
class CASClient:
def __init__(self, url='https://fed.princeton.edu/cas/'):
self.cas_url = url
def Authenticate(self):
# If the request contains a login ticket, try to validate it
if form.has_key('ticket'):
netid = self.Validate(form['ticket'].value)
if netid != None:
return netid
# No valid ticket; redirect the browser to the login page to get one
login_url = self.cas_url + 'login' \
+ '?service=' + urllib.quote(self.ServiceURL())
print 'Location: ' + login_url
print 'Status-line: HTTP/1.1 307 Temporary Redirect'
print ""
sys.exit(0)
def Validate(self, ticket):
val_url = self.cas_url + "validate" + \
'?service=' + urllib.quote(self.ServiceURL()) + \
'&ticket=' + urllib.quote(ticket)
#val_url = self.cas_url + "serviceValidate" + \
# '?service=' + urllib.quote(self.ServiceURL()) + \
# '&ticket=' + urllib.quote(ticket) # new
r = urllib.urlopen(val_url).readlines() # returns 2 lines
if len(r) == 2 and re.match("yes", r[0]) != None:
return r[1].strip()
return None
def ServiceURL(self):
if os.environ.has_key('REQUEST_URI'):
ret = 'http://' + os.environ['HTTP_HOST'] + os.environ['REQUEST_URI']
ret = re.sub(r'ticket=[^&]*&?', '', ret)
ret = re.sub(r'\?&?$|&$', '', ret)
return ret
#$url = preg_replace('/ticket=[^&]*&?/', '', $url);
#return preg_replace('/?&?$|&$/', '', $url);
return "something is badly wrong"
# https://fed.princeton.edu/cas/
# validate?ticket=ST-3555-McPZ4NKfx6S0EhnCEkHc
# &service=https://www.applyweb.com/proto/auth/cas/princeton
def main():
print "CASClient does not run standalone"
if __name__ == '__main__':
main()
CAStest.py 0000755 0001171 0001630 00000000565 12134337662 011046 0 ustar bwk fac #!/usr/local/python/current/bin/python
import _ssl;_ssl.PROTOCOL_SSLv23 = _ssl.PROTOCOL_SSLv3
import CASClient
C = CASClient.CASClient()
netid = C.Authenticate()
print "Content-Type: text/html"
print ""
import os
print "Hello from the other side, %s\n" % netid
print "
Think of this as the main page of your application after %s has been authenticated." % (netid)
CAStestjava.cgi 0000755 0001171 0001630 00000000102 11733616776 012017 0 ustar bwk fac #!/bin/sh
export PATH=/usr/local/java/jdk/bin:$PATH
java CAStest
CASClient.java 0000644 0001171 0001630 00000020012 11733622406 011555 0 ustar bwk fac //----------------------------------------------------------------------
// PennypackJavaAuthCas/CASClient.java
// Author: Bob Dondero, based upon similar PHP code written by
// Scott Karlin and Alex Halderman, and similar Python code written by
// by Brian Kernighan
//----------------------------------------------------------------------
import java.net.*;
import java.util.*;
import java.io.*;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.util.StringTokenizer;
import java.util.HashMap;
import java.net.URLDecoder;
public class CASClient
{
private String casUrl;
public CASClient()
{
casUrl = "https://fed.princeton.edu/cas/";
}
public CASClient(String casUrl)
{
this.casUrl = casUrl;
}
// Authenticate the remote user, and return the user's NetID.
// Upon the first call, redirect the browser to a login page to
// complete the authentication process. (The login page then
// redirects the browser back to the current page.)
// Upon subsequent calls, confirm that the login was successful
// and return the NetID. Do not return unless the user is
// successfully authenticated.
public String authenticate()
{
// If the request contains a login ticket, try to validate it.
HashMap Hello from the other side, " + netid);
prl(" Think of this as the main page of your application after " +
netid + " has been authenticated.");
}
}