openid.test 29.6 KB
Newer Older
1 2
<?php

3 4 5 6 7
/**
 * @file
 * Tests for openid.module.
 */

8
/**
9
 * Base class for OpenID tests.
10
 */
11 12 13 14 15 16 17 18 19 20 21
abstract class OpenIDWebTestCase extends DrupalWebTestCase {

  /**
   * Initiates the login procedure using the specified User-supplied Identity.
   */
  function submitLoginForm($identity) {
    // Fill out and submit the login form.
    $edit = array('openid_identifier' => $identity);
    $this->drupalPost('', $edit, t('Log in'));

    // Check we are on the OpenID redirect form.
22
    $this->assertTitle(t('OpenID redirect'), t('OpenID redirect page was displayed.'));
23 24 25 26

    // Submit form to the OpenID Provider Endpoint.
    $this->drupalPost(NULL, array(), t('Send'));
  }
27 28 29 30 31 32 33 34 35 36

  /**
   * Parses the last sent e-mail and returns the one-time login link URL.
   */
  function getPasswordResetURLFromMail() {
    $mails = $this->drupalGetMails();
    $mail = end($mails);
    preg_match('@.+user/reset/.+@', $mail['body'], $matches);
    return $matches[0];
  }
37 38 39 40 41 42
}

/**
 * Test discovery and login using OpenID
 */
class OpenIDFunctionalTestCase extends OpenIDWebTestCase {
43 44
  protected $web_user;

45
  public static function getInfo() {
46
    return array(
47 48
      'name' => 'OpenID discovery and login',
      'description' => "Adds an identity to a user's profile and uses it to log in.",
49
      'group' => 'OpenID'
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
    );
  }

  function setUp() {
    parent::setUp('openid', 'openid_test');

    // User doesn't need special permissions; only the ability to log in.
    $this->web_user = $this->drupalCreateUser(array());
  }

  /**
   * Test discovery of OpenID Provider Endpoint via Yadis and HTML.
   */
  function testDiscovery() {
    $this->drupalLogin($this->web_user);

    // The User-supplied Identifier entered by the user may indicate the URL of
    // the OpenID Provider Endpoint in various ways, as described in OpenID
    // Authentication 2.0 and Yadis Specification 1.0.
    // Note that all of the tested identifiers refer to the same endpoint, so
    // only the first will trigger an associate request in openid_association()
    // (association is only done the first time Drupal encounters a given
    // endpoint).


    // Yadis discovery (see Yadis Specification 1.0, section 6.2.5):
    // If the User-supplied Identifier is a URL, it may be a direct or indirect
    // reference to an XRDS document (a Yadis Resource Descriptor) that contains
    // the URL of the OpenID Provider Endpoint.

    // Identifier is the URL of an XRDS document.
81 82 83
    // The URL scheme is stripped in order to test that the supplied identifier
    // is normalized in openid_begin().
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
84 85 86 87
    $this->addIdentity(preg_replace('@^https?://@', '', $identity), 2, 'http://example.com/xrds', $identity);

    $identity = url('openid-test/yadis/xrds/delegate', array('absolute' => TRUE));
    $this->addIdentity(preg_replace('@^https?://@', '', $identity), 2, 'http://example.com/xrds-delegate', $identity);
88

89 90 91
    // Identifier is the URL of an XRDS document containing an OP Identifier
    // Element. The Relying Party sends the special value
    // "http://specs.openid.net/auth/2.0/identifier_select" as Claimed
92 93 94 95 96 97
    // Identifier. The OpenID Provider responds with the actual identifier
    // including the fragment.
    $identity = url('openid-test/yadis/xrds/dummy-user', array('absolute' => TRUE, 'fragment' => $this->randomName()));
    // Tell openid_test.module to respond with this identifier. We test if
    // openid_complete() processes it right.
    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 102 103 104 105 106 107 108
    // Identifier is the URL of an HTML page that is sent with an HTTP header
    // that contains the URL of an XRDS document.
    $this->addIdentity(url('openid-test/yadis/x-xrds-location', array('absolute' => TRUE)), 2);

    // Identifier is the URL of an HTML page containing a <meta http-equiv=...>
    // element that contains the URL of an XRDS document.
    $this->addIdentity(url('openid-test/yadis/http-equiv', array('absolute' => TRUE)), 2);

109 110
    // Identifier is an XRI. Resolve using our own dummy proxy resolver.
    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 114
    // Make sure that unverified CanonicalID are not trusted.
    variable_set('openid_test_canonical_id_status', 'bad value');
115
    $this->addIdentity('@example*résumé;%25', 2, FALSE, FALSE);
116

117 118 119 120 121 122
    // HTML-based discovery:
    // If the User-supplied Identifier is a URL of an HTML page, the page may
    // contain a <link rel=...> element containing the URL of the OpenID
    // Provider Endpoint. OpenID 1 and 2 describe slightly different formats.

    // 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 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148

    // OpenID Authentication 2.0, section 7.2.4:
    // URL Identifiers MUST then be further normalized by both (1) following
    // redirects when retrieving their content and finally (2) applying the
    // rules in Section 6 of RFC3986 to the final destination URL. This final
    // URL MUST be noted by the Relying Party as the Claimed Identifier and be
    // used when requesting authentication.

    // Single redirect.
    $identity = $expected_claimed_id = url('openid-test/redirected/yadis/xrds/1', array('absolute' => TRUE));
    $this->addRedirectedIdentity($identity, 2, 'http://example.com/xrds', $expected_claimed_id, 0);

    // Exact 3 redirects (default value for the 'max_redirects' option in
    // drupal_http_request()).
    $identity = $expected_claimed_id = url('openid-test/redirected/yadis/xrds/2', array('absolute' => TRUE));
    $this->addRedirectedIdentity($identity, 2, 'http://example.com/xrds', $expected_claimed_id, 2);

    // Fails because there are more than 3 redirects (default value for the
    // 'max_redirects' option in drupal_http_request()).
    $identity = url('openid-test/redirected/yadis/xrds/3', array('absolute' => TRUE));
    $expected_claimed_id = FALSE;
    $this->addRedirectedIdentity($identity, 2, 'http://example.com/xrds', $expected_claimed_id, 3);
149 150 151 152 153 154 155 156 157 158 159 160 161 162
  }

