From 600070e846a6b3827cd8f75d63db7c820f8aaad8 Mon Sep 17 00:00:00 2001
From: Bradley M. Froehle <brad.froehle@gmail.com>
Date: Thu, 17 Feb 2011 15:21:38 -0800
Subject: [PATCH] 1059942 - refactor hooks D7

---
 README.txt  |    6 +++
 cas.api.php |   80 +++++++++++++++++++++++++++++++++++++++++++++
 cas.module  |  103 +++++++++++-----------------------------------------------
 3 files changed, 106 insertions(+), 83 deletions(-)
 create mode 100644 cas.api.php

diff --git README.txt README.txt
index 878e9a3..5c9a4f8 100644
--- README.txt
+++ README.txt
@@ -31,3 +31,9 @@ Installation
   Depending on where and how you installed the phpCAS library, you may need
   to configure the path to CAS.php. The current library version will be
   displayed if the library is found.
+
+
+API Changes Since 6.x-2.x
+=========================
+The hooks hook_auth_name() and hook_auth_filter() were combined and renamed
+to hook_cas_user_alter(). See cas.api.php.
diff --git cas.api.php cas.api.php
new file mode 100644
index 0000000..44ac5e3
--- /dev/null
+++ cas.api.php
@@ -0,0 +1,80 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Documentation for CAS API.
+ */
+
+/*
+ * Modify CAS user properties before the user is logged in.
+ *
+ * Allows modules to alter the CAS user name and account creation permissions
+ * after the CAS user name is returned from phpCAS::getUser().
+ *
+ * Modules implementing this hook may wish to alter 'name' if the CAS server
+ * returns user names which contain excess information or are not directly
+ * machine readable. This field is not the Drupal name of the user. Instead, 
+ * this is used to load a Drupal user via the mapping in the {cas_user} table.
+ *
+ * The 'register' parameter controls whether an account should be created if 
+ * the user does not already have a Drupal account. Defaults to the value of
+ * "Should Drupal user accounts be automatically created?" in the CAS module
+ * settings.
+ *
+ * @param $cas_user
+ *   An associative array, with the following keys:
+ *   - 'user': The CAS machine-readable user name.
+ *   - 'register': If TRUE, the user will be allowed to register a Drupal
+ *     account if one does not already exist.
+ */
+function hook_cas_user_alter(&$cas_user) {
+  // Alter the CAS user name. The CAS server returned a compound name like
+  //   it:johndoe:10.10.1.2:200805064255
+  // and so we extract the actual user name of 'johndoe'.
+  $parts = explode(':', $cas_user['name'], 3);
+  $cas_user['name'] = $parts[1];
+
+  // Allow registrations only for a certain class of users.
+  $cas_user['register'] = _ldap_user_has_home_directory($cas_user['name']);
+}
+
+/*
+ * Modify a Drupal user account before a CAS user is registered.
+ *
+ * This hook is called after the user array has been assembled, but before
+ * user_save() is called.
+ *
+ * @param $edit
+ *   An array of values corresponding to the Drupal user to be created.
+ */
+function hook_cas_user_register_alter(&$edit) {
+  $cas_name = $edit['name'];
+
+  // Look up the user's real name using LDAP.
+  $ldap_connection = ldap_connect('ldap.example.com', 389);
+  $ldap_result = ldap_search($ldap_connection, 'ou=people', 'uid=' . $cas_name, array('cn'), 0, 1);
+  $entries = ldap_get_entries($ldap_connection, $ldap_result);
+  $attributes = $entries[0];
+
+  if (!empty($attributes['cn'])) {
+    $edit['name'] = $attributes['cn'];
+  }
+}
+
+/**
+ * Modify phpCAS authentication properties.
+ *
+ * This is called after phpCAS has been configured with the basic server
+ * properties, but before phpCAS::forceAuthentication() is called.
+ *
+ * Users will generally not need to implement this hook, as most phpCAS
+ * configuration options are already provided in the CAS module UI.
+ *
+ * There are no parameters, instead the module should directly call the
+ * functions in the phpCAS namespace.
+ */
+function hook_cas_phpcas_alter() {
+  // Set a custom server login URL.
+  phpCAS::setServerLoginURL('https://login.example.com/cas/login');
+}
diff --git cas.module cas.module
index 0a651f7..ad9d96d 100644
--- cas.module
+++ cas.module
@@ -18,55 +18,6 @@ define('CAS_LOGIN_REDIR_MESSAGE', 'You will be redirected to the secure cas logi
 define('CAS_EXCLUDE', 'services/*'); 
 define('CAS_AUTHMAP_EXTERNAL', 0);  // Use external authmap entries for cas
 define('CAS_AUTHMAP_INTERNAL', 1);  // Use drupal as the internal user. 
- 
-
-/**
- * Invokes hook_auth_transform() in every module.
- *
- * Other modules may need to transform the results of phpCAS::getUser() into a Drupal username
- * (i.e. phpCAS::getUser() is not guaranteed to return the same username that the user typed in
- *       or the Drupal username might be username@cas or something and we need to know it before we filter)
- *
- * We cannot use hook_insert or any user hooks, because they fire way too late.
- * We cannot use module_invoke_all(), because the argument needs to be passed by reference.
- *
- * @param $cas_user
- *   The cas reply string to transform into a drupal username
- */
-function cas_invoke_auth_transform(&$cas_name) {
-  foreach (module_implements('auth_transform') as $module) {
-    $function = $module . '_auth_transform';
-    if (function_exists($function)) {
-      $function('cas', $cas_name);
-    }
-  }
-}
-
-/**
- * Invokes hook_auth_filter() in every module.
- *
- * We cannot use module_invoke_all() for this,
- * because we want to break out as soon as one fails.
- *
- * @param $cas_user
- *   The transformed $cas_name to filter
- *
- * @return
- *   TRUE if no module implementing this hook denied access
- *   FALSE if any module returned FALSE
- */
-function cas_invoke_auth_filter($cas_name) {
-  foreach (module_implements('auth_filter') as $module) {
-    $function = $module . '_auth_filter';
-    if (function_exists($function)) {
- 
-      if (($return = $function('cas', $cas_name)) === FALSE) {
-        return FALSE;
-      }
-    }
-  } 
-  return TRUE;
-}
 
 /**
  * Implementation of hook_init
@@ -143,7 +94,6 @@ function cas_login_check() {
     
 
     // Variable set
-    $cas_user_register = variable_get('cas_user_register', 1);
     $cas_authmap       = variable_get('cas_authmap', CAS_AUTHMAP_EXTERNAL);
     $server_version    = (string)variable_get('cas_version', '2.0');
     $server_cas_server = (string)variable_get('cas_server', 'sso-cas.univ-rennes1.fr');
@@ -191,6 +141,10 @@ function cas_login_check() {
         break;
     } 
 
+    // Allow other modules to call phpCAS routines. We do not call
+    // drupal_alter() since there are no parameters to pass.
+    module_invoke_all('cas_phpcas_alter');
+
     // We're going to try phpCAS auth test
     if (!$cas_force_login) {
       $logged_in = phpCAS::checkAuthentication(); 
@@ -204,37 +158,18 @@ function cas_login_check() {
     else { 
       phpCAS::forceAuthentication();
     }
-    
-    $cas_name = phpCAS::getUser();
-    
-    /*
-     * Invoke hook_auth_transform($op, &$username)
-     *
-     * Allow other modules to change the login name
-     * eg. if phpCAS::getUser() returns a string like it:johndoe:10.10.1.2:200805064255
-     * eg. if your cas users in Drupal need to be johndoe@cas
-     *
-     * Note: this transformation needs to happen before we check for blocked users.
-     */
-    
-    cas_invoke_auth_transform($cas_name);
 
- 
-    /*
-     * Invoke hook_auth_filter($op, &$username)
-     *
-     * Allow other modules to filter out some cas logins
-     * eg. if you want to use cas authentication but only allow SOME people in
-     * eg. if you want to filter out people without LDAP home directories
-     */
-    if (cas_invoke_auth_filter($cas_name) === FALSE) {
- 
-      drupal_set_message(t('The user account %name is not available on this site.', array('%name' => $cas_name)), 'error');
-      return;
-    }
- 
+    // Build the cas_user object and allow modules to alter it.
+    $cas_user = array(
+      'name' => phpCAS::getUser(),
+      'register' => variable_get('cas_user_register', TRUE),
+    );
+    drupal_alter('cas_user', $cas_user);
+
+    // Proceed with the login process, using the altered CAS user name.
+    $cas_name = $cas_user['name'];
+
     // blocked user check
-    
     if (($cas_authmap == CAS_AUTHMAP_INTERNAL) && user_is_blocked($cas_name)) {
       // blocked in user administration
       drupal_set_message(t('The username %name has been blocked.', array('%name' => $cas_name)), 'error');
@@ -288,8 +223,8 @@ function cas_login_check() {
     
     // If we don't have a user register them.
     if (empty($acct) || !$acct->uid ) {
-      if ($cas_user_register == 1) {
-        $user_default = array(
+      if ($cas_user['register']) {
+        $edit = array(
           "name" => $cas_name,
           "pass" => user_password(),
           "init" => $cas_name,
@@ -297,13 +232,15 @@ function cas_login_check() {
           "status" => 1,
           "roles" => $cas_roles,
         );
-        if ($cas_domain) $user_default['mail'] = $cas_name . '@' . $cas_domain;
+        if ($cas_domain) $edit['mail'] = $cas_name . '@' . $cas_domain;
 
         // Set a session variable to denote this the initial login
         $_SESSION['cas_first_login'] = TRUE;
 
+        drupal_alter('cas_user_register', $edit);
+
         // now save the user and become the new user.
-        $acct = user_save(drupal_anonymous_user(), $user_default);
+        $acct = user_save(drupal_anonymous_user(), $edit);
         if ($cas_authmap == CAS_AUTHMAP_EXTERNAL) {
           db_insert('cas_user')
             ->fields(array(
-- 
1.7.3.5

