Projet

Général

Profil

Paste
Télécharger (8,84 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / cas / cas_server.module @ a2baadd1

1
<?php
2

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

    
8
/**
9
 * Implementation of hook_menu
10
 */
11
function cas_server_menu() {
12
  $items = array();
13
  $items['cas/login'] = array(
14
    'page callback' => 'cas_server_login',
15
    'title' => 'CAS Login',
16
    'access callback' => TRUE,
17
    'type' => MENU_CALLBACK,
18
  );
19

    
20
  $items['cas/validate'] = array(
21
    'page callback' => 'cas_server_validate',
22
    'title' => 'CAS Validate',
23
    'access callback' => TRUE,
24
    'type' => MENU_CALLBACK,
25
  );
26

    
27
  $items['cas/serviceValidate'] = array(
28
    'page callback' => 'cas_server_service_validate',
29
    'title' => 'CAS Service Validate',
30
    'access callback' => TRUE,
31
    'type' => MENU_CALLBACK,
32
  );
33

    
34
  $items['cas/proxyValidate'] = array(
35
    'page callback' => 'cas_server_service_validate',
36
    'title' => 'CAS Proxy Ticket Validate',
37
    'access callback' => TRUE,
38
    'type' => MENU_CALLBACK,
39
  );
40

    
41
  $items['cas/logout'] = array(
42
    'page callback' => 'cas_server_logout',
43
    'title' => 'CAS Logout',
44
    'access callback' => TRUE,
45
    'type' => MENU_CALLBACK,
46
  );
47
  return $items;
48
}
49

    
50
/**
51
 * Implements hook_theme().
52
 */
53
function cas_server_theme() {
54
  return array(
55
    'cas_service_validate_success' => array(
56
      'variables' => array('name' => NULL, 'attributes' => NULL),
57
      'file' => 'cas_server.response.inc',
58
    ),
59
    'cas_service_validate_attributes' => array(
60
      'variables' => array('attributes' => NULL, 'style' => 'jasig'),
61
      'file' => 'cas_server.response.inc',
62
    ),
63
    'cas_service_validate_failure' => array(
64
      'variables' => array('ticket' => NULL, 'error_code' => NULL),
65
      'file' => 'cas_server.response.inc',
66
    ),
67
    'cas_service_logout_request' => array(
68
      'variables' => array('ticket' => NULL, 'date' => NULL, 'id' => NULL),
69
      'file' => 'cas_server.response.inc',
70
    ),
71
  );
72
}
73

    
74
/**
75
 * Implements hook_cas_server_user_attributes().
76
 *
77
 * Returns the user's roles.
78
 */
79
function cas_server_cas_server_user_attributes($account, $service) {
80
  return array(
81
    'uid'           => $account->uid,
82
    'mail'          => $account->mail,
83
    'created'       => $account->created,
84
    'timezone'      => $account->timezone,
85
    'language'      => $account->language,
86
    'drupal_roles'  => $account->roles,
87
  );
88
}
89

    
90
function cas_server_service_return() {
91
  global $user;
92
  $service = isset($_COOKIE[CAS_LOGIN_COOKIE]) ? $_COOKIE[CAS_LOGIN_COOKIE] : '';
93
  if ($service && $user->uid) {
94
    $ticket = _cas_server_save_ticket($user->uid, $service);
95
    setcookie(CAS_LOGIN_COOKIE, "", -3600);
96
    drupal_goto($service, array('query' => array('ticket' => $ticket)));
97
  }
98
}
99

    
100
/**
101
 * Handle login
102
 *
103
 */
104
function cas_server_login() {
105
  // Set login cookie so that we know we're in the process of logging in
106
  global $user;
107
  $output='';
108
  $service = isset($_REQUEST['service']) ? $_REQUEST['service'] : '';
109
  $gateway = isset($_REQUEST['gateway']);
110
  if ($user->uid) {
111
    if ($service) {
112
      $_COOKIE[CAS_LOGIN_COOKIE] = $service;
113
    }
114
    $output=t('You have successfully logged into CAS');
115
    cas_server_service_return();
116
  }
117
  else {
118
    if ($gateway && $service) {
119
      drupal_goto($service);
120
    }
121
    else {
122
      // Redirect to user login
123
      if ($service) {
124
        setcookie(CAS_LOGIN_COOKIE, $service);
125
      }
126
      $output .= l(t('Login'), 'user', array('query' => array('destination' => 'cas/login')));
127
      drupal_goto('user', array('query' => array('destination' => 'cas/login')));
128
    }
129
  }
130
  return $output;
131
}
132

    
133
/**
134
 * Validate the ticket using a CAS 1.x methodology
135
 * This provides the simple non-xml based
136
 */
137
function cas_server_validate() {
138
  // Prevent this page from being cached.
139
  drupal_page_is_cacheable(FALSE);
140

    
141
  // Set content type.
142
  drupal_add_http_header('Content-Type', 'text/plain; charset=utf-8');
143

    
144
  //Obtain the ticket from the url and validate it.
145
  $ticket = isset($_REQUEST['ticket']) ? $_REQUEST['ticket'] : '';
146
  $service = isset($_REQUEST['service']) ? $_REQUEST['service'] : '';
147
  $user_name = _cas_server_validate($service, $ticket);
148
  if ($user_name) {
149
    print "yes\n";
150
    print "$user_name\n";
151
  }
152
  else {
153
    print "no\n";
154
    print "\n";
155
  }
156
}
157
/**
158
 * serviceValidate method using cas 2.0
159
 * Returns data in xml
160
 */
161
function cas_server_service_validate() {
162
  // Prevent this page from being cached.
163
  drupal_page_is_cacheable(FALSE);
164

    
165
  // Set content type.
166
  drupal_add_http_header('Content-Type', 'text/xml; charset=utf-8');
167

    
168
  $ticket = isset($_REQUEST['ticket']) ? $_REQUEST['ticket'] : '';
169
  $service = isset($_REQUEST['service']) ? $_REQUEST['service'] : '';
170
  $user_name = _cas_server_validate($service, $ticket);
171
  if (!$user_name) $cas_error='INVALID_TICKET';
172
  if (!$ticket || !$service) $cas_error='INVALID_REQUEST';
173

    
174
  if ($user_name) {
175
    //@TODO Generate proxy granting ticket
176
    $account = user_load_by_name($user_name);
177

    
178
    // Generate a list of attributes to return.
179
    $attributes = module_invoke_all('cas_server_user_attributes', $account, $service, $ticket);
180

    
181
    // Let other modules alter the list of attributes.
182
    $context = array(
183
      'service' => $service,
184
      'ticket' => $ticket,
185
    );
186
    drupal_alter('cas_server_user_attributes', $attributes, $account, $context);
187

    
188
    print theme('cas_service_validate_success', array('name' => $user_name, 'attributes' => $attributes));
189
    watchdog('cas', 'User %name CAS sucessully authenticated.', array('%name' => $user_name));
190
  }
191
  else {
192
    print theme('cas_service_validate_failure', array('ticket' => $ticket, 'error_code' => $cas_error));
193
    watchdog('cas', 'Ticket %ticket for service %service not recognized.', array('%ticket' => $ticket, '%service' => $service));
194
  }
195
}
196

    
197
/**
198
 * Test to see if a one time use ticket is valid
199
 *
200
 * @param unknown_type $ticket
201
 * @return unknown
202
 */
203
function _cas_server_validate($service, $ticket) {
204
  // Look up the ticket
205
  $user_name='';
206
  $ticket_info=array(':service' => $service, ':ticket' => $ticket);
207
  $result = db_query_range("SELECT u.name FROM {cas_server_tickets} t JOIN {users} u ON t.uid=u.uid  WHERE t.service = :service and t.ticket = :ticket AND valid=1", 0, 1, $ticket_info);
208
  if ($result !== FALSE) {
209
    foreach ($result as $ticket_data) {
210
      $user_name = $ticket_data->name;
211
    }
212
  }
213
  db_update('cas_server_tickets')
214
    ->fields(array('valid' => 0))
215
    ->condition('ticket', $ticket)
216
    ->execute();
217

    
218
  return $user_name;
219
}
220

    
221
/**
222
 * Generate a one time use login ticket for the user in question.
223
 *
224
 * @param int $uid
225
 */
226
function _cas_server_save_ticket($uid, $service) {
227
  // Generate the ticket
228
  $time = REQUEST_TIME;
229
  $ticket = 'ST-' . user_password();
230
  $ticket_data = array('uid' => $uid, 'service' => $service, 'ticket' => $ticket, 'timestamp' => $time, 'valid' => 1);
231
  // Save the ticket to the db
232
  if ($uid && $service) {
233
    db_insert('cas_server_tickets')->fields($ticket_data)->execute();
234
  }
235
  return $ticket;
236
}
237

    
238
/**
239
 * Menu callback; triggers a CAS logout.
240
 */
241
function cas_server_logout() {
242
  global $user;
243

    
244
  watchdog('user', 'Session closed for %name.', array('%name' => $user->name));
245

    
246
  module_invoke_all('user_logout', $user);
247

    
248
  // Destroy the current session, and reset $user to the anonymous user.
249
  session_destroy();
250

    
251
  $output = '<p>' . t('You have been logged out successfully.') . '</p>';
252
  if (isset($_REQUEST['url'])) {
253
    $output .= '<p>' . l(t('Continue'), $_REQUEST['url']) . '</p>';
254
  }
255
  return $output;
256
}
257

    
258
/**
259
 * Send CAS a logout requests for each of the user's CAS tickets.
260
 *
261
 * @param $account
262
 *   The user for whom to send CAS logout requests.
263
 */
264
function cas_server_logout_clients($account) {
265
   $result = db_query("SELECT service, ticket, valid FROM {cas_server_tickets} WHERE uid= :uid", array(':uid' => $account->uid));
266
    if ($result !== FALSE) {
267
      $expired_tickets = array();
268
      foreach ($result as $client) {
269
        $expired_tickets[] = $client->ticket;
270
        if (!$client->valid)  {
271
          $id = 'LR-' . user_password();
272
          $date = date('c');
273
          $logout_request = theme('cas_service_logout_request', array('id' => $id, 'date' => $date, 'ticket' => $client->ticket));
274
          // Send POST request
275
          $response = drupal_http_request(
276
            $client->service,
277
            array(
278
              'headers' => array('Content-Type' => 'application/x-www-form-urlencoded'),
279
              'method' =>  'POST',
280
              'data' => 'logoutRequest=' . urlencode($logout_request),
281
            )
282
          );
283
          if (@$response->error) {
284
            watchdog('error', 'Error in CAS logout Request - %code : %message', array('%code' => $response->code, '%error' => $response->error));
285
          }
286
        }
287
        // Remove ticket
288
      }
289
      if ($expired_tickets) {
290
        db_delete('cas_server_tickets')
291
          ->condition('ticket', $expired_tickets, 'IN')
292
          ->execute();
293
      }
294
    }
295
}
296

    
297
/**
298
 * Implements hook_user_logout().
299
 */
300
function cas_server_user_logout($account) {
301
  cas_server_logout_clients($account);
302
}