  /**
   * Test login using OpenID.
   */
  function testLogin() {
    $this->drupalLogin($this->web_user);

    // Use a User-supplied Identity that is the URL of an XRDS document.
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
    $this->addIdentity($identity);

    $this->drupalLogout();

163 164
    // Test logging in via the login block on the front page.
    $this->submitLoginForm($identity);
165
    $this->assertLink(t('Log out'), 0, t('User was logged in.'));
166 167

    $this->drupalLogout();
168 169 170

    // Test logging in via the user/login page.
    $edit = array('openid_identifier' => $identity);
171 172 173
    $this->drupalPost('user/login', $edit, t('Log in'));

    // Check we are on the OpenID redirect form.
174
    $this->assertTitle(t('OpenID redirect'), t('OpenID redirect page was displayed.'));
175 176 177 178

    // Submit form to the OpenID Provider Endpoint.
    $this->drupalPost(NULL, array(), t('Send'));

179
    $this->assertLink(t('Log out'), 0, t('User was logged in.'));
180 181 182

    // Verify user was redirected away from user/login to an accessible page.
    $this->assertResponse(200);
183 184
  }

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
  /**
   * Test login using OpenID during maintenance mode.
   */
  function testLoginMaintenanceMode() {
    $this->web_user = $this->drupalCreateUser(array('access site in maintenance mode'));
    $this->drupalLogin($this->web_user);

    // Use a User-supplied Identity that is the URL of an XRDS document.
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
    $this->addIdentity($identity);
    $this->drupalLogout();

    // Enable maintenance mode.
    variable_set('maintenance_mode', 1);

    // Test logging in via the user/login page while the site is offline.
    $edit = array('openid_identifier' => $identity);
    $this->drupalPost('user/login', $edit, t('Log in'));

    // Check we are on the OpenID redirect form.
205
    $this->assertTitle(t('OpenID redirect'), t('OpenID redirect page was displayed.'));
206 207 208 209

    // Submit form to the OpenID Provider Endpoint.
    $this->drupalPost(NULL, array(), t('Send'));

210
    $this->assertLink(t('Log out'), 0, t('User was logged in.'));
211 212 213 214 215 216

    // Verify user was redirected away from user/login to an accessible page.
    $this->assertText(t('Operating in maintenance mode.'));
    $this->assertResponse(200);
  }

217 218 219 220 221 222 223 224 225
  /**
   * Test deleting an OpenID identity from a user's profile.
   */
  function testDelete() {
    $this->drupalLogin($this->web_user);

    // Add identity to user's profile.
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
    $this->addIdentity($identity);
226
    $this->assertText($identity, t('Identity appears in list.'));
227 228 229 230 231

    // Delete the newly added identity.
    $this->clickLink(t('Delete'));
    $this->drupalPost(NULL, array(), t('Confirm'));

232 233
    $this->assertText(t('OpenID deleted.'), t('Identity deleted'));
    $this->assertNoText($identity, t('Identity no longer appears in list.'));
234 235
  }

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
  /**
   * Test that a blocked user cannot log in.
   */
  function testBlockedUserLogin() {
    // Use a User-supplied Identity that is the URL of an XRDS document.
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));

    // Log in and add an OpenID Identity to the account.
    $this->drupalLogin($this->web_user);
    $this->addIdentity($identity);
    $this->drupalLogout();

    // Log in as an admin user and block the account.
    $admin_user = $this->drupalCreateUser(array('administer users'));
    $this->drupalLogin($admin_user);
    $this->drupalGet('admin/people');
    $edit = array(
      'operation' => 'block',
      'accounts[' . $this->web_user->uid . ']' => TRUE,
    );
    $this->drupalPost('admin/people', $edit, t('Update'));
