You are here

cas_server.module in CAS 5.4

Provides a protocol compliant version of CAS server 2.x

File

cas_server.module
View source
<?php

/**
 * @file Provides a protocol compliant version of CAS server 2.x
 */
define('CAS_LOGIN_COOKIE', 'cas_server_login');

/**
 * Implementation of hook_menu
 */
function cas_server_menu($may_cache = FALSE) {
  $items = array();
  if (!$may_cache) {
    $items[] = array(
      'path' => 'cas/login',
      'callback' => 'cas_server_login',
      'title' => t('CAS Login'),
      'access' => TRUE,
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'cas/validate',
      'callback' => 'cas_server_validate',
      'title' => t('CAS Validate'),
      'access' => TRUE,
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'cas/serviceValidate',
      'callback' => 'cas_server_service_validate',
      'title' => t('CAS Service Validate'),
      'access' => TRUE,
      'type' => MENU_CALLBACK,
    );
    $items[] = array(
      'path' => 'cas/logout',
      'callback' => 'cas_server_logout',
      'title' => t('CAS Logout'),
      'access' => TRUE,
      'type' => MENU_CALLBACK,
    );
  }
  return $items;
}
function cas_server_service_return() {
  global $user;
  $service = $_COOKIE[CAS_LOGIN_COOKIE];
  if ($service && $user->uid) {
    $ticket = _cas_server_save_ticket($user->uid, $service);
    setcookie(CAS_LOGIN_COOKIE, "", -3600);
    drupal_goto($service, 'ticket=' . urlencode($ticket));
  }
}

/**
 * Handle login 
 *
 */
function cas_server_login() {

  // Set login cookie so that we know we're in the process of logging in
  global $user;
  if ($user->uid) {
    if ($_GET['service']) {
      $_COOKIE[CAS_LOGIN_COOKIE] = $_REQUEST['service'];
    }
    $output = t('You have successfully logged into CAS');
    cas_server_service_return();
  }
  else {
    if ($_GET['gateway'] && $_GET['service']) {
      drupal_goto($_GET['service']);
    }
    else {

      // Redirect to user login
      if ($_GET['service']) {
        setcookie(CAS_LOGIN_COOKIE, $_REQUEST['service']);
      }
      $output .= l('Login', 'user', array(
        'query' => 'destination=cas/login',
      ));
      drupal_goto('user', 'destination=cas/login');
    }
  }
  return $output;
}

/**
 * Validate the ticket using a CAS 1.x methodology
 * This provides the simple non-xml based 
 */
function cas_server_validate() {

  //Obtain the ticket from the url and validate it.
  $ticket = $_GET['ticket'];
  $service = $_GET['service'];
  $user_name = _cas_server_validate($service, $ticket);
  if ($user_name) {
    print "yes\n";
    print "{$user_name}\n";
  }
  else {
    print "no\n";
    print "\n";
  }
}

/**
 * serviceValidate method using cas 2.0 
 * Returns data in xml 
 */
function cas_server_service_validate() {
  $ticket = $_GET['ticket'];
  $service = $_GET['service'];
  $user_name = _cas_server_validate($service, $ticket);
  if (!$user_name) {
    $cas_error = 'INVALID_TICKET';
  }
  if (!$ticket || !$service) {
    $cas_error = 'INVALID_REQUEST';
  }
  header('Content-type:', 'text/xml');
  if ($user_name) {

    //@TODO Generate proxy granting ticket
    print "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n" . "  <cas:authenticationSuccess>\n" . "    <cas:user>{$user_name}</cas:user>\n" . "  </cas:authenticationSuccess>\n" . "</cas:serviceResponse>\n";
    watchdog('cas', 'User ' . $user_name . ' CAS sucessully authenticated.');
  }
  else {
    print "<cas:serviceReponse xmlns:cas='http://www.yale.edu/tp/cas'>\n" . "  <cas:authenticationFailure code=\"{$cas_error}\">\n" . "     Ticket {$ticket} not recognized.\n" . "  </cas:authenticationFailure>" . "</cas:serviceResponse>";
    watchdog('cas', 'User ' . $user_name . ' authentication failed!');
  }
}

/**
 * Test to see if a one time use ticket is valid
 *
 * @param unknown_type $ticket
 * @return unknown
 */
function _cas_server_validate($service, $ticket) {

  // Look up the ticket
  $user_name = '';
  $ticket_info = array(
    $service,
    $ticket,
  );
  $result = db_query_range("SELECT u.name FROM {cas_server_tickets} t JOIN {users} u ON t.uid=u.uid  WHERE t.service = '%s' and t.ticket = '%s'", $ticket_info, 0, 1);
  if ($result !== FALSE) {
    while ($ticket_data = db_fetch_object($result)) {
      $user_name = $ticket_data->name;
    }
  }
  db_query("DELETE FROM {cas_server_tickets} WHERE ticket='%s'", array(
    $ticket,
  ));
  return $user_name;
}

/**
 * Generate a one time use login ticket for the user in question. 
 *
 * @param int $uid
 */
function _cas_server_save_ticket($uid, $service) {

  // Generate the ticket
  $time = time();
  $ticket = 'ST-' . user_password();
  $ticket_data = array(
    $uid,
    $service,
    $ticket,
    $time,
  );

  // Save the ticket to the db
  if ($uid && $service) {
    db_query("INSERT INTO {cas_server_tickets} (uid, service, ticket, timestamp) VALUES (%d, '%s', '%s', %d)", $ticket_data);
  }
  return $ticket;
}

/**
 * Cas Logout
 * @TODO: Implement single sign out support
 */
function cas_server_logout() {

  // Destroy the current session:
  session_destroy();
  module_invoke_all('user', 'logout', NULL, $user);
  $output = '<p>You have been logged out successfully</p>';
  if ($_GET['url']) {
    $output .= '<p>' . l('Continue', $_GET['url']) . '</p>';
  }
  return $output;
}

Functions

Namesort descending Description
cas_server_login Handle login
cas_server_logout Cas Logout @TODO: Implement single sign out support
cas_server_menu Implementation of hook_menu
cas_server_service_return
cas_server_service_validate serviceValidate method using cas 2.0 Returns data in xml
cas_server_validate Validate the ticket using a CAS 1.x methodology This provides the simple non-xml based
_cas_server_save_ticket Generate a one time use login ticket for the user in question.
_cas_server_validate Test to see if a one time use ticket is valid

Constants

Namesort descending Description
CAS_LOGIN_COOKIE @file Provides a protocol compliant version of CAS server 2.x