$30 off During Our Annual Pro Sale. View Details »

Building Persona: federated and privacy-sensiti...

Building Persona: federated and privacy-sensitive identity for the Web (Open Source Days 2013)

This talk explores the challenges of the existing Web identity solutions and introduce the choices that were made during the development of Persona (formerly BrowserID), a new Open Source federated identity solution from Mozilla, designed and built to respect user privacy.

Francois Marier

March 10, 2013
Tweet

More Decks by Francois Marier

Other Decks in Programming

Transcript

  1. François Marier – @fmarier B u i l d i

    n g P e r s o n a federated & privacy-sensitive identity for the web
  2. bcrypt per-user salt site secret password & lockout policies secure

    recovery 2013 2013 password password guidelines guidelines
  3. My name is François Marier and my email is too

    long to fit on one line. private
  4. My name is François Marier and my email is too

    long to fit on one line. public
  5. js

  6. navigator.id.watch({ loggedInEmail: “[email protected]”, onlogin: function (assertion) { $.post('/login', {assertion: assertion},

    function (data) { // do something } ); }, onlogout: function () { window.location = '/logout'; } });
  7. navigator.id.watch({ loggedInUser: “[email protected]”, onlogin: function (assertion) { $.post('/login', {assertion: assertion},

    function (data) { // do something } ); }, onlogout: function () { window.location = '/logout'; } });
  8. navigator.id.watch({ loggedInUser: null, onlogin: function (assertion) { $.post('/login', {assertion: assertion},

    function (data) { // do something } ); }, onlogout: function () { window.location = '/logout'; } });
  9. navigator.id.watch({ loggedInUser: null, onlogin: function (assertion) { $.post('/login', {assertion: assertion},

    function (data) { // do something } ); }, onlogout: function () { window.location = '/logout'; } });
  10. navigator.id.watch({ loggedInUser: null, onlogin: function (assertion) { $.post('/login', {assertion: assertion},

    function (data) { window.location = '/'; } ); }, onlogout: function () { window.location = '/logout'; } });
  11. navigator.id.watch({ loggedInUser: null, onlogin: function (assertion) { $.post('/login', {assertion: assertion},

    function (data) { window.location = '/'; } ); }, onlogout: function () { window.location = '/logout'; } });
  12. navigator.id.watch({ loggedInUser: null, onlogin: function (assertion) { $.post('/login', {assertion: assertion},

    function (data) { window.location = '/home'; } ); }, onlogout: function () { window.location = '/logout'; } });
  13. navigator.id.watch({ loggedInUser: null, onlogin: function (assertion) { $.post('/login', {assertion: assertion},

    function (data) { window.location = '/home'; } ); }, onlogout: function () { window.location = '/logout'; } });
  14. 1. load javascript library 2. setup login & logout callbacks

    3. add login and logout buttons 4. verify proof of ownership
  15. <?php if (!empty($_POST)) { $result = verify_assertion($_POST['assertion']); if ($result->status ===

    'okay') { print_header(); echo "<p>Logged in as: " . $result->email . "</p>"; echo '<p><a href="javascript:do_logout()">Logout</a></p>'; print_backLink(); print_footer($result->email); } else { print_header(); echo "<p>Error: " . $result->reason . "</p>"; print_backLink(); print_footer(); } } elseif (!empty($_GET['logout'])) { print_header(); echo "<p>You have logged out.</p>"; print_backLink(); print_footer(); } else { print_header(); echo "<p><a href=\"javascript:do_login()\">Login</a></p>"; print_footer(); } function print_header() { echo <<<EOF <!DOCTYPE html><html><head><meta charset="utf-8"></head> <body> <form id="login-form" method="POST"> <input id="assertion-field" type="hidden" name="assertion" value=""> </form> EOF; } function print_backLink() { echo "<p><a href=\"persona.php\">Back to login page</a></p>"; } function print_footer($email = 'null') { if ($email !== 'null') { $email = "'$email'"; } echo <<<EOF <script src="http://127.0.0.1:10002/include.orig.js"></script> <script> function do_login() { navigator.id.request(); } function do_logout() { navigator.id.logout(); } navigator.id.watch({ loggedInUser: $email, onlogin: function (assertion) { alert("onlogin: $email"); var assertion_field = document.getElementById("assertion-field"); assertion_field.value = assertion; var login_form = document.getElementById("login-form"); login_form.submit(); }, onlogout: function () { alert("onlogout: $email"); window.location = '?logout=1'; } }); </script></body></html> EOF; } function verify_assertion($assertion) { $audience = ($_SERVER['HTTPS'] === 'on' ? 'https://' : 'http://') . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']; $postdata = 'assertion=' . urlencode($assertion) . '&audience=' . urlencode($audience); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "https://verifier.login.persona.org/verify"); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); $json = curl_exec($ch); curl_close($ch); $res = json_decode($json); $res->status = 'okay'; $res->email = '[email protected]'; return $res; } ?>
  16. To learn more about Persona: https://login.persona.org/ http://identity.mozilla.com/ https://developer.mozilla.org/docs/Persona/Why_Persona https://developer.mozilla.org/docs/Persona/Quick_Setup https://github.com/mozilla/browserid-cookbook

    https://developer.mozilla.org/docs/Persona/Libraries_and_plugins http://123done.org/ https://wiki.mozilla.org/Identity#Get_Involved @fmarier http://fmarier.org
  17. identity provider API https://eyedee.me/.well-known/browserid: { "public-key": { "algorithm":"RS", "n":"8606...", "e":"65537"

    }, "authentication": "/browserid/sign_in.html", "provisioning": "/browserid/provision.html" }
  18. identity provider API 1. check for your /.well-known/browserid 2. try

    the provisioning endpoint 3. show the authentication page 4. call the provisioning endpoint again
  19. identity provider API 1. check for your /.well-known/browserid 2. try

    the provisioning endpoint 3. show the authentication page 4. call the provisioning endpoint again
  20. identity provider API 1. check for your /.well-known/browserid 2. try

    the provisioning endpoint 3. show the authentication page 4. call the provisioning endpoint again
  21. identity provider API 1. check for your /.well-known/browserid 2. try

    the provisioning endpoint 3. show the authentication page 4. call the provisioning endpoint again
  22. © 2013 François Marier <[email protected]> This work is licensed under

    a Creative Commons Attribution-ShareAlike 3.0 New Zealand License. Top 500 passwords: http://xato.net/passwords/more-top-worst-passwords/ Parchment: https://secure.flickr.com/photos/27613359@N03/6750396225/ Elephant in room: https://secure.flickr.com/photos/bitboy/246805948/ Cookie on tray: https://secure.flickr.com/photos/jamisonjudd/4810986199/ Uncle Sam: https://secure.flickr.com/photos/donkeyhotey/5666065982/ Danish passport: https://en.wikipedia.org/wiki/File:DK_Passport_Cover.jpg Restaurant dinner: https://secure.flickr.com/photos/yourdon/3977084094/ Photo credits: