-
-
Save gdb/cd4504c852102d4fd92c to your computer and use it in GitHub Desktop.
User authentication using Stellar: proof-of-concept
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Authentication through Stellar proof-of-concept</title> | |
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css" rel="stylesheet"> | |
<style> | |
body { | |
padding-top: 50px; | |
} | |
.starter-template { | |
padding: 40px 15px; | |
text-align: center; | |
} | |
</style> | |
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> | |
<script> | |
live = true; | |
if (live) { | |
var username = 'gdb-auth-notifier'; | |
var account_id = 'g3S2S81x97WN4ZDdmYsWFt5pLzfwG3xqv7'; | |
var url = 'ws://live.stellar.org:9001' | |
} else { | |
// Generate a test account using the tutorial at https://www.stellar.org/blog/introducing-stellar/ | |
var username = '(no usernames in testmode)'; | |
var account_id = 'gNL4zATHB95QPzM914hsnbXhXJxKc9hECR'; | |
var url = 'ws://test.stellar.org:9001' | |
} | |
// Small random number. Normally this would be generated by the server | |
// to match with your session. | |
var microstellar_amount = Math.round(Math.random() * 1000); | |
function lookupUsername(account, onComplete) { | |
$.get('https://api.stellar.org/reverseFederation', { | |
destination_address: account, | |
domain: 'stellar.org', | |
type: 'reverse_federation' | |
}, function(data) { | |
console.log("Federation server responded with", data); | |
// Lifted from https://www.stellar.org/wp-content/themes/stellar/angular/explorer/scripts/services/reverseFederation.js?ver=0.0 | |
if ("object" === typeof data && | |
"object" === typeof data.federation_json && | |
data.federation_json.type === "federation_record" && | |
data.federation_json.destination_address === account && | |
data.federation_json.domain === 'stellar.org') { | |
var username = data.federation_json.destination; | |
onComplete(username); | |
} else { | |
onComplete(null); | |
} | |
}); | |
} | |
function promptLogin(destination) { | |
lookupUsername(destination, function(username) { | |
if (username) { | |
var text = "Authentication request received. Log in as " + username + " (" + destination + ")?"; | |
} else { | |
var text = "Authentication request received. Log in as " + destination + "?"; | |
} | |
var proceed = confirm(text); | |
if (proceed) { | |
$('#auth').text('You have successfully authenticated as ' + username + '.') | |
} | |
}) | |
} | |
var ws = new WebSocket(url); | |
ws.onopen = function() { | |
console.log("Connected to stellard at " + url); | |
var msg = JSON.stringify({ | |
command: 'subscribe', | |
accounts: [account_id] | |
}); | |
ws.send(msg); | |
}; | |
ws.onerror = function(err) { | |
console.error(err); | |
} | |
ws.onmessage = function(result) { | |
var msg = JSON.parse(result.data); | |
console.log(msg); | |
if( | |
msg.engine_result_code === 0 && | |
msg.type === 'transaction' && | |
msg.transaction.Destination === account_id | |
) { | |
if (msg.transaction.Amount == microstellar_amount) { | |
promptLogin(msg.transaction.Account); | |
} else { | |
console.log("Saw someone else's payment for", msg.transaction.Amount, "microstellars"); | |
} | |
} | |
} | |
</script> | |
</head> | |
<body> | |
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation"> | |
<div class="container"> | |
<div class="navbar-header"> | |
<span class="navbar-brand"> | |
User authentication via Stellar (<a href="https://gist.github.com/gdb/cd4504c852102d4fd92c">Github</a>) | |
</span> | |
</div> | |
</div> | |
</div> | |
<div class="container"> | |
<div class="starter-template"> | |
<h1>User authentication using Stellar</h1> | |
<p class="lead"> This is a proof-of-concept of using a Stellar | |
account for user authentication. </p> | |
<h2> How it works </h2> | |
<p> The service asks the user to send it a transaction for a | |
unique amount. Once the transaction has been received, the service | |
knows the user's address. In order to prevent an attacker from | |
just guessing the unique amount and submitting their own | |
transaction, the service prompts the user to confirm their | |
address. </p> | |
<h2> Known issues </h2> | |
<p> This implementation is vulnerable to a session fixation | |
attack, similar to the one that | |
affected <a href="http://hueniverse.com/2009/04/23/explaining-the-oauth-session-fixation-attack/">OAuth | |
v1</a>. The most plausible workaround I've thought of is that | |
payments need to somehow embed the metadata {gregbrockman.com, | |
session ID} (either natively by extending the Stellar protocol, or | |
as a layer on top of it) -- that way the user <i>can</i> always | |
verify which site they're authenticating to. I feel like there's | |
probably a better solution though, and would be curious to | |
<a href="https://twitter.com/thegdb">hear</a> if you have any | |
ideas. </p> | |
<hr /> | |
<h2> Authenticate </h2> | |
<div id="auth"> | |
<p> Leaving this window open, send <b id="amount">...</b> STR to <a id="destination" href="#">...</a> (<span id="account_id">...</span>) to authenticate. </p> | |
</div> | |
<script> | |
$('#amount').text(microstellar_amount/1000000); | |
var destination = $('#destination'); | |
destination.text(username); | |
destination.attr('href', 'https://www.stellar.org/viewer/#/' + username); | |
$('#account_id').text(account_id); | |
</script> | |
</div> | |
</div><!-- /.container --> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment