Projet

Général

Profil

Paste
Télécharger (36,6 ko) Statistiques
| Branche: | Révision:

root / drupal7 / modules / openid / openid.test @ 76597ebf

1 85ad3d82 Assos Assos
<?php
2
3
/**
4
 * @file
5
 * Tests for openid.module.
6
 */
7
8
/**
9
 * Base class for OpenID tests.
10
 */
11
abstract class OpenIDWebTestCase extends DrupalWebTestCase {
12
13
  /**
14
   * Initiates the login procedure using the specified User-supplied Identity.
15
   */
16
  function submitLoginForm($identity) {
17
    // Fill out and submit the login form.
18
    $edit = array('openid_identifier' => $identity);
19
    $this->drupalPost('', $edit, t('Log in'));
20
21
    // Check we are on the OpenID redirect form.
22
    $this->assertTitle(t('OpenID redirect'), 'OpenID redirect page was displayed.');
23
24
    // Submit form to the OpenID Provider Endpoint.
25
    $this->drupalPost(NULL, array(), t('Send'));
26
  }
27
28
  /**
29
   * Parses the last sent e-mail and returns the one-time login link URL.
30
   */
31
  function getPasswordResetURLFromMail() {
32
    $mails = $this->drupalGetMails();
33
    $mail = end($mails);
34
    preg_match('@.+user/reset/.+@', $mail['body'], $matches);
35
    return $matches[0];
36
  }
37
}
38
39
/**
40
 * Test discovery and login using OpenID
41
 */
42
class OpenIDFunctionalTestCase extends OpenIDWebTestCase {
43
  protected $web_user;
44
45
  public static function getInfo() {
46
    return array(
47
      'name' => 'OpenID discovery and login',
48
      'description' => "Adds an identity to a user's profile and uses it to log in.",
49
      'group' => 'OpenID'
50
    );
51
  }
52
53
  function setUp() {
54
    parent::setUp('openid', 'openid_test');
55
56
    // User doesn't need special permissions; only the ability to log in.
57
    $this->web_user = $this->drupalCreateUser(array());
58
  }
59
60
  /**
61
   * Test discovery of OpenID Provider Endpoint via Yadis and HTML.
62
   */
63
  function testDiscovery() {
64
    $this->drupalLogin($this->web_user);
65
66
    // The User-supplied Identifier entered by the user may indicate the URL of
67
    // the OpenID Provider Endpoint in various ways, as described in OpenID
68
    // Authentication 2.0 and Yadis Specification 1.0.
69
    // Note that all of the tested identifiers refer to the same endpoint, so
70
    // only the first will trigger an associate request in openid_association()
71
    // (association is only done the first time Drupal encounters a given
72
    // endpoint).
73
74
75
    // Yadis discovery (see Yadis Specification 1.0, section 6.2.5):
76
    // If the User-supplied Identifier is a URL, it may be a direct or indirect
77
    // reference to an XRDS document (a Yadis Resource Descriptor) that contains
78
    // the URL of the OpenID Provider Endpoint.
79
80
    // Identifier is the URL of an XRDS document.
81
    // On HTTP test environments, the URL scheme is stripped in order to test
82
    // that the supplied identifier is normalized in openid_begin().
83
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
84
    $this->addIdentity(preg_replace('@^http://@', '', $identity), 2, 'http://example.com/xrds', $identity);
85
86
    $identity = url('openid-test/yadis/xrds/delegate', array('absolute' => TRUE));
87
    $this->addIdentity(preg_replace('@^http://@', '', $identity), 2, 'http://example.com/xrds-delegate', $identity);
88
89
    // Identifier is the URL of an XRDS document containing an OP Identifier
90
    // Element. The Relying Party sends the special value
91
    // "http://specs.openid.net/auth/2.0/identifier_select" as Claimed
92
    // Identifier. The OpenID Provider responds with the actual identifier
93
    // including the fragment.
94
    $identity = url('openid-test/yadis/xrds/dummy-user', array('absolute' => TRUE, 'fragment' => $this->randomName()));
95
    // Tell openid_test.module to respond with this identifier. If the fragment
96
    // part is present in the identifier, it should be retained.
97
    variable_set('openid_test_response', array('openid.claimed_id' => $identity));
98
    $this->addIdentity(url('openid-test/yadis/xrds/server', array('absolute' => TRUE)), 2, 'http://specs.openid.net/auth/2.0/identifier_select', $identity);
99
    variable_set('openid_test_response', array());
100
101
    // Identifier is the URL of an HTML page that is sent with an HTTP header
102
    // that contains the URL of an XRDS document.
103
    $this->addIdentity(url('openid-test/yadis/x-xrds-location', array('absolute' => TRUE)), 2);
104
105
    // Identifier is the URL of an HTML page containing a <meta http-equiv=...>
106
    // element that contains the URL of an XRDS document.
107
    $this->addIdentity(url('openid-test/yadis/http-equiv', array('absolute' => TRUE)), 2);
108
109
    // Identifier is an XRI. Resolve using our own dummy proxy resolver.
110
    variable_set('xri_proxy_resolver', url('openid-test/yadis/xrds/xri', array('absolute' => TRUE)) . '/');
111
    $this->addIdentity('@example*résumé;%25', 2, 'http://example.com/xrds', 'http://example.com/user');
112
113
    // Make sure that unverified CanonicalID are not trusted.
114
    variable_set('openid_test_canonical_id_status', 'bad value');
115
    $this->addIdentity('@example*résumé;%25', 2, FALSE, FALSE);
116
117
    // HTML-based discovery:
118
    // If the User-supplied Identifier is a URL of an HTML page, the page may
119
    // contain a <link rel=...> element containing the URL of the OpenID
120
    // Provider Endpoint. OpenID 1 and 2 describe slightly different formats.
121
122
    // OpenID Authentication 1.1, section 3.1:
123
    $this->addIdentity(url('openid-test/html/openid1', array('absolute' => TRUE)), 1, 'http://example.com/html-openid1');
124
125
    // OpenID Authentication 2.0, section 7.3.3:
126
    $this->addIdentity(url('openid-test/html/openid2', array('absolute' => TRUE)), 2, 'http://example.com/html-openid2');
127
128
    // OpenID Authentication 2.0, section 7.2.4:
129
    // URL Identifiers MUST then be further normalized by both (1) following
130
    // redirects when retrieving their content and finally (2) applying the
131
    // rules in Section 6 of RFC3986 to the final destination URL. This final
132
    // URL MUST be noted by the Relying Party as the Claimed Identifier and be
133
    // used when requesting authentication.
134
135
    // Single redirect.
136
    $identity = $expected_claimed_id = url('openid-test/redirected/yadis/xrds/1', array('absolute' => TRUE));
137
    $this->addRedirectedIdentity($identity, 2, 'http://example.com/xrds', $expected_claimed_id, 0);
138
139
    // Exact 3 redirects (default value for the 'max_redirects' option in
140
    // drupal_http_request()).
141
    $identity = $expected_claimed_id = url('openid-test/redirected/yadis/xrds/2', array('absolute' => TRUE));
142
    $this->addRedirectedIdentity($identity, 2, 'http://example.com/xrds', $expected_claimed_id, 2);
143
144
    // Fails because there are more than 3 redirects (default value for the
145
    // 'max_redirects' option in drupal_http_request()).
146
    $identity = url('openid-test/redirected/yadis/xrds/3', array('absolute' => TRUE));
147
    $expected_claimed_id = FALSE;
148
    $this->addRedirectedIdentity($identity, 2, 'http://example.com/xrds', $expected_claimed_id, 3);
149
  }
150
151
  /**
152
   * Test login using OpenID.
153
   */
154
  function testLogin() {
155
    $this->drupalLogin($this->web_user);
156
157
    // Use a User-supplied Identity that is the URL of an XRDS document.
158
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
159
    $this->addIdentity($identity);
160
161
    $this->drupalLogout();
162
163
    // Test logging in via the login block on the front page.
164
    $this->submitLoginForm($identity);
165
    $this->assertLink(t('Log out'), 0, 'User was logged in.');
166
167
    $this->drupalLogout();
168
169
    // Test logging in via the user/login page.
170
    $edit = array('openid_identifier' => $identity);
171
    $this->drupalPost('user/login', $edit, t('Log in'));
172
173
    // Check we are on the OpenID redirect form.
174
    $this->assertTitle(t('OpenID redirect'), 'OpenID redirect page was displayed.');
175
176
    // Submit form to the OpenID Provider Endpoint.
177
    $this->drupalPost(NULL, array(), t('Send'));
178
179
    $this->assertLink(t('Log out'), 0, 'User was logged in.');
180
181
    // Verify user was redirected away from user/login to an accessible page.
182
    $this->assertResponse(200);
183
184
    $this->drupalLogout();
185
    // Use a User-supplied Identity that is the URL of an XRDS document.
186
    // Tell the test module to add a doctype. This should fail.
187
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE, 'query' => array('doctype' => 1)));
188
    // Test logging in via the login block on the front page.
189
    $edit = array('openid_identifier' => $identity);
190
    $this->drupalPost('', $edit, t('Log in'));
191
    $this->assertRaw(t('Sorry, that is not a valid OpenID. Ensure you have spelled your ID correctly.'), 'XML with DOCTYPE was rejected.');
192
  }
193
194
  /**
195
   * Test login using OpenID during maintenance mode.
196
   */
197
  function testLoginMaintenanceMode() {
198
    $this->web_user = $this->drupalCreateUser(array('access site in maintenance mode'));
199
    $this->drupalLogin($this->web_user);
200
201
    // Use a User-supplied Identity that is the URL of an XRDS document.
202
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
203
    $this->addIdentity($identity);
204
    $this->drupalLogout();
205
206
    // Enable maintenance mode.
207
    variable_set('maintenance_mode', 1);
208
209
    // Test logging in via the user/login page while the site is offline.
210
    $edit = array('openid_identifier' => $identity);
211
    $this->drupalPost('user/login', $edit, t('Log in'));
212
213
    // Check we are on the OpenID redirect form.
214
    $this->assertTitle(t('OpenID redirect'), 'OpenID redirect page was displayed.');
215
216
    // Submit form to the OpenID Provider Endpoint.
217
    $this->drupalPost(NULL, array(), t('Send'));
218
219
    $this->assertLink(t('Log out'), 0, 'User was logged in.');
220
221
    // Verify user was redirected away from user/login to an accessible page.
222
    $this->assertText(t('Operating in maintenance mode.'));
223
    $this->assertResponse(200);
224
  }
225
226
  /**
227
   * Test deleting an OpenID identity from a user's profile.
228
   */
229
  function testDelete() {
230
    $this->drupalLogin($this->web_user);
231
232
    // Add identity to user's profile.
233
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
234
    $this->addIdentity($identity);
235
    $this->assertText($identity, 'Identity appears in list.');
236
237
    // Delete the newly added identity.
238
    $this->clickLink(t('Delete'));
239
    $this->drupalPost(NULL, array(), t('Confirm'));
240
241
    $this->assertText(t('OpenID deleted.'), 'Identity deleted');
242
    $this->assertNoText($identity, 'Identity no longer appears in list.');
243
  }
244
245
  /**
246
   * Test that a blocked user cannot log in.
247
   */
248
  function testBlockedUserLogin() {
249
    // Use a User-supplied Identity that is the URL of an XRDS document.
250
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
251
252
    // Log in and add an OpenID Identity to the account.
253
    $this->drupalLogin($this->web_user);
254
    $this->addIdentity($identity);
255
    $this->drupalLogout();
256
257
    // Log in as an admin user and block the account.
258
    $admin_user = $this->drupalCreateUser(array('administer users'));
259
    $this->drupalLogin($admin_user);
260
    $this->drupalGet('admin/people');
261
    $edit = array(
262
      'operation' => 'block',
263
      'accounts[' . $this->web_user->uid . ']' => TRUE,
264
    );
265
    $this->drupalPost('admin/people', $edit, t('Update'));
266
    $this->assertRaw('The update has been performed.', 'Account was blocked.');
267
    $this->drupalLogout();
268
269
    $this->submitLoginForm($identity);
270
    $this->assertRaw(t('The username %name has not been activated or is blocked.', array('%name' => $this->web_user->name)), 'User login was blocked.');
271
  }
272
273
  /**
274
   * Add OpenID identity to user's profile.
275
   *
276
   * @param $identity
277
   *   The User-supplied Identifier.
278
   * @param $version
279
   *   The protocol version used by the service.
280
   * @param $local_id
281
   *   The expected OP-Local Identifier found during discovery.
282
   * @param $claimed_id
283
   *   The expected Claimed Identifier returned by the OpenID Provider, or FALSE
284
   *   if the discovery is expected to fail.
285
   */
286
  function addIdentity($identity, $version = 2, $local_id = 'http://example.com/xrds', $claimed_id = NULL) {
287
    // Tell openid_test.module to only accept this OP-Local Identifier.
288
    variable_set('openid_test_identity', $local_id);
289
290
    $edit = array('openid_identifier' => $identity);
291
    $this->drupalPost('user/' . $this->web_user->uid . '/openid', $edit, t('Add an OpenID'));
292
293
    if ($claimed_id === FALSE) {
294
      $this->assertRaw(t('Sorry, that is not a valid OpenID. Ensure you have spelled your ID correctly.'), 'Invalid identity was rejected.');
295
      return;
296
    }
297
298
    // OpenID 1 used a HTTP redirect, OpenID 2 uses a HTML form that is submitted automatically using JavaScript.
299
    if ($version == 2) {
300
      // Check we are on the OpenID redirect form.
301
      $this->assertTitle(t('OpenID redirect'), 'OpenID redirect page was displayed.');
302
303
      // Submit form to the OpenID Provider Endpoint.
304
      $this->drupalPost(NULL, array(), t('Send'));
305
    }
306
307
    if (!isset($claimed_id)) {
308
      $claimed_id = $identity;
309
    }
310
    $this->assertRaw(t('Successfully added %identity', array('%identity' => $claimed_id)), format_string('Identity %identity was added.', array('%identity' => $identity)));
311
  }
312
313
  /**
314
   * Add OpenID identity, changed by the following redirects, to user's profile.
315
   *
316
   * According to OpenID Authentication 2.0, section 7.2.4, URL Identifiers MUST
317
   * be further normalized by following redirects when retrieving their content
318
   * and this final URL MUST be noted by the Relying Party as the Claimed
319
   * Identifier and be used when requesting authentication.
320
   *
321
   * @param $identity
322
   *   The User-supplied Identifier.
323
   * @param $version
324
   *   The protocol version used by the service.
325
   * @param $local_id
326
   *   The expected OP-Local Identifier found during discovery.
327
   * @param $claimed_id
328
   *   The expected Claimed Identifier returned by the OpenID Provider, or FALSE
329
   *   if the discovery is expected to fail.
330
   * @param $redirects
331
   *   The number of redirects.
332
   */
333
  function addRedirectedIdentity($identity, $version = 2, $local_id = 'http://example.com/xrds', $claimed_id = NULL, $redirects = 0) {
334
    // Set the final destination URL which is the same as the Claimed
335
    // Identifier, we insert the same identifier also to the provider response,
336
    // but provider could further change the Claimed ID actually (e.g. it could
337
    // add unique fragment).
338
    variable_set('openid_test_redirect_url', $identity);
339
    variable_set('openid_test_response', array('openid.claimed_id' => $identity));
340
341
    $this->addIdentity(url('openid-test/redirect/' . $redirects, array('absolute' => TRUE)), $version, $local_id, $claimed_id);
342
343
    // Clean up.
344
    variable_del('openid_test_redirect_url');
345
    variable_del('openid_test_response');
346
  }
347
348
  /**
349
   * Tests that openid.signed is verified.
350
   */
351
  function testSignatureValidation() {
352
    // Use a User-supplied Identity that is the URL of an XRDS document.
353
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
354
355
    // Respond with an invalid signature.
356
    variable_set('openid_test_response', array('openid.sig' => 'this-is-an-invalid-signature'));
357
    $this->submitLoginForm($identity);
358
    $this->assertRaw('OpenID login failed.');
359
360
    // Do not sign the mandatory field openid.assoc_handle.
361
    variable_set('openid_test_response', array('openid.signed' => 'op_endpoint,claimed_id,identity,return_to,response_nonce'));
362
    $this->submitLoginForm($identity);
363
    $this->assertRaw('OpenID login failed.');
364
365
    // Sign all mandatory fields and a custom field.
366
    $keys_to_sign = array('op_endpoint', 'claimed_id', 'identity', 'return_to', 'response_nonce', 'assoc_handle', 'foo');
367
    $association = new stdClass();
368
    $association->mac_key = variable_get('mac_key');
369
    $response = array(
370
      'openid.op_endpoint' => url('openid-test/endpoint', array('absolute' => TRUE)),
371
      'openid.claimed_id' => $identity,
372
      'openid.identity' => $identity,
373
      'openid.return_to' => url('openid/authenticate', array('absolute' => TRUE)),
374
      'openid.response_nonce' => _openid_nonce(),
375
      'openid.assoc_handle' => 'openid-test',
376
      'openid.foo' => 123,
377
      'openid.signed' => implode(',', $keys_to_sign),
378
    );
379
    $response['openid.sig'] = _openid_signature($association, $response, $keys_to_sign);
380
    variable_set('openid_test_response', $response);
381
    $this->submitLoginForm($identity);
382
    $this->assertNoRaw('OpenID login failed.');
383
    $this->assertFieldByName('name', '', 'No username was supplied by provider.');
384
    $this->assertFieldByName('mail', '', 'No e-mail address was supplied by provider.');
385
386
    // Check that unsigned SREG fields are ignored.
387
    $response = array(
388
      'openid.signed' => 'op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle,sreg.nickname',
389
      'openid.sreg.nickname' => 'john',
390
      'openid.sreg.email' => 'john@example.com',
391
    );
392
    variable_set('openid_test_response', $response);
393
    $this->submitLoginForm($identity);
394
    $this->assertNoRaw('OpenID login failed.');
395
    $this->assertFieldByName('name', 'john', 'Username was supplied by provider.');
396
    $this->assertFieldByName('mail', '', 'E-mail address supplied by provider was ignored.');
397
  }
398
}
399
400
/**
401
 * Test account registration using Simple Registration and Attribute Exchange.
402
 */
403
class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
404
  public static function getInfo() {
405
    return array(
406
      'name' => 'OpenID account registration',
407
      'description' => 'Creates a user account using auto-registration.',
408
      'group' => 'OpenID'
409
    );
410
  }
411
412
  function setUp() {
413
    parent::setUp('openid', 'openid_test');
414
    variable_set('user_register', USER_REGISTER_VISITORS);
415
  }
416
417
  /**
418
   * Test OpenID auto-registration with e-mail verification enabled.
419
   */
420
  function testRegisterUserWithEmailVerification() {
421
    variable_set('user_email_verification', TRUE);
422
423
    // Tell openid_test.module to respond with these SREG fields.
424
    variable_set('openid_test_response', array('openid.sreg.nickname' => 'john', 'openid.sreg.email' => 'john@example.com'));
425
426
    // Use a User-supplied Identity that is the URL of an XRDS document.
427
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
428
    $this->submitLoginForm($identity);
429
    $this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), 'User was asked to verify e-mail address.');
430
    $this->assertRaw(t('A welcome message with further instructions has been sent to your e-mail address.'), 'A welcome message was sent to the user.');
431
    $reset_url = $this->getPasswordResetURLFromMail();
432
433
    $user = user_load_by_name('john');
434
    $this->assertTrue($user, 'User was registered with right username.');
435
    $this->assertEqual($user->mail, 'john@example.com', 'User was registered with right email address.');