257
    $this->assertRaw('The update has been performed.', t('Account was blocked.'));
258 259
    $this->drupalLogout();

260
    $this->submitLoginForm($identity);
261
    $this->assertRaw(t('The username %name has not been activated or is blocked.', array('%name' => $this->web_user->name)), t('User login was blocked.'));
262 263
  }

264 265
  /**
   * Add OpenID identity to user's profile.
266 267 268 269 270
   *
   * @param $identity
   *   The User-supplied Identifier.
   * @param $version
   *   The protocol version used by the service.
271 272
   * @param $local_id
   *   The expected OP-Local Identifier found during discovery.
273
   * @param $claimed_id
274 275
   *   The expected Claimed Identifier returned by the OpenID Provider, or FALSE
   *   if the discovery is expected to fail.
276
   */
277 278 279 280
  function addIdentity($identity, $version = 2, $local_id = 'http://example.com/xrds', $claimed_id = NULL) {
    // Tell openid_test.module to only accept this OP-Local Identifier.
    variable_set('openid_test_identity', $local_id);

281
    $edit = array('openid_identifier' => $identity);
282 283 284
    $this->drupalPost('user/' . $this->web_user->uid . '/openid', $edit, t('Add an OpenID'));

    if ($claimed_id === FALSE) {
285
      $this->assertRaw(t('Sorry, that is not a valid OpenID. Ensure you have spelled your ID correctly.'), t('Invalid identity was rejected.'));
286 287
      return;
    }
288 289 290

    // OpenID 1 used a HTTP redirect, OpenID 2 uses a HTML form that is submitted automatically using JavaScript.
    if ($version == 2) {
291
      // Check we are on the OpenID redirect form.
292
      $this->assertTitle(t('OpenID redirect'), t('OpenID redirect page was displayed.'));
293 294

      // Submit form to the OpenID Provider Endpoint.
295 296 297
      $this->drupalPost(NULL, array(), t('Send'));
    }

298
    if (!isset($claimed_id)) {
299 300
      $claimed_id = $identity;
    }
301
    $this->assertRaw(t('Successfully added %identity', array('%identity' => $claimed_id)), t('Identity %identity was added.', array('%identity' => $identity)));
302
  }
303

304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
  /**
   * Add OpenID identity, changed by the following redirects, to user's profile.
   *
   * According to OpenID Authentication 2.0, section 7.2.4, URL Identifiers MUST
   * be further normalized by following redirects when retrieving their content
   * and this final URL MUST be noted by the Relying Party as the Claimed
   * Identifier and be used when requesting authentication.
   *
   * @param $identity
   *   The User-supplied Identifier.
   * @param $version
   *   The protocol version used by the service.
   * @param $local_id
   *   The expected OP-Local Identifier found during discovery.
   * @param $claimed_id
   *   The expected Claimed Identifier returned by the OpenID Provider, or FALSE
   *   if the discovery is expected to fail.
   * @param $redirects
   *   The number of redirects.
   */
  function addRedirectedIdentity($identity, $version = 2, $local_id = 'http://example.com/xrds', $claimed_id = NULL, $redirects = 0) {
    // Set the final destination URL which is the same as the Claimed
    // Identifier, we insert the same identifier also to the provider response,
327
    // but provider could further change the Claimed ID actually (e.g. it could
328 329 330 331 332 333 334 335 336 337 338
    // add unique fragment).
    variable_set('openid_test_redirect_url', $identity);
    variable_set('openid_test_response', array('openid.claimed_id' => $identity));

    $this->addIdentity(url('openid-test/redirect/' . $redirects, array('absolute' => TRUE)), $version, $local_id, $claimed_id);

    // Clean up.
    variable_del('openid_test_redirect_url');
    variable_del('openid_test_response');
  }

339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
  /**
   * Tests that openid.signed is verified.
   */
  function testSignatureValidation() {
    // Use a User-supplied Identity that is the URL of an XRDS document.
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));

    // Do not sign all mandatory fields (e.g. assoc_handle).
    variable_set('openid_test_response', array('openid.signed' => 'op_endpoint,claimed_id,identity,return_to,response_nonce'));
    $this->submitLoginForm($identity);
    $this->assertRaw('OpenID login failed.');

    // Sign all mandatory fields and some custom fields.
    variable_set('openid_test_response', array('openid.foo' => 'bar', 'openid.signed' => 'op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle,foo'));
    $this->submitLoginForm($identity);
    $this->assertNoRaw('OpenID login failed.');
  }

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
}

/**
 * Test account registration using Simple Registration and Attribute Exchange.
 */
class OpenIDRegistrationTestCase extends OpenIDWebTestCase {
  public static function getInfo() {
    return array(
      'name' => 'OpenID account registration',
      'description' => 'Creates a user account using auto-registration.',
      'group' => 'OpenID'
    );
  }

  function setUp() {
    parent::setUp('openid', 'openid_test');
373
    variable_set('user_register', USER_REGISTER_VISITORS);
374
  }
375 376

  /**
377
   * Test OpenID auto-registration with e-mail verification enabled.
378
   */
379 380
  function testRegisterUserWithEmailVerification() {
    variable_set('user_email_verification', TRUE);
381

382 383
    // Tell openid_test.module to respond with these SREG fields.
    variable_set('openid_test_response', array('openid.sreg.nickname' => 'john', 'openid.sreg.email' => 'john@example.com'));
384 385 386

    // Use a User-supplied Identity that is the URL of an XRDS document.
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
387
    $this->submitLoginForm($identity);
388 389
    $this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), t('User was asked to verify e-mail address.'));
    $this->assertRaw(t('A welcome message with further instructions has been sent to your e-mail address.'), t('A welcome message was sent to the user.'));
390
    $reset_url = $this->getPasswordResetURLFromMail();
391

392
    $user = user_load_by_name('john');
393 394 395
    $this->assertTrue($user, t('User was registered with right username.'));
    $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
    $this->assertFalse($user->data, t('No additional user info was saved.'));
396

397 398
    $this->submitLoginForm($identity);
    $this->assertRaw(t('You must validate your email address for this account before logging in via OpenID.'));
399

400
    // Follow the one-time login that was sent in the welcome e-mail.
401
    $this->drupalGet($reset_url);
402
    $this->drupalPost(NULL, array(), t('Log in'));
403

404 405 406 407
    $this->drupalLogout();

    // Verify that the account was activated.
    $this->submitLoginForm($identity);
408
    $this->assertLink(t('Log out'), 0, t('User was logged in.'));
409 410 411 412 413 414 415 416 417 418 419 420 421 422
  }

  /**
   * Test OpenID auto-registration with e-mail verification disabled.
   */
  function testRegisterUserWithoutEmailVerification() {
    variable_set('user_email_verification', FALSE);

    // Tell openid_test.module to respond with these SREG fields.
    variable_set('openid_test_response', array('openid.sreg.nickname' => 'john', 'openid.sreg.email' => 'john@example.com'));

    // Use a User-supplied Identity that is the URL of an XRDS document.
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
    $this->submitLoginForm($identity);
423
    $this->assertLink(t('Log out'), 0, t('User was logged in.'));
424 425

    $user = user_load_by_name('john');
426 427 428
    $this->assertTrue($user, t('User was registered with right username.'));
    $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
    $this->assertFalse($user->data, t('No additional user info was saved.'));
429 430 431 432

    $this->drupalLogout();

    $this->submitLoginForm($identity);
433
    $this->assertLink(t('Log out'), 0, t('User was logged in.'));
434 435 436 437 438 439 440
  }

  /**
   * Test OpenID auto-registration with a provider that supplies invalid SREG
   * information (a username that is already taken, and no e-mail address).
   */
  function testRegisterUserWithInvalidSreg() {
441 442 443
    // Tell openid_test.module to respond with these SREG fields.
    $web_user = $this->drupalCreateUser(array());
    variable_set('openid_test_response', array('openid.sreg.nickname' => $web_user->name, 'openid.sreg.email' => 'mail@invalid#'));
444 445 446

    // Use a User-supplied Identity that is the URL of an XRDS document.
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
447
    $this->submitLoginForm($identity);
448

449 450 451
    $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'))), t('User was asked to complete the registration process manually.'));
    $this->assertRaw(t('The name %name is already taken.', array('%name' => $web_user->name)), t('Form validation error for username was displayed.'));
    $this->assertRaw(t('The e-mail address %mail is not valid.', array('%mail' => 'mail@invalid#')), t('Form validation error for e-mail address was displayed.'));
452 453 454 455

    // Enter username and e-mail address manually.
    $edit = array('name' => 'john', 'mail' => 'john@example.com');
    $this->drupalPost(NULL, $edit, t('Create new account'));
456
    $this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), t('User was asked to verify e-mail address.'));
457
    $reset_url = $this->getPasswordResetURLFromMail();
458 459

    $user = user_load_by_name('john');
460 461
    $this->assertTrue($user, t('User was registered with right username.'));
    $this->assertFalse($user->data, t('No additional user info was saved.'));
462

463
    // Follow the one-time login that was sent in the welcome e-mail.
464
    $this->drupalGet($reset_url);
465 466 467
    $this->drupalPost(NULL, array(), t('Log in'));

    // The user is taken to user/%uid/edit.
468
    $this->assertFieldByName('mail', 'john@example.com', t('User was registered with right e-mail address.'));
469 470

    $this->clickLink(t('OpenID identities'));
471
    $this->assertRaw($identity, t('OpenID identity was registered.'));
472 473 474 475 476 477 478 479 480 481 482 483
  }

  /**
   * Test OpenID auto-registration with a provider that does not supply SREG
   * information (i.e. no username or e-mail address).
   */
  function testRegisterUserWithoutSreg() {
    // Load the front page to get the user login block.
    $this->drupalGet('');

    // Use a User-supplied Identity that is the URL of an XRDS document.
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
484
    $this->submitLoginForm($identity);
485 486 487
    $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'))), t('User was asked to complete the registration process manually.'));
    $this->assertNoRaw(t('You must enter a username.'), t('Form validation error for username was not displayed.'));
    $this->assertNoRaw(t('You must enter an e-mail address.'), t('Form validation error for e-mail address was not displayed.'));
488 489 490 491

    // Enter username and e-mail address manually.
    $edit = array('name' => 'john', 'mail' => 'john@example.com');
    $this->drupalPost(NULL, $edit, t('Create new account'));
492
    $this->assertRaw(t('Once you have verified your e-mail address, you may log in via OpenID.'), t('User was asked to verify e-mail address.'));
493
    $reset_url = $this->getPasswordResetURLFromMail();
494 495

    $user = user_load_by_name('john');
496 497
    $this->assertTrue($user, t('User was registered with right username.'));
    $this->assertFalse($user->data, t('No additional user info was saved.'));
498

499
    // Follow the one-time login that was sent in the welcome e-mail.
500
    $this->drupalGet($reset_url);
501 502 503
    $this->drupalPost(NULL, array(), t('Log in'));

    // The user is taken to user/%uid/edit.
504
    $this->assertFieldByName('mail', 'john@example.com', t('User was registered with right e-mail address.'));
505 506

    $this->clickLink(t('OpenID identities'));
507
    $this->assertRaw($identity, t('OpenID identity was registered.'));
508
  }
509 510 511 512 513 514 515 516 517 518 519

  /**
   * Test OpenID auto-registration with a provider that supplies AX information,
   * but no SREG.
   */
  function testRegisterUserWithAXButNoSREG() {
    variable_set('user_email_verification', FALSE);

    // Tell openid_test.module to respond with these AX fields.
    variable_set('openid_test_response', array(
      'openid.ns.ext123' => 'http://openid.net/srv/ax/1.0',
520 521 522 523 524
      'openid.ext123.type.mail456' => 'http://axschema.org/contact/email',
      'openid.ext123.value.mail456' => 'john@example.com',
      'openid.ext123.type.name789' => 'http://schema.openid.net/namePerson/friendly',
      'openid.ext123.count.name789' => '1',
      'openid.ext123.value.name789.1' => 'john',
525 526
    ));

527 528 529
    // Use a User-supplied Identity that is the URL of an XRDS document.
    $identity = url('openid-test/yadis/xrds', array('absolute' => TRUE));
    $this->submitLoginForm($identity);
530
    $this->assertLink(t('Log out'), 0, t('User was logged in.'));
531 532

    $user = user_load_by_name('john');
533 534
    $this->assertTrue($user, t('User was registered with right username.'));
    $this->assertEqual($user->mail, 'john@example.com', t('User was registered with right email address.'));
535
  }
536 537 538 539 540 541
}

/**
 * Test internal helper functions.
 */
class OpenIDUnitTest extends DrupalWebTestCase {
542
  public static function getInfo() {
543
    return array(
544 545 546
      'name' => 'OpenID helper functions',
      'description' => 'Test OpenID helper functions.',
      'group' => 'OpenID'
547 548 549 550 551 552 553 554 555 556 557 558
    );
  }

  function setUp() {
    parent::setUp('openid');
    module_load_include('inc', 'openid');
  }

  /**
   * Test _openid_dh_XXX_to_XXX() functions.
   */
  function testConversion() {
559 560
    $this->assertEqual(_openid_dh_long_to_base64('12345678901234567890123456789012345678901234567890'), 'CHJ/Y2mq+DyhUCZ0evjH8ZbOPwrS', t('_openid_dh_long_to_base64() returned expected result.'));
    $this->assertEqual(_openid_dh_base64_to_long('BsH/g8Nrpn2dtBSdu/sr1y8hxwyx'), '09876543210987654321098765432109876543210987654321', t('_openid_dh_base64_to_long() returned expected result.'));
561

562 563
    $this->assertEqual(_openid_dh_long_to_binary('12345678901234567890123456789012345678901234567890'), "\x08r\x7fci\xaa\xf8<\xa1P&tz\xf8\xc7\xf1\x96\xce?\x0a\xd2", t('_openid_dh_long_to_binary() returned expected result.'));
    $this->assertEqual(_openid_dh_binary_to_long("\x06\xc1\xff\x83\xc3k\xa6}\x9d\xb4\x14\x9d\xbb\xfb+\xd7/!\xc7\x0c\xb1"), '09876543210987654321098765432109876543210987654321', t('_openid_dh_binary_to_long() returned expected result.'));
564 565 566 567 568 569
  }

  /**
   * Test _openid_dh_xorsecret().
   */
  function testOpenidDhXorsecret() {
570
    $this->assertEqual(_openid_dh_xorsecret('123456790123456790123456790', "abc123ABC\x00\xFF"), "\xa4'\x06\xbe\xf1.\x00y\xff\xc2\xc1", t('_openid_dh_xorsecret() returned expected result.'));
571 572 573 574 575 576
  }

  /**
   * Test _openid_get_bytes().
   */
  function testOpenidGetBytes() {
577
    $this->assertEqual(strlen(_openid_get_bytes(20)), 20, t('_openid_get_bytes() returned expected result.'));
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
  }

