Date post: | 08-May-2015 |
Category: |
Technology |
Upload: | francois-marier |
View: | 1,578 times |
Download: | 3 times |
François Marier – @fmarier
B u i l d i n g P e r s o n afederated & privacy-sensitive identity for the web
solving thepassword problem
on the web
Username:francois
Password:****************
X
Sign in
security
bcrypt
per-user salt
site secret
password & lockout policies
secure recovery
bcrypt
per-user salt
site secret
password & lockout policies
secure recovery
bcrypt
per-user salt
site secret
password & lockout policies
secure recovery
bcrypt
per-user salt
site secret
password & lockout policies
secure recovery
bcrypt
per-user salt
site secret
password & lockout policies
secure recovery
bcrypt
per-user salt
site secret
password & lockout policies
secure recovery
20132013
passwordpassword
guidelines
guidelines
conversionrate
# hits
signup
# hits
signup signup_complete
# hits
signup signup_complete
l o s t cust-omers
existing solutions
client certificates
centralized authorities
so...
storing passwords is hard
so...
storing passwords is hard
no suitable alternatives
decentralized
privacy-sensitivedecentralized
privacy-sensitive
simple
decentralized
privacy-sensitive
simpleopen source
decentralized
in your browser
how does it work?
getting a proof of email ownership
authenticate?
authenticate?
public key
authenticate?
public key
signed public key
you have a signed statement from yourprovider that you own your email address
logging into a 3rd party site
Valid for: 2 minutes
linux.conf.au
assertion
Valid for: 2 minutes
linux.conf.au
check audience
assertion
Valid for: 2 minutes
linux.conf.au
check audiencecheck expiry
assertion
Valid for: 2 minutes
linux.conf.au
check audiencecheck expirycheck signature
assertion
assertion
Valid for: 2 minutes
linux.conf.au
public key
assertion
Valid for: 2 minutes
linux.conf.au
assertion
session cookie
achievingthat vision
email providers
browser vendors
email providers
fallback identity provider
persona.org account
support for all email providers
browser vendors
navigator.id.*
js
support for allmodern browsers
>= 8
support for allmodern browsers
>= 8
LIFD
LocallyIsolatedFeatureDomain
wanted: trusted coderunning in the browser
login.persona.org
localStorage
localStorage.setItem("key", serializedKey);
var serializedKey = localStorage.getItem("key");
storage tied tologin.persona.org
window.postMessage()
https://login.persona.org
postMessage
localStorage
https://login.persona.org
localStorage
questions?
postMessage
live demo
using it on your site
<script src=”https://login.persona.org/include.js”></script></body></html>
navigator.id.watch({ loggedInEmail: “[email protected]”, onlogin: function (assertion) { $.post('/login', {assertion: assertion}, function (data) { // do something } ); }, onlogout: function () { window.location = '/logout'; }});
navigator.id.watch({ loggedInUser: “[email protected]”, onlogin: function (assertion) { $.post('/login', {assertion: assertion}, function (data) { // do something } ); }, onlogout: function () { window.location = '/logout'; }});
navigator.id.watch({ loggedInUser: null, onlogin: function (assertion) { $.post('/login', {assertion: assertion}, function (data) { // do something } ); }, onlogout: function () { window.location = '/logout'; }});
navigator.id.watch({ loggedInUser: null, onlogin: function (assertion) { $.post('/login', {assertion: assertion}, function (data) { // do something } ); }, onlogout: function () { window.location = '/logout'; }});
navigator.id.watch({ loggedInUser: null, onlogin: function (assertion) { $.post('/login', {assertion: assertion}, function (data) { window.location = '/'; } ); }, onlogout: function () { window.location = '/logout'; }});
navigator.id.request()
navigator.id.watch({ loggedInUser: null, onlogin: function (assertion) { $.post('/login', {assertion: assertion}, function (data) { window.location = '/'; } ); }, onlogout: function () { window.location = '/logout'; }});
navigator.id.watch({ loggedInUser: null, onlogin: function (assertion) { $.post('/login', {assertion: assertion}, function (data) { window.location = '/home'; } ); }, onlogout: function () { window.location = '/logout'; }});
def verify_assertion(assertion):
page = requests.post( 'https://verifier.login.persona.org/verify', Data={ "assertion": assertion, "audience": 'http://123done.org'})
data = page.json return data.status == 'okay'
def verify_assertion(assertion):
page = requests.post( 'https://verifier.login.persona.org/verify', Data={ "assertion": assertion, "audience": 'http://123done.org'})
data = page.json return data.status == 'okay'
{ status: “okay”,
audience: “http://123done.org”,
expires: 1344849682560,
email: “[email protected]”,
issuer: “login.persona.org”}
{ status: “failed”,
reason: “assertion has expired”}
navigator.id.logout()
navigator.id.watch({ loggedInUser: null, onlogin: function (assertion) { $.post('/login', {assertion: assertion}, function (data) { window.location = '/home'; } ); }, onlogout: function () { window.location = '/logout'; }});
1. load javascript library
1. load javascript library
2. setup login & logout callbacks
1. load javascript library
2. setup login & logout callbacks
3. add login and logout buttons
1. load javascript library
2. setup login & logout callbacks
3. add login and logout buttons
4. verify proof of ownership
<?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;}?>
wanna help ussolve the
password problem?
add Persona toyour project/site
tell us about yourexperience
email one siteasking for it
add Persona toyour project/site
tell us about yourexperience
email one siteasking for it
add Persona toyour project/site
tell us about yourexperience
email one siteasking for it
grab some stickers!
To learn more about Persona:
https://login.persona.org/http://identity.mozilla.com/
https://developer.mozilla.org/docs/Persona/Why_Personahttps://developer.mozilla.org/docs/Persona/Quick_Setup
https://github.com/mozilla/browserid-cookbookhttps://developer.mozilla.org/docs/Persona/Libraries_and_plugins
http://123done.org/https://wiki.mozilla.org/Identity#Get_Involved
@fmarier http://fmarier.org
© 2013 François Marier <[email protected]>This work is licensed under aCreative 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/
Photo credits:
Who's using Persona?
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"}
https://eyedee.me/.well-known/browserid:
{ "public-key": { "algorithm":"RS", "n":"8606...", "e":"65537" }, "authentication": "/browserid/sign_in.html", "provisioning": "/browserid/provision.html"}
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"}
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"}
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"}
identity provider API
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
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
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
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