sinatra-browserid 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +59 -0
- data/example/app.rb +28 -0
- data/example/config.ru +2 -0
- data/example/views/index.erb +21 -0
- data/lib/sinatra/browserid.rb +138 -0
- metadata +86 -0
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
Sinatra plugin that allows authentication against [BrowserID](https://browserid.org/). BrowserID lets you verify the email identity of a user.
|
2
|
+
|
3
|
+
To learn more, see how it works [from a users perspective](https://browserid.org/about) and [from a developers perspective](https://github.com/mozilla/browserid/wiki/How-to-Use-BrowserID-on-Your-Site).
|
4
|
+
|
5
|
+
Note that BrowserID logins are not done from within a form on your site -- you provide a login button, and that will start up the BrowserID login flow (either via a pop-up or an in-browser widget).
|
6
|
+
|
7
|
+
How to get started:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
require 'sinatra/base'
|
11
|
+
require 'sinatra/browserid'
|
12
|
+
|
13
|
+
module MyApp < Sinatra::Base
|
14
|
+
register Sinatra::BrowserID
|
15
|
+
|
16
|
+
set :browserid_login_button, :orange
|
17
|
+
set :sessions, true
|
18
|
+
|
19
|
+
get '/'
|
20
|
+
if authorized?
|
21
|
+
"Welcome, #{authorized_email}"
|
22
|
+
else
|
23
|
+
render_login_button
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
get '/secure'
|
28
|
+
authorize! # require a user be logged in
|
29
|
+
|
30
|
+
email = authorized_email # browserid email
|
31
|
+
...
|
32
|
+
end
|
33
|
+
|
34
|
+
get '/logout'
|
35
|
+
logout!
|
36
|
+
|
37
|
+
redirect '/'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
See the rdoc for more details on the helper functions. For a functioning
|
43
|
+
example app, run <tt>rackup -p $PORT</tt> in the example directory.
|
44
|
+
|
45
|
+
Available sinatra settings:
|
46
|
+
|
47
|
+
* <tt>:browserid_login_button</tt>: set to a color (:orange, :red, :blue,
|
48
|
+
:green, :grey) or an image URL
|
49
|
+
* <tt>:browserid_server</tt>: If you're using an alternate auth provider
|
50
|
+
other than https://browserid.org
|
51
|
+
* <tt>:browserid_login_url</tt>: URL users get redirected to when the
|
52
|
+
<tt>authorize!</tt> helper is called and a user is not logged in
|
53
|
+
|
54
|
+
|
55
|
+
Still TODO:
|
56
|
+
|
57
|
+
* better error handling
|
58
|
+
* local assertion verification (eliminate callback)
|
59
|
+
|
data/example/app.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$: << File.join(File.dirname(__FILE__), "..", "lib")
|
4
|
+
|
5
|
+
require "sinatra/base"
|
6
|
+
require "sinatra/browserid"
|
7
|
+
|
8
|
+
class TestApp < Sinatra::Base
|
9
|
+
register Sinatra::BrowserID
|
10
|
+
|
11
|
+
set :sessions, true
|
12
|
+
|
13
|
+
get '/' do
|
14
|
+
erb :index
|
15
|
+
end
|
16
|
+
|
17
|
+
get '/logout' do
|
18
|
+
logout!
|
19
|
+
|
20
|
+
redirect '/'
|
21
|
+
end
|
22
|
+
|
23
|
+
get '/confidential' do
|
24
|
+
authorize!
|
25
|
+
|
26
|
+
"Hey #{authorized_email}, you're authorized!"
|
27
|
+
end
|
28
|
+
end
|
data/example/config.ru
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
</head>
|
4
|
+
<body>
|
5
|
+
|
6
|
+
<h1>Test App</h1>
|
7
|
+
|
8
|
+
<p>
|
9
|
+
<% if authorized? %>
|
10
|
+
Hello, <%= authorized_email %> <a href="/logout">(logout)</a>
|
11
|
+
<% else %>
|
12
|
+
<%= render_login_button %>
|
13
|
+
<% end %>
|
14
|
+
</p>
|
15
|
+
|
16
|
+
<p>
|
17
|
+
see a <a href="/confidential">page that requires a login</a>.
|
18
|
+
</p>
|
19
|
+
|
20
|
+
</body>
|
21
|
+
</html>
|
@@ -0,0 +1,138 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "net/https"
|
5
|
+
require "sinatra/base"
|
6
|
+
|
7
|
+
# This module provides an interface to verify a users email address
|
8
|
+
# with browserid.org.
|
9
|
+
module Sinatra
|
10
|
+
module BrowserID
|
11
|
+
|
12
|
+
module Helpers
|
13
|
+
# Returns true if the current user has logged in and presented
|
14
|
+
# a valid assertion.
|
15
|
+
def authorized?
|
16
|
+
! session[:browserid_email].nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
# If the current user is not logged in, redirects to a login
|
20
|
+
# page. Override the login page by setting the Sinatra
|
21
|
+
# option <tt>:browserid_login_url</tt>.
|
22
|
+
def authorize!
|
23
|
+
session[:authorize_redirect_url] = request.url
|
24
|
+
login_url = settings.browserid_login_url
|
25
|
+
redirect login_url unless authorized?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Logs out the current user.
|
29
|
+
def logout!
|
30
|
+
session[:browserid_email] = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the BrowserID verified email address, or nil if the
|
34
|
+
# user is not logged in.
|
35
|
+
def authorized_email
|
36
|
+
session[:browserid_email]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns the HTML to render the BrowserID login button.
|
40
|
+
# Optionally takes a URL parameter for where the user should
|
41
|
+
# be redirected to after the assert POST back. You can
|
42
|
+
# customize the button image by setting the Sinatra option
|
43
|
+
# <tt>:browserid_login_button</tt> to a color (:orange,
|
44
|
+
# :red, :blue, :green, :grey) or an actual URL.
|
45
|
+
def render_login_button(redirect_url = nil)
|
46
|
+
case settings.browserid_login_button
|
47
|
+
when :orange, :red, :blue, :green, :grey
|
48
|
+
button_url = "#{settings.browserid_url}/i/sign_in_" \
|
49
|
+
"#{settings.browserid_login_button.to_s}.png"
|
50
|
+
else
|
51
|
+
button_url = settings.browserid_login_button
|
52
|
+
end
|
53
|
+
|
54
|
+
if session[:authorize_redirect_url]
|
55
|
+
redirect_url = session[:authorize_redirect_url]
|
56
|
+
session[:authorize_redirect_url] = nil
|
57
|
+
end
|
58
|
+
redirect_url ||= request.url
|
59
|
+
|
60
|
+
template = ERB.new(Templates::LOGIN_BUTTON)
|
61
|
+
template.result(binding)
|
62
|
+
end
|
63
|
+
end # module Helpers
|
64
|
+
|
65
|
+
def self.registered(app)
|
66
|
+
app.helpers BrowserID::Helpers
|
67
|
+
|
68
|
+
app.set :browserid_url, "https://browserid.org"
|
69
|
+
app.set :browserid_login_button, :red
|
70
|
+
app.set :browserid_login_url, "/_browserid_login"
|
71
|
+
|
72
|
+
app.get '/_browserid_login' do
|
73
|
+
# TODO(petef): render a page that initiates login without
|
74
|
+
# waiting for a user click.
|
75
|
+
render_login_button
|
76
|
+
end
|
77
|
+
|
78
|
+
app.post '/_browserid_assert' do
|
79
|
+
# TODO(petef): do verification locally, without a callback
|
80
|
+
audience = request.host_with_port
|
81
|
+
http = Net::HTTP.new("browserid.org", 443)
|
82
|
+
http.use_ssl = true
|
83
|
+
data = {
|
84
|
+
"assertion" => params[:assertion],
|
85
|
+
"audience" => audience,
|
86
|
+
}
|
87
|
+
data_str = data.collect { |k, v| "#{k}=#{v}" }.join("&")
|
88
|
+
res, body = http.post("/verify", data_str)
|
89
|
+
|
90
|
+
# TODO: check res is a 200
|
91
|
+
verify = JSON.parse(body) || nil
|
92
|
+
if verify.nil?
|
93
|
+
# JSON parsing error
|
94
|
+
return
|
95
|
+
end
|
96
|
+
|
97
|
+
if verify["status"] != "okay"
|
98
|
+
$stderr.puts "status was not OK. #{verify.inspect}"
|
99
|
+
return
|
100
|
+
end
|
101
|
+
|
102
|
+
session[:browserid_email] = verify["email"]
|
103
|
+
session[:browserid_expires] = verify["expires"].to_f / 1000
|
104
|
+
|
105
|
+
redirect params[:redirect] || "/"
|
106
|
+
end
|
107
|
+
end # def self.registered
|
108
|
+
|
109
|
+
module Templates
|
110
|
+
LOGIN_BUTTON = %q{
|
111
|
+
<script src="<%= settings.browserid_url %>/include.js" type="text/javascript"></script>
|
112
|
+
<script type="text/javascript">
|
113
|
+
function _browserid_login() {
|
114
|
+
navigator.id.getVerifiedEmail(function(assertion) {
|
115
|
+
if (assertion) {
|
116
|
+
document.forms._browserid_assert.assertion.value = assertion;
|
117
|
+
document.forms._browserid_assert.submit();
|
118
|
+
} else {
|
119
|
+
// TODO: handle failure case?
|
120
|
+
}
|
121
|
+
});
|
122
|
+
}
|
123
|
+
</script>
|
124
|
+
|
125
|
+
<form name="_browserid_assert" action="/_browserid_assert" method="post">
|
126
|
+
<input type="hidden" name="redirect" value="<%= redirect_url %>">
|
127
|
+
<input type="hidden" name="assertion" value="">
|
128
|
+
</form>
|
129
|
+
|
130
|
+
<a href="#"><img src="<%= button_url %>" id="browserid_login_button" border=0 onClick="_browserid_login()" /></a>
|
131
|
+
}
|
132
|
+
end
|
133
|
+
end # module BrowserID
|
134
|
+
|
135
|
+
register BrowserID
|
136
|
+
end # module Sinatra
|
137
|
+
|
138
|
+
#set :sessions, true
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sinatra-browserid
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 9
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: "0.1"
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Pete Fritchman
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-10-21 00:00:00 -04:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: sinatra
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 19
|
29
|
+
segments:
|
30
|
+
- 1
|
31
|
+
- 1
|
32
|
+
- 0
|
33
|
+
version: 1.1.0
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
description:
|
37
|
+
email:
|
38
|
+
- petef@databits.net
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- README.md
|
47
|
+
- lib/sinatra/browserid.rb
|
48
|
+
- example/app.rb
|
49
|
+
- example/config.ru
|
50
|
+
- example/views/index.erb
|
51
|
+
has_rdoc: true
|
52
|
+
homepage: https://github.com/fetep/sinatra-browserid
|
53
|
+
licenses: []
|
54
|
+
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options:
|
57
|
+
- --inline-source
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
hash: 3
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
version: "0"
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
none: false
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
hash: 3
|
75
|
+
segments:
|
76
|
+
- 0
|
77
|
+
version: "0"
|
78
|
+
requirements: []
|
79
|
+
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 1.3.7
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: Sinatra extension for user authentication with browserid.org
|
85
|
+
test_files: []
|
86
|
+
|