  /**
   * Test _openid_signature().
   */
  function testOpenidSignature() {
    // Test that signature is calculated according to OpenID Authentication 2.0,
    // section 6.1. In the following array, only the two first entries should be
    // included in the calculation, because the substring following the period
    // is mentioned in the third argument for _openid_signature(). The last
    // entry should not be included, because it does not start with "openid.".
    $response = array(
      'openid.foo' => 'abc1',
      'openid.bar' => 'abc2',
      'openid.baz' => 'abc3',
      'foobar.foo' => 'abc4',
    );
595
    $association = new stdClass();
596
    $association->mac_key = "1234567890abcdefghij\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9";
597
    $this->assertEqual(_openid_signature($association, $response, array('foo', 'bar')), 'QnKZQzSFstT+GNiJDFOptdcZjrc=', t('Expected signature calculated.'));
598
  }
599 600 601 602 603 604 605 606 607

  /**
   * Test _openid_is_xri().
   */
  function testOpenidXRITest() {
    // Test that the XRI test is according to OpenID Authentication 2.0,
    // section 7.2. If the user-supplied string starts with xri:// it should be
    // stripped and the resulting string should be treated as an XRI when it
    // starts with "=", "@", "+", "$", "!" or "(".
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
    $this->assertTrue(_openid_is_xri('xri://=foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme.'));
    $this->assertTrue(_openid_is_xri('xri://@foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme.'));
    $this->assertTrue(_openid_is_xri('xri://+foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme.'));
    $this->assertTrue(_openid_is_xri('xri://$foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme.'));
    $this->assertTrue(_openid_is_xri('xri://!foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme..'));
    $this->assertTrue(_openid_is_xri('xri://(foo'), t('_openid_is_xri() returned expected result for an xri identifier with xri scheme..'));

    $this->assertTrue(_openid_is_xri('=foo'), t('_openid_is_xri() returned expected result for an xri identifier.'));
    $this->assertTrue(_openid_is_xri('@foo'), t('_openid_is_xri() returned expected result for an xri identifier.'));
    $this->assertTrue(_openid_is_xri('+foo'), t('_openid_is_xri() returned expected result for an xri identifier.'));
    $this->assertTrue(_openid_is_xri('$foo'), t('_openid_is_xri() returned expected result for an xri identifier.'));
    $this->assertTrue(_openid_is_xri('!foo'), t('_openid_is_xri() returned expected result for an xri identifier.'));
    $this->assertTrue(_openid_is_xri('(foo'), t('_openid_is_xri() returned expected result for an xri identifier.'));

    $this->assertFalse(_openid_is_xri('foo'), t('_openid_is_xri() returned expected result for an http URL.'));
    $this->assertFalse(_openid_is_xri('xri://foo'), t('_openid_is_xri() returned expected result for an http URL.'));
    $this->assertFalse(_openid_is_xri('http://foo/'), t('_openid_is_xri() returned expected result for an http URL.'));
    $this->assertFalse(_openid_is_xri('http://example.com/'), t('_openid_is_xri() returned expected result for an http URL.'));
    $this->assertFalse(_openid_is_xri('user@example.com/'), t('_openid_is_xri() returned expected result for an http URL.'));
    $this->assertFalse(_openid_is_xri('http://user@example.com/'), t('_openid_is_xri() returned expected result for an http URL.'));
628
  }
629 630

  /**
631
   * Test openid_normalize().
632 633 634 635 636
   */
  function testOpenidNormalize() {
    // Test that the normalization is according to OpenID Authentication 2.0,
    // section 7.2 and 11.5.2.

637 638
    $this->assertEqual(openid_normalize('$foo'), '$foo', t('openid_normalize() correctly normalized an XRI.'));
    $this->assertEqual(openid_normalize('xri://$foo'), '$foo', t('openid_normalize() correctly normalized an XRI with an xri:// scheme.'));
639

640 641 642
    $this->assertEqual(openid_normalize('example.com/'), 'http://example.com/', t('openid_normalize() correctly normalized a URL with a missing scheme.'));
    $this->assertEqual(openid_normalize('example.com'), 'http://example.com/', t('openid_normalize() correctly normalized a URL with a missing scheme and empty path.'));
    $this->assertEqual(openid_normalize('http://example.com'), 'http://example.com/', t('openid_normalize() correctly normalized a URL with an empty path.'));
643

644
    $this->assertEqual(openid_normalize('http://example.com/path'), 'http://example.com/path', t('openid_normalize() correctly normalized a URL with a path.'));
645

646
    $this->assertEqual(openid_normalize('http://example.com/path#fragment'), 'http://example.com/path', t('openid_normalize() correctly normalized a URL with a fragment.'));
647
  }
648
}