SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

CodeZineニュース

[PHPプロ!] PHPのOpenSSL関数を使って、OpenIDとTypeKey認証を実装するコード

  • このエントリーをはてなブックマークに追加

  • このエントリーをはてなブックマークに追加

Wez Furlong氏による、OpenIDとTypeKey認証を行うための、OpenSSLエクステンションのパッチが公開されています。このパッチを使用すると、PHPのアプリケーションにて、OpenIDとTypeKey認証を簡単に実装できます。

 Wez Furlong氏による、OpenIDとTypeKey認証を行うための、OpenSSLエクステンションのパッチが公開されています。このパッチを使用すると、PHPのアプリケーションにて、OpenIDとTypeKey認証を簡単に実装できます。

 パッチ自体は、このURLからダウンロードできます。Furlong氏のサーバー上でのPHP5にて動作を確認されているという事ですが、PHP4でも動作するだろうと、同氏は述べています。

Associateリクエスト

 Associateリクエストを行い、キーを生成、交換することで、OpenIDサーバーとの関係を構築できます。このリクエストの結果は、同じサーバーを認証する場合の、ユーザー認証に使用できます。このコードは以下のようになります。

<?php
  $assoc = array(); 
  $crypto = array(); 
  $dh = openssl_dh_generate_key(OPENID_P_VALUE, '2'); 
  foreach (openssl_dh_get_params($dh) as $n => $v) { 
    $crypto[$n] = openssl_bignum_to_string($v, 10); 
  } 
  $params = array( 
     'openid.mode' => 'associate', 
     'openid.assoc_type' => 'HMAC-SHA1', 
     'openid.session_type' => 'DH-SHA1', 
     'openid.dh_modulus' => base64_encode( 
                openssl_bignum_to_string(OPENID_P_VALUE)), 
     'openid.dh_gen' => base64_encode( 
                openssl_bignum_to_string('2')), 
     'openid.dh_consumer_public' => base64_encode( 
                openssl_bignum_to_string($crypto['pub_key'])), 
  ); 
  $r = perform_openid_rpc($server, $params); // サーバーと通信する
  if ($r['session_type'] == 'DH-SHA1') { 
    $s_pub = openssl_bignum_from_bin( 
               base64_decode($r['dh_server_public'])); 
    $dh_sec = openssl_dh_compute_key($dh, $s_pub); 
    if ($dh_sec === false) { 
      do { 
        $err = openssl_error_string(); 
        if ($err === false) { 
          break; 
        } 
        echo "$err<br>\n"; 
      } while (true); 
    } 
    $sh_sec = sha1($dh_sec, true); 
    $enc_mac = base64_decode($r['enc_mac_key']); 
    $secret = ''; 
    for ($i = 0; $i < strlen($enc_mac); $i++) { 
      $secret .= chr(ord($enc_mac[$i]) ^ ord($sh_sec[$i])); 
    } 
    $assoc['secret'] = $secret; 
    $assoc['handle']  = $r['assoc_handle']; 
    $assoc['assoc_type'] = $r['assoc_type']; 
    $assoc['expires'] = time() + $r['expires_in']; 
  } else { 
    $assoc = false; 
  } 
?>

 OpenIDサーバーにて認証を行ったら、先ほど$returnURLに指定したURLに、リダイレクトで戻ってきます。

<?php 
    $assoc = $this->associate($args['srv']); 
    $token_contents = ''; 
    /* token_contentsハッシュの名前は、
       接頭辞が付いていないことに注意が必要です */
    foreach (explode(',', $_GET['openid_signed']) as $name) { 
      if ($name == 'return_to') { 
        $token_contents .= "$name:" . $_GET['openid_return_to'] . "\n"; 
      } else { 
        $token_contents .= "$name:" . $_GET["openid_" 
          . str_replace('.', '_', $name)] . "\n"; 
      } 
    } 
    $x = hash_hmac('sha1', $token_contents, $assoc['secret'], true); 
    $hash = base64_encode($x); 
    if ($hash === $_GET['openid_sig']) { 
      // 認証が成功した
      return true; 
    } 
    /* 何らかの理由で認証が失敗した */ 
    $params = array(); 
    $signed = explode(',', $_GET['openid_signed']); 
    $signed = array_merge($signed, array('assoc_handle',
      'sig', 'signed', 'invalidate_handle')); 
    foreach ($signed as $name) { 
      $k = "openid_" . str_replace('.', '_', $name); 
      if (array_key_exists($k, $_GET)) { 
        $params["openid.$name"] = $_GET[$k]; 
      } 
    } 
    $server = $args['srv']; 
    /* 証明書が壊れている。
     * openid.modeをcheck_authentificationにして、認証のチェックを行う
     */ 
    $params['openid.mode'] = 'check_authentication'; 
    $res = perform_openid_rpc($server, $params); 
    if (isset($res['invalidate_handle'])) { 
      if ($res['invalidate_handle'] === $assoc['handle']) { 
        $this->associate($server, true); 
      } 
    } 
    return $res['is_valid'] === 'true'; 
?>

TypeKeyへの対応

 TypeKeyからリダイレクトで戻ってきた際、シグネチャーを検証するスクリプトは以下の通りになります。

<?php 
    $keydata = array(); 
    $regkeys = cache::httpGet(
      'http://www.typekey.com/extras/regkeys.txt', 24*60*60); 
    if ($regkeys === false) { 
       die("urgh"); 
    } 
    foreach (explode(' ', $regkeys) as $pair) { 
      list($k, $v) = explode('=', trim($pair)); 
      $keydata[$k] = $v; 
    } 
    $sig = str_replace(' ', '+', $_GET['sig']); 
    $email = $_GET['email']; 
    $name = $_GET['name']; 
    $nick = $_GET['nick']; 
    $ts = $_GET['ts']; 
    $msg = "$email::$name::$nick::$ts::" . TYPEKEY_TOKEN; 
    if (time() - $ts > 300) { 
      die("possible replay"); 
    } 
    list($r_sig, $s_sig) = explode(':', $sig, 2); 
    $r_sig = base64_decode($r_sig); 
    $s_sig = base64_decode($s_sig); 
    $valid = openssl_dsa_verify(sha1($msg, true), 
                     openssl_bignum_from_bin($r_sig), 
                     openssl_bignum_from_bin($s_sig), 
                     $keydata['p'], $keydata['q'], 
                     $keydata['g'], $keydata['pub_key']); 
?>

 (PHPプロ!

関連リンク

転載元

 PHPプロ!:最新のPHPニュース

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加
この記事の著者

PHPプロ!(PHPプロ!)

PHPプロ!」は、アシアル株式会社が運営するPHP開発者のためのポータル&コミュニティサイトです。同サイトでは、PHP最新ニュースや、困ったときのQ&A掲示板、初心者向けのPHP講座、PHP中級者のためのTIPSメーリングリスト、中・上級者向けの技術ノウハウ満載のPHPプロ!マガジンの提供など、PHP開発...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/1004 2007/02/14 10:57

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング