tags:

views:

286

answers:

2

I'm trying to get a check_authentication response working, but so far, all consumers reject it and say that my server denied check_authentication.

This is the GET and POST data that my server file receives:

$_GET:
Array
(
    [mode] => profile
    [username] => hachque
    [domain] => roket-enterprises.com
)
$_POST:
Array
(
    [openid_assoc_handle] => {HMAC-SHA1}{4b00d7b2}{vo1FEQ==}
    [openid_identity] => http://www.roket-enterprises.com/openaccount/openid:hachque
    [openid_mode] => check_authentication
    [openid_response_nonce] => 2009-11-16T04:40:18Zrrz8R4
    [openid_return_to] => http://openiddirectory.com:80/openidauth/id/c/finish_auth.php?nonce=adCevd6T
    [openid_sig] => SgFE5iT9IGd5EftkrZ72mgCHiLk=
    [openid_signed] => assoc_handle,identity,mode,response_nonce,return_to,signed,sreg.email,sreg.fullname,sreg.nickname
    [openid_sreg_email] => [email protected]
    [openid_sreg_fullname] => James Rhodes
    [openid_sreg_nickname] => jrhodes
)

This is the header reponse that I am outputting (contains POST data as it was explained to me on IRC that sending the key-values as headers shouldn't be done to the consumer server EDIT: Come to think of it, it doesn't make much sense RESPONDING with POST data. Maybe some here can explain the whole process of check_authentication clearly).

  Content-Type: text/plain;
  Content-Length: 675;
  openid.mode=id_res&openid.assoc_handle=%7BHMAC-SHA1%7D%7B4b00d7b2%7D%7Bvo1FEQ%3D%3D%7D&openid.identity=http%3A%2F%2Fwww.roket-enterprises.com%2Fopenaccount%2Fopenid%3Ahachque&openid.response_nonce=2009-11-16T04%3A40%3A18Zrrz8R4&openid.return_to=http%3A%2F%2Fopeniddirectory.com%3A80%2Fopenidauth%2Fid%2Fc%2Ffinish_auth.php%3Fnonce%3DadCevd6T&openid.signed=assoc_handle%2Cidentity%2Cmode%2Cresponse_nonce%2Creturn_to%2Csigned%2Csreg.email%2Csreg.fullname%2Csreg.nickname&openid.sreg_email=jrhodes%40roket-enterprises.com&openid.sreg_fullname=James+Rhodes&openid.sreg_nickname=jrhodes&openid.sig=MGVhMmQ1Mzg4ZWFlMWY1OWVlYjlmZmY0Njc3OTc5YWIzMjM3NGFjMQ%3D%3D&openid.is_valid=true;


This is the PHP code that my file is using to handle check_authentication (remember that PHP turns all . characters into _ for $_GET and $_POST variables since they aren't valid character in PHP array keys):

  // Retrieve the OpenID information from the $_REQUEST data
  // I'm not sure whether it's possible that this data might
  // come in on the $_GET parameter instead of $_POST, so that's
  // what it uses $_REQUEST.

  $assoc_handle = $_REQUEST['openid_assoc_handle'];
  $sig = $_REQUEST['openid_sig'];
  $signed = $_REQUEST['openid_signed'];

  // The method for returning data is via the headers outputted
  // by the webserver.  Create an array that stores the headers
  // to be returned.

  $keys = array(
   'openid.mode' => 'id_res',
   'openid.assoc_handle' => $_REQUEST['openid_assoc_handle'],
   'openid.identity' => $_REQUEST['openid_identity'],
   'openid.response_nonce' => $_REQUEST['openid_response_nonce'],
   'openid.return_to' => $_REQUEST['openid_return_to'],
   'openid.signed' => $_REQUEST['openid_signed'],
   'openid.sreg_email' => $_REQUEST['openid_sreg_email'],
   'openid.sreg_fullname' => $_REQUEST['openid_sreg_fullname'],
   'openid.sreg_nickname' => $_REQUEST['openid_sreg_nickname']
   //'openid_mode' => 'id_res'
  );

  // The server may request that we invalidate the user's session
  // via $_REQUEST['openid_invalidate_handle'].  In this case we
  // will clear the session data (you may need to change this
  // depending on how you implement the session).  After doing so
  // we continue and tell the server we did via a variable

  if (strlen($_REQUEST['openid_invalidate_handle']) > 0)
  {
   // Reset the session
   session_unset();
   session_name('openid_server');
   session_start();

   // Set the header we need to return
   $keys['openid.invalidate_handle'] = $_REQUEST['openid_invalidate_handle'];
  }

  // We need to validate the signature now.  This constructs a token_contents
  // for signing the data.  The signing key is returned as openid.sig
  // and is generated with base64(HMAC(secret(assoc_handle), token_contents)

  $token_contents = '';
  foreach (explode(',', $signed) as $param) {
   $post = preg_replace('/\./', '_', $param);
   $token_contents .= sprintf("%s:%s\n", $param, $_REQUEST['openid_' . $post]);
  }

  // Generate our openid.sig and add it to the list of keys to
  // return.

  $keys['openid.sig'] = base64_encode(hash_hmac('sha1',$token_contents,$assoc_handle));

  // Add the data that we are sharing (via SReg) to the headers.
  // For now this is fixed data (see action_authorization.php).
  //$keys["sreg.fullname"] = 'James Rhodes';
  //$keys["sreg.nickname"] = 'jrhodes';
  //$keys["sreg.email"] = '[email protected]';

  // Just accept the request for now..
  // phpMyID does some kind of secret-shared-key thing
  // here to determine whether it is valid.  I'm not
  // quite sure how that process works yet, so we are just
  // going to say go ahead.
  $keys["openid.is_valid"] = "true";

  // We need to format the $keys array into POST format
  $keys_post = "";
  $keys_post_first = true;
  foreach ($keys as $name => $value)
  {
   if ($keys_post_first)
    $keys_post_first = false;
   else
    $keys_post .= "&";
   $keys_post .= urlencode($name) . "=" . urlencode($value);
  }

  // Now output the POST data
  header('Content-Type: application/x-www-form-urlencoded');
  header('Content-Length: ' . strlen($keys_post));
  header($keys_post);

Can anyone help me with my problem? I've been trying to get this working for months and I can't get a straight answer on how this stage of OpenID authentication is meant to work.

A: 

First of all, although PHP transforms periods to underscores in parameter names, be sure you're sending periods and not underscores.

Secondly, your check_authentication response should only have three parameters, but you have six. Check the spec and fix up your response and see if that helps.

Andrew Arnott
I checked the phpMyID code and it appears to add the SReg variables to the check_authentication response. I'll remove them and try again though. I checked with Firefox's Live HTTP Headers and I am sending periods in the headers.
Hach-Que
Besides the extra sreg parameters, you have extra openid.mode and openid_mode parameters (neither should be present). And probably most importantly, you're *missing* the `ns` parameter.
Andrew Arnott
A: 

Andrew Arnott,you're wrong! documentation from openid.net:

11.4.2.1. Request Parameters

openid.mode Value: "check_authentication"

Exact copies of all fields from the authentication response, except for "openid.mode".

may be more than three fields!

Dont confuse people. "authentication response" is other response. Response on "check_authentication", should be 3 fields, like is_valid
dynback.com
I now only haveopenid.modeis_validyet it still says that the server has denied check_authentication.
Hach-Que