436
    $this->assertFalse($user->data, 'No additional user info was saved.');
437
438
    $this->submitLoginForm($identity);
439
    $this->assertRaw(t('You must validate your email address for this account before logging in via OpenID.'));
440
441
    // Follow the one-time login that was sent in the welcome e-mail.
442
    $this->drupalGet($reset_url);
443
    $this->drupalPost(NULL, array(), t('Log in'));
444
445
    $this->drupalLogout();
446
447
    // Verify that the account was activated.
448
    $this->submitLoginForm($identity);
449
    $this->assertLink(t('Log out'), 0, 'User was logged in.');
450
  }
451
452
  /**
453
   * Test OpenID auto-registration with e-mail verification disabled.
454
   */
455
  function testRegisterUserWithoutEmailVerification() {
456
    variable_set('user_email_verification', FALSE);
457
458
    // Tell openid_test.module to respond with these SREG fields.
459
    variable_set('openid_test_response', array('openid.sreg.nickname' => 'john', 'openid.sreg.email' => 'john@example.com'));
460
461
    // Use a User-supplied Identity that is the URL of an XRDS document.
462
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
463
    $this->submitLoginForm($identity);
464
    $this->assertLink(t('Log out'), 0, 'User was logged in.');
465
466
    $user = user_load_by_name('john');
467
    $this->assertTrue($user, 'User was registered with right username.');
468
    $this->assertEqual($user->mail, 'john@example.com', 'User was registered with right email address.');
469
    $this->assertFalse($user->data, 'No additional user info was saved.');
470
471
    $this->drupalLogout();
472
473
    $this->submitLoginForm($identity);
474
    $this->assertLink(t('Log out'), 0, 'User was logged in.');
475
  }
476
477
  /**
478
   * Test OpenID auto-registration with a provider that supplies invalid SREG
479
   * information (a username that is already taken, and no e-mail address).
480
   */
481
  function testRegisterUserWithInvalidSreg() {
482
    // Tell openid_test.module to respond with these SREG fields.
483
    $web_user = $this->drupalCreateUser(array());
484
    variable_set('openid_test_response', array('openid.sreg.nickname' => $web_user->name, 'openid.sreg.email' => 'mail@invalid#'));
485
486
    // Use a User-supplied Identity that is the URL of an XRDS document.
487
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
488
    $this->submitLoginForm($identity);
489
490
    $this->assertRaw(t('Account registration using the information provided by your OpenID provider failed due to the reasons listed below. Complete the registration by filling out the form below. If you already have an account, you can <a href="@login">log in</a> now and add your OpenID under "My account".', array('@login' => url('user/login'))), 'User was asked to complete the registration process manually.');
491
    $this->assertRaw(t('The name %name is already taken.', array('%name' => $web_user->name)), 'Form validation error for username was displayed.');
492
    $this->assertRaw(t('The e-mail address %mail is not valid.', array('%mail' => 'mail@invalid#')), 'Form validation error for e-mail address was displayed.');
493
494
    // Enter username and e-mail address manually.
495
    $edit = array('name' => 'john', 'mail' => 'john@example.com');
496
    $this->drupalPost(NULL, $edit, t('Create new account'));
497
    $this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), 'User was asked to verify e-mail address.');
498
    $reset_url = $this->getPasswordResetURLFromMail();
499
500
    $user = user_load_by_name('john');
501
    $this->assertTrue($user, 'User was registered with right username.');
502
    $this->assertFalse($user->data, 'No additional user info was saved.');
503
504
    // Follow the one-time login that was sent in the welcome e-mail.
505
    $this->drupalGet($reset_url);
506
    $this->drupalPost(NULL, array(), t('Log in'));
507
508
    // The user is taken to user/%uid/edit.
509
    $this->assertFieldByName('mail', 'john@example.com', 'User was registered with right e-mail address.');
510
511
    $this->clickLink(t('OpenID identities'));
512
    $this->assertRaw($identity, 'OpenID identity was registered.');
513
  }
514
515
  /**
516
   * Test OpenID auto-registration with a provider that does not supply SREG
517
   * information (i.e. no username or e-mail address).
518
   */
519
  function testRegisterUserWithoutSreg() {
520
    // Load the front page to get the user login block.
521
    $this->drupalGet('');
522
523
    // Use a User-supplied Identity that is the URL of an XRDS document.
524
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
525
    $this->submitLoginForm($identity);
526
    $this->assertRaw(t('Complete the registration by filling out the form below. If you already have an account, you can <a href="@login">log in</a> now and add your OpenID under "My account".', array('@login' => url('user/login'))), 'User was asked to complete the registration process manually.');
527
    $this->assertNoRaw(t('You must enter a username.'), 'Form validation error for username was not displayed.');
528
    $this->assertNoRaw(t('You must enter an e-mail address.'), 'Form validation error for e-mail address was not displayed.');
529
530
    // Enter username and e-mail address manually.
531
    $edit = array('name' => 'john', 'mail' => 'john@example.com');
532
    $this->drupalPost(NULL, $edit, t('Create new account'));
533
    $this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), 'User was asked to verify e-mail address.');
534
    $reset_url = $this->getPasswordResetURLFromMail();
535
536
    $user = user_load_by_name('john');
537
    $this->assertTrue($user, 'User was registered with right username.');
538
    $this->assertFalse($user->data, 'No additional user info was saved.');
539
540
    // Follow the one-time login that was sent in the welcome e-mail.
541
    $this->drupalGet($reset_url);
542
    $this->drupalPost(NULL, array(), t('Log in'));
543
544
    // The user is taken to user/%uid/edit.
545
    $this->assertFieldByName('mail', 'john@example.com', 'User was registered with right e-mail address.');
546
547
    $this->clickLink(t('OpenID identities'));
548
    $this->assertRaw($identity, 'OpenID identity was registered.');
549
  }
550
551
  /**
552
   * Test OpenID auto-registration with a provider that supplies AX information,
553
   * but no SREG.
554
   */
555
  function testRegisterUserWithAXButNoSREG() {
556
    variable_set('user_email_verification', FALSE);
557
558
    // Tell openid_test.module to respond with these AX fields.
559
    variable_set('openid_test_response', array(
560
      'openid.ns.ext123' => 'http://openid.net/srv/ax/1.0',
561
      'openid.ext123.type.mail456' => 'http://axschema.org/contact/email',
562
      'openid.ext123.value.mail456' => 'john@example.com',
563
      'openid.ext123.type.name789' => 'http://schema.openid.net/namePerson/friendly',
564
      'openid.ext123.count.name789' => '1',
565
      'openid.ext123.value.name789.1' => 'john',
566
    ));
567
568
    // Use a User-supplied Identity that is the URL of an XRDS document.
569
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
570
    $this->submitLoginForm($identity);
571
    $this->assertLink(t('Log out'), 0, 'User was logged in.');
572
573
    $user = user_load_by_name('john');
574
    $this->assertTrue($user, 'User was registered with right username.');
575
    $this->assertEqual($user->mail, 'john@example.com', 'User was registered with right email address.');
576
  }
577
}
578
579
/**
580
 * Test account registration using Simple Registration and Attribute Exchange.
581
 */
582
class OpenIDInvalidIdentifierTransitionTestCase extends OpenIDFunctionalTestCase  {
583
584
  public static function getInfo() {
585
    return array(
586
      'name' => 'OpenID account update',
587
      'description' => 'Tries to correct OpenID identifiers attached to accounts if their identifiers were stripped.',
588
      'group' => 'OpenID',
589
    );
590
  }
591
592
  function setUp() {
593
    parent::setUp('openid', 'openid_test');
594
    variable_set('user_register', USER_REGISTER_VISITORS);
595
    variable_set('openid_less_obtrusive_transition', TRUE);
596
  }
597
598
  /**
599
   * Test OpenID transition with e-mail mismatch.
600
   */
601
  function testStrippedFragmentAccountEmailMismatch() {
602
    $this->drupalLogin($this->web_user);
603
604
    // Use a User-supplied Identity that is the URL of an XRDS document.
605
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE, 'fragment' => $this->randomName()));
606
    $identity_stripped = preg_replace('/#.*/', '', $identity);
607
608
    // Add invalid identifier to the authmap (identifier has stripped fragment).
609
    $this->addIdentity($identity_stripped);
610
    $this->drupalLogout();
611
612
    // Test logging in via the login form, provider will respond with full
613
    // identifier (including fragment) but with different email, so we can't
614
    // provide auto-update.
615
    variable_set('openid_test_response', array(
616
      'openid.claimed_id' => $identity,
617
      'openid.sreg.nickname' => $this->web_user->name,
618
      'openid.sreg.email' => 'invalid-' . $this->web_user->mail));
619
620
    $edit = array('openid_identifier' => $identity_stripped);
621
    $this->submitLoginForm($identity_stripped);
622
623
    // Verify user was redirected away from user login to an accessible page.
624
    $this->assertResponse(200);
625
626
    // Verify the message.
627
    $this->assertRaw(t('There is already an existing account associated with the OpenID identifier that you have provided.'), 'Message that OpenID identifier must be updated manually was displayed.');
628
  }
629
630
  /**
631
   * Test OpenID auto transition with e-mail.
632
   */
633
  function testStrippedFragmentAccountAutoUpdateSreg() {
634
    $this->drupalLogin($this->web_user);
635
636
    // Use a User-supplied Identity that is the URL of an XRDS document.
637
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE, 'fragment' => $this->randomName()));
638
    $identity_stripped = preg_replace('/#.*/', '', $identity);
639
640
    // Add invalid identifier to the authmap (identifier has stripped fragment).
641
    $this->addIdentity($identity_stripped);
642
    $this->drupalLogout();
643
644
    // Test logging in via the login form, provider will respond with full
645
    // identifier (including fragment) but with different email, so we can't
646
    // provide auto-update.
647
    variable_set('openid_test_response', array(
648
      'openid.claimed_id' => $identity,
649
      'openid.sreg.nickname' => $this->web_user->name,
650
      'openid.sreg.email' => $this->web_user->mail));
651
652
    $this->submitLoginForm($identity_stripped);
653
654
    // Verify user was redirected away from user login to an accessible page.
655
    $this->assertResponse(200);
656
657
    // Verify the message.
658
    $this->assertRaw(t('New OpenID identifier %identity was added as a replacement for invalid identifier %invalid_identity.', array('%invalid_identity' => $identity_stripped, '%identity' => $identity)), 'Message that OpenID identifier was added automatically was displayed.');
659
  }
660
}
661
662
/**
663
 * Test internal helper functions.
664
 */
665
class OpenIDTestCase extends DrupalWebTestCase {
666
  public static function getInfo() {
667
    return array(
668
      'name' => 'OpenID helper functions',
669
      'description' => 'Test OpenID helper functions.',
670
      'group' => 'OpenID'
671
    );
672
  }
673
674
  function setUp() {
675
    parent::setUp('openid');
676
    module_load_include('inc', 'openid');
677
  }
678
679
  /**
680
   * Test _openid_dh_XXX_to_XXX() functions.
681
   */
682
  function testConversion() {
683
    $this->assertEqual(_openid_dh_long_to_base64('12345678901234567890123456789012345678901234567890'), 'CHJ/Y2mq+DyhUCZ0evjH8ZbOPwrS', '_openid_dh_long_to_base64() returned expected result.');
684
    $this->assertEqual(_openid_dh_base64_to_long('BsH/g8Nrpn2dtBSdu/sr1y8hxwyx'), '09876543210987654321098765432109876543210987654321', '_openid_dh_base64_to_long() returned expected result.');
685
686
    $this->assertEqual(_openid_dh_long_to_binary('12345678901234567890123456789012345678901234567890'), "\x08r\x7fci\xaa\xf8<\xa1P&tz\xf8\xc7\xf1\x96\xce?\x0a\xd2", '_openid_dh_long_to_binary() returned expected result.');
687
    $this->assertEqual(_openid_dh_binary_to_long("\x06\xc1\xff\x83\xc3k\xa6}\x9d\xb4\x14\x9d\xbb\xfb+\xd7/!\xc7\x0c\xb1"), '09876543210987654321098765432109876543210987654321', '_openid_dh_binary_to_long() returned expected result.');
688
  }
689
690
  /**
691
   * Test _openid_dh_xorsecret().
692
   */
693
  function testOpenidDhXorsecret() {
694
    $this->assertEqual(_openid_dh_xorsecret('123456790123456790123456790', "abc123ABC\x00\xFF"), "\xa4'\x06\xbe\xf1.\x00y\xff\xc2\xc1", '_openid_dh_xorsecret() returned expected result.');
695
  }
696
697
  /**
698
   * Test _openid_signature().
699
   */
700
  function testOpenidSignature() {
701
    // Test that signature is calculated according to OpenID Authentication 2.0,
702
    // section 6.1. In the following array, only the two first entries should be
703
    // included in the calculation, because the substring following the period
704
    // is mentioned in the third argument for _openid_signature(). The last
705
    // entry should not be included, because it does not start with "openid.".
706
    $response = array(
707
      'openid.foo' => 'abc1',
708
      'openid.bar' => 'abc2',
709
      'openid.baz' => 'abc3',
710
      'foobar.foo' => 'abc4',
711
    );
712
    $association = new stdClass();
713
    $association->mac_key = "1234567890abcdefghij\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9";
714
    $this->assertEqual(_openid_signature($association, $response, array('foo', 'bar')), 'QnKZQzSFstT+GNiJDFOptdcZjrc=', 'Expected signature calculated.');
715
  }
716
717
  /**
718
   * Test _openid_is_xri().
719
   */
720
  function testOpenidXRITest() {
721
    // Test that the XRI test is according to OpenID Authentication 2.0,
722
    // section 7.2. If the user-supplied string starts with xri:// it should be
723
    // stripped and the resulting string should be treated as an XRI when it
724
    // starts with "=", "@", "+", "$", "!" or "(".
725
    $this->assertTrue(_openid_is_xri('xri://=foo'), '_openid_is_xri() returned expected result for an xri identifier with xri scheme.');
726
    $this->assertTrue(_openid_is_xri('xri://@foo'), '_openid_is_xri() returned expected result for an xri identifier with xri scheme.');
727
    $this->assertTrue(_openid_is_xri('xri://+foo'), '_openid_is_xri() returned expected result for an xri identifier with xri scheme.');
728
    $this->assertTrue(_openid_is_xri('xri://$foo'), '_openid_is_xri() returned expected result for an xri identifier with xri scheme.');
729
    $this->assertTrue(_openid_is_xri('xri://!foo'), '_openid_is_xri() returned expected result for an xri identifier with xri scheme..');
730
    $this->assertTrue(_openid_is_xri('xri://(foo'), '_openid_is_xri() returned expected result for an xri identifier with xri scheme..');
731
732
    $this->assertTrue(_openid_is_xri('=foo'), '_openid_is_xri() returned expected result for an xri identifier.');
733
    $this->assertTrue(_openid_is_xri('@foo'), '_openid_is_xri() returned expected result for an xri identifier.');
734
    $this->assertTrue(_openid_is_xri('+foo'), '_openid_is_xri() returned expected result for an xri identifier.');
735
    $this->assertTrue(_openid_is_xri('$foo'), '_openid_is_xri() returned expected result for an xri identifier.');
736
    $this->assertTrue(_openid_is_xri('!foo'), '_openid_is_xri() returned expected result for an xri identifier.');
737
    $this->assertTrue(_openid_is_xri('(foo'), '_openid_is_xri() returned expected result for an xri identifier.');
738
739
    $this->assertFalse(_openid_is_xri('foo'), '_openid_is_xri() returned expected result for an http URL.');
740
    $this->assertFalse(_openid_is_xri('xri://foo'), '_openid_is_xri() returned expected result for an http URL.');
741
    $this->assertFalse(_openid_is_xri('http://foo/'), '_openid_is_xri() returned expected result for an http URL.');
742
    $this->assertFalse(_openid_is_xri('http://example.com/'), '_openid_is_xri() returned expected result for an http URL.');
743
    $this->assertFalse(_openid_is_xri('user@example.com/'), '_openid_is_xri() returned expected result for an http URL.');
744
    $this->assertFalse(_openid_is_xri('http://user@example.com/'), '_openid_is_xri() returned expected result for an http URL.');
745
  }
746
747
  /**
748
   * Test openid_normalize().
749
   */
750
  function testOpenidNormalize() {
751
    // Test that the normalization is according to OpenID Authentication 2.0,
752
    // section 7.2 and 11.5.2.
753
754
    $this->assertEqual(openid_normalize('$foo'), '$foo', 'openid_normalize() correctly normalized an XRI.');
755
    $this->assertEqual(openid_normalize('xri://$foo'), '$foo', 'openid_normalize() correctly normalized an XRI with an xri:// scheme.');
756
757
    $this->assertEqual(openid_normalize('example.com/'), 'http://example.com/', 'openid_normalize() correctly normalized a URL with a missing scheme.');
758
    $this->assertEqual(openid_normalize('example.com'), 'http://example.com/', 'openid_normalize() correctly normalized a URL with a missing scheme and empty path.');
759
    $this->assertEqual(openid_normalize('http://example.com'), 'http://example.com/', 'openid_normalize() correctly normalized a URL with an empty path.');
760
761
    $this->assertEqual(openid_normalize('http://example.com/path'), 'http://example.com/path', 'openid_normalize() correctly normalized a URL with a path.');
762
763
    $this->assertEqual(openid_normalize('http://example.com/path#fragment'), 'http://example.com/path', 'openid_normalize() correctly normalized a URL with a fragment.');
764
  }
765
766
  /**
767
   * Test openid_extract_namespace().
768
   */
769
  function testOpenidExtractNamespace() {
770
    $response = array(
771
      'openid.sreg.nickname' => 'john',
772
      'openid.ns.ext1' => OPENID_NS_SREG,
773
      'openid.ext1.nickname' => 'george',
774
      'openid.ext1.email' => 'george@example.com',
775
      'openid.ns.ext2' => 'http://example.com/ns/ext2',
776
      'openid.ext2.foo' => '123',
777
      'openid.ext2.bar' => '456',
778
      'openid.signed' => 'sreg.nickname,ns.ext1,ext1.email,ext2.foo',
779
    );
780
781
    $values = openid_extract_namespace($response, 'http://example.com/ns/dummy', NULL, FALSE);
782
    $this->assertEqual($values, array(), 'Nothing found for unused namespace.');
783
784
    $values = openid_extract_namespace($response, 'http://example.com/ns/dummy', 'sreg', FALSE);
785
    $this->assertEqual($values, array('nickname' => 'john'), 'Value found for fallback prefix.');
786
787
    $values = openid_extract_namespace($response, OPENID_NS_SREG, 'sreg', FALSE);
788
    $this->assertEqual($values, array('nickname' => 'george', 'email' => 'george@example.com'), 'Namespace takes precedence over fallback prefix.');
789
790
    // ext1.email is signed, but ext1.nickname is not.
791
    $values = openid_extract_namespace($response, OPENID_NS_SREG, 'sreg', TRUE);
792
    $this->assertEqual($values, array('email' => 'george@example.com'), 'Unsigned namespaced fields ignored.');
793
794
    $values = openid_extract_namespace($response, 'http://example.com/ns/ext2', 'sreg', FALSE);
795
    $this->assertEqual($values, array('foo' => '123', 'bar' => '456'), 'Unsigned fields found.');
796
797
    // ext2.foo and ext2.bar are ignored, because ns.ext2 is not signed. The
798
    // fallback prefix is not used, because the namespace is specified.
799
    $values = openid_extract_namespace($response, 'http://example.com/ns/ext2', 'sreg', TRUE);
800
    $this->assertEqual($values, array(), 'Unsigned fields ignored.');
801
  }
802
}