index.phps 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. <?php
  2. /**
  3. * Copyright (c) 2014 Yubico AB
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are
  8. * met:
  9. *
  10. * * Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. *
  13. * * Redistributions in binary form must reproduce the above
  14. * copyright notice, this list of conditions and the following
  15. * disclaimer in the documentation and/or other materials provided
  16. * with the distribution.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /**
  31. * This is a simple example using PDO and a sqlite database for storing
  32. * registrations. It supports multiple registrations associated with each user.
  33. */
  34. require_once('../../src/u2flib_server/U2F.php');
  35. $dbfile = '/var/tmp/u2f-pdo.sqlite';
  36. $pdo = new PDO("sqlite:$dbfile");
  37. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  38. $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
  39. $pdo->exec("create table if not exists users (id integer primary key, name varchar(255))");
  40. $pdo->exec("create table if not exists registrations (id integer primary key, user_id integer, keyHandle varchar(255), publicKey varchar(255), certificate text, counter integer)");
  41. $scheme = isset($_SERVER['HTTPS']) ? "https://" : "http://";
  42. $u2f = new u2flib_server\U2F($scheme . $_SERVER['HTTP_HOST']);
  43. session_start();
  44. function createAndGetUser($name) {
  45. global $pdo;
  46. $sel = $pdo->prepare("select * from users where name = ?");
  47. $sel->execute(array($name));
  48. $user = $sel->fetch();
  49. if(!$user) {
  50. $ins = $pdo->prepare("insert into users (name) values(?)");
  51. $ins->execute(array($name));
  52. $sel->execute(array($name));
  53. $user = $sel->fetch();
  54. }
  55. return $user;
  56. }
  57. function getRegs($user_id) {
  58. global $pdo;
  59. $sel = $pdo->prepare("select * from registrations where user_id = ?");
  60. $sel->execute(array($user_id));
  61. return $sel->fetchAll();
  62. }
  63. function addReg($user_id, $reg) {
  64. global $pdo;
  65. $ins = $pdo->prepare("insert into registrations (user_id, keyHandle, publicKey, certificate, counter) values (?, ?, ?, ?, ?)");
  66. $ins->execute(array($user_id, $reg->keyHandle, $reg->publicKey, $reg->certificate, $reg->counter));
  67. }
  68. function updateReg($reg) {
  69. global $pdo;
  70. $upd = $pdo->prepare("update registrations set counter = ? where id = ?");
  71. $upd->execute(array($reg->counter, $reg->id));
  72. }
  73. ?>
  74. <html>
  75. <head>
  76. <title>PHP U2F example</title>
  77. <script src="../assets/u2f-api.js"></script>
  78. <script>
  79. <?php
  80. if($_SERVER['REQUEST_METHOD'] === 'POST') {
  81. if(!$_POST['username']) {
  82. echo "alert('no username provided!');";
  83. } else if(!isset($_POST['action']) && !isset($_POST['register2']) && !isset($_POST['authenticate2'])) {
  84. echo "alert('no action provided!');";
  85. } else {
  86. $user = createAndGetUser($_POST['username']);
  87. if(isset($_POST['action'])) {
  88. switch($_POST['action']):
  89. case 'register':
  90. try {
  91. $data = $u2f->getRegisterData(getRegs($user->id));
  92. list($req,$sigs) = $data;
  93. $_SESSION['regReq'] = json_encode($req);
  94. echo "var req = " . json_encode($req) . ";";
  95. echo "var sigs = " . json_encode($sigs) . ";";
  96. echo "var username = '" . $user->name . "';";
  97. ?>
  98. setTimeout(function() {
  99. console.log("Register: ", req);
  100. u2f.register([req], sigs, function(data) {
  101. var form = document.getElementById('form');
  102. var reg = document.getElementById('register2');
  103. var user = document.getElementById('username');
  104. console.log("Register callback", data);
  105. if(data.errorCode && errorCode != 0) {
  106. alert("registration failed with errror: " + data.errorCode);
  107. return;
  108. }
  109. reg.value = JSON.stringify(data);
  110. user.value = username;
  111. form.submit();
  112. });
  113. }, 1000);
  114. <?php
  115. } catch( Exception $e ) {
  116. echo "alert('error: " . $e->getMessage() . "');";
  117. }
  118. break;
  119. case 'authenticate':
  120. try {
  121. $reqs = json_encode($u2f->getAuthenticateData(getRegs($user->id)));
  122. $_SESSION['authReq'] = $reqs;
  123. echo "var req = $reqs;";
  124. echo "var username = '" . $user->name . "';";
  125. ?>
  126. setTimeout(function() {
  127. console.log("sign: ", req);
  128. u2f.sign(req, function(data) {
  129. var form = document.getElementById('form');
  130. var auth = document.getElementById('authenticate2');
  131. var user = document.getElementById('username');
  132. console.log("Authenticate callback", data);
  133. auth.value=JSON.stringify(data);
  134. user.value = username;
  135. form.submit();
  136. });
  137. }, 1000);
  138. <?php
  139. } catch( Exception $e ) {
  140. echo "alert('error: " . $e->getMessage() . "');";
  141. }
  142. break;
  143. endswitch;
  144. } else if($_POST['register2']) {
  145. try {
  146. $reg = $u2f->doRegister(json_decode($_SESSION['regReq']), json_decode($_POST['register2']));
  147. addReg($user->id, $reg);
  148. } catch( Exception $e ) {
  149. echo "alert('error: " . $e->getMessage() . "');";
  150. } finally {
  151. $_SESSION['regReq'] = null;
  152. }
  153. } else if($_POST['authenticate2']) {
  154. try {
  155. $reg = $u2f->doAuthenticate(json_decode($_SESSION['authReq']), getRegs($user->id), json_decode($_POST['authenticate2']));
  156. updateReg($reg);
  157. echo "alert('success: " . $reg->counter . "');";
  158. } catch( Exception $e ) {
  159. echo "alert('error: " . $e->getMessage() . "');";
  160. } finally {
  161. $_SESSION['authReq'] = null;
  162. }
  163. }
  164. }
  165. }
  166. ?>
  167. </script>
  168. </head>
  169. <body>
  170. <form method="POST" id="form">
  171. username: <input name="username" id="username"/><br/>
  172. register: <input value="register" name="action" type="radio"/><br/>
  173. authenticate: <input value="authenticate" name="action" type="radio"/><br/>
  174. <input type="hidden" name="register2" id="register2"/>
  175. <input type="hidden" name="authenticate2" id="authenticate2"/>
  176. <button type="submit">Submit!</button>
  177. </form>
  178. </body>
  179. </html>