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

Post on 08-May-2015

225 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

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.

Transcript

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

users: reduce number of passwords

users: reduce number of passwords

developers: reduce implementation costs

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

ALTER TABLE userDROP COLUMN password;

existing solutions

client certificates

“social” authentication

“People want a littledating before marriage.”

Eric Vishria – Rockmelt

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?

francois@mozilla.com

<digital signatures 101>

private public

public

My name isFrançois Marierand my email istoo long to fiton one line.

My name isFrançois Marierand my email istoo long to fiton one line.private

My name isFrançois Marierand my email istoo long to fiton one line. public

sign verify

</digital signatures 101>

francois@mozilla.com

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

fmarier@gmail.com

fmarier@gmail.com

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

live demo

using it on your site

no need to take notesthese slides will be online )(

<script src=”https://login.persona.org/include.js”></script></body></html>

navigator.id.watch({ loggedInEmail: “francois@mozilla.com”, onlogin: function (assertion) { $.post('/login', {assertion: assertion}, function (data) { // do something } ); }, onlogout: function () { window.location = '/logout'; }});

navigator.id.watch({ loggedInUser: “francois@mozilla.com”, 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: “francois@mozilla.com”,

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 = 'francois@mozilla.com'; 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

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

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

© 2013 François Marier <francois@mozilla.com>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/

Danish passport: https://en.wikipedia.org/wiki/File:DK_Passport_Cover.jpg

Restaurant dinner: https://secure.flickr.com/photos/yourdon/3977084094/

Photo credits:

top related