sinatra-portier 1.3.0 → 1.5.2
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.
- checksums.yaml +5 -5
- data/README.md +12 -5
- data/example/app.rb +23 -22
- data/example/config.ru +8 -2
- data/lib/sinatra/browserid/helpers.rb +22 -0
- data/lib/sinatra/browserid/template.rb +1 -1
- data/lib/sinatra/browserid.rb +17 -4
- metadata +35 -9
- data/example/views/index.erb +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cbb567b7fdc34ac49a53113b97b08a27b52c2fd1e85552c2ea44eb7cabfc9666
|
4
|
+
data.tar.gz: 3528e61f4a6fdc75ed3d2aee2bb80235a139860ca079b63d6ee3cfac487adbf3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce0b199ca249d27d1cefc7db7c25f6bb5595165d7076843a190c448e61b596fcd2b0e3c362ddaf155ca6f7fb3002a73511b0ba4a8f111a5ffc1f5b1bc7b8e15c
|
7
|
+
data.tar.gz: 5c6e1b3cc2890c87f32bda865530accd31ff97df69c5977d1c1de5009337cda8f38447756da9ca202cfae8d34859c8f9d98a6a606efc4d76120ec5587dedceba
|
data/README.md
CHANGED
@@ -10,7 +10,7 @@ Note that logins are not done from within a form on your site -- you provide a l
|
|
10
10
|
|
11
11
|
## How to get started
|
12
12
|
|
13
|
-
Install the gem **sinatra-portier
|
13
|
+
Install the gem **sinatra-portier**:
|
14
14
|
|
15
15
|
```
|
16
16
|
gem install sinatra-portier
|
@@ -27,7 +27,7 @@ require 'sinatra/browserid'
|
|
27
27
|
register Sinatra::BrowserID
|
28
28
|
|
29
29
|
set :sessions, true
|
30
|
-
# Disabling origin-
|
30
|
+
# Disabling origin-check is needed to make webkit-browsers like Chrome work.
|
31
31
|
# Behind a proxy you will also need to disable :remote_token, regardless for which browser.
|
32
32
|
set :protection, except: [:http_origin]
|
33
33
|
get '/' do
|
@@ -53,12 +53,19 @@ end
|
|
53
53
|
```
|
54
54
|
|
55
55
|
See the rdoc for more details on the helper functions. For a functioning
|
56
|
-
example app,
|
56
|
+
example app, start the app in the example directory:
|
57
|
+
|
58
|
+
```
|
59
|
+
bundle install
|
60
|
+
bundle exec rackup -p PORT
|
61
|
+
|
62
|
+
```
|
57
63
|
|
58
64
|
Available sinatra settings:
|
59
65
|
|
60
66
|
* <tt>:browserid_url</tt>: If you're using an alternate auth provider
|
61
67
|
other than https://broker.portier.io
|
62
68
|
* <tt>:browserid_login_url</tt>: URL users get redirected to when the
|
63
|
-
<tt>authorize
|
64
|
-
* <tt>:browserid_button_class</tt
|
69
|
+
<tt>authorize!(redirect: nil)</tt> helper is called and a user is not logged in. `redirect` is an optional parameter to set the redirect target on the function call instead.
|
70
|
+
* <tt>:browserid_button_class</tt>: Css class of the login button
|
71
|
+
* <tt>:browserid_button_text</tt>: Text of the login button
|
data/example/app.rb
CHANGED
@@ -1,28 +1,29 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
1
|
+
require 'sinatra'
|
2
|
+
require 'sinatra/browserid'
|
3
|
+
|
4
|
+
|
5
|
+
register Sinatra::BrowserID
|
6
|
+
|
7
|
+
set :sessions, true
|
8
|
+
# Disabling origin-check is needed to make webkit-browsers like Chrome work.
|
9
|
+
# Behind a proxy you will also need to disable :remote_token, regardless for which browser.
|
10
|
+
set :protection, except: [:http_origin]
|
11
|
+
get '/' do
|
12
|
+
if authorized?
|
13
|
+
"Welcome, #{authorized_email}"
|
14
|
+
else
|
15
|
+
render_login_button
|
16
|
+
end
|
17
|
+
end
|
10
18
|
|
11
|
-
|
19
|
+
get '/secure' do
|
20
|
+
authorize! # require a user be logged in
|
12
21
|
|
13
|
-
|
14
|
-
|
15
|
-
end
|
22
|
+
authorized_email # browserid email
|
23
|
+
end
|
16
24
|
|
17
|
-
|
25
|
+
get '/logout' do
|
18
26
|
logout!
|
19
27
|
|
20
28
|
redirect '/'
|
21
|
-
|
22
|
-
|
23
|
-
get '/confidential' do
|
24
|
-
authorize!
|
25
|
-
|
26
|
-
"Hey #{authorized_email}, you're authorized!"
|
27
|
-
end
|
28
|
-
end
|
29
|
+
end
|
data/example/config.ru
CHANGED
@@ -28,6 +28,28 @@ module Sinatra
|
|
28
28
|
session[:browserid_email]
|
29
29
|
end
|
30
30
|
|
31
|
+
# Normalize the email like the broker will do it, see
|
32
|
+
# https://github.com/portier/portier.github.io/blob/master/specs/Email-Normalization.md
|
33
|
+
def normalize_email(email)
|
34
|
+
begin
|
35
|
+
user, domain = email.split("@")
|
36
|
+
if user == nil or user.empty?
|
37
|
+
raise ArgumentError.new('user part must not be empty')
|
38
|
+
end
|
39
|
+
user = user.downcase
|
40
|
+
domain = SimpleIDN.to_ascii(domain).downcase
|
41
|
+
begin
|
42
|
+
IPAddr.new(domain)
|
43
|
+
rescue
|
44
|
+
# if domain could not be parsed as IP we are good
|
45
|
+
return user + "@" + domain
|
46
|
+
end
|
47
|
+
raise ArgumentError.new('domain must not be an IP')
|
48
|
+
rescue Exception => e
|
49
|
+
raise ArgumentError, 'Not a valid email adress: ' + e.message
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
31
53
|
# Returns the HTML to render the Persona login form.
|
32
54
|
# Optionally takes a URL parameter for where the user should
|
33
55
|
# be redirected to after the assert POST back.
|
@@ -10,7 +10,7 @@ module Sinatra
|
|
10
10
|
<input type=hidden name=client_id value="<%= request.base_url.chomp('/') %>" />
|
11
11
|
<input type=hidden name=redirect_uri value="<%= url '/_browserid_assert' %>" />
|
12
12
|
<input type=hidden name=nonce value="<%= nonce %>" />
|
13
|
-
<input type=submit value="
|
13
|
+
<input type=submit value="<%= settings.browserid_button_text %>" class="<%= settings.browserid_button_class %>" />
|
14
14
|
</form>
|
15
15
|
EOF
|
16
16
|
end
|
data/lib/sinatra/browserid.rb
CHANGED
@@ -4,9 +4,12 @@ require "open-uri"
|
|
4
4
|
require 'json'
|
5
5
|
require 'url_safe_base64'
|
6
6
|
require 'jwt'
|
7
|
+
require 'simpleidn'
|
8
|
+
require 'ipaddr'
|
7
9
|
require "sinatra/base"
|
8
10
|
require 'sinatra/browserid/helpers'
|
9
11
|
require 'sinatra/browserid/template'
|
12
|
+
require 'addressable/uri'
|
10
13
|
|
11
14
|
# This module provides an interface to verify a users email address
|
12
15
|
# with browserid.org.
|
@@ -19,6 +22,7 @@ module Sinatra
|
|
19
22
|
app.set :browserid_login_button, :red
|
20
23
|
app.set :browserid_login_url, "/_browserid_login"
|
21
24
|
app.set :browserid_button_class, ""
|
25
|
+
app.set :browserid_button_text, "Log in"
|
22
26
|
|
23
27
|
app.get '/_browserid_login' do
|
24
28
|
# TODO(petef): render a page that initiates login without
|
@@ -30,10 +34,19 @@ module Sinatra
|
|
30
34
|
begin
|
31
35
|
# 3. Server checks signature
|
32
36
|
# for that, fetch the public key from the LA instance (TODO: Do that beforehand for trusted instances, and generally cache the key)
|
33
|
-
|
37
|
+
public_key_jwks_uri = Addressable::URI.parse(settings.browserid_url + '/keys.json')
|
38
|
+
public_key_jwks = ::JSON.parse(URI.parse(public_key_jwks_uri).read)
|
34
39
|
public_key = OpenSSL::PKey::RSA.new
|
35
|
-
public_key.
|
36
|
-
|
40
|
+
if public_key.respond_to? :set_key
|
41
|
+
# set n and d via the new set_key function, as direct access to n and e is blocked for some ruby and openssl versions.
|
42
|
+
# Note that we have no d, as this is a public key, which would be the third param
|
43
|
+
public_key.set_key( (OpenSSL::BN.new UrlSafeBase64.decode64(public_key_jwks["keys"][0]["n"]), 2),
|
44
|
+
(OpenSSL::BN.new UrlSafeBase64.decode64(public_key_jwks["keys"][0]["e"]), 2),
|
45
|
+
nil)
|
46
|
+
else
|
47
|
+
public_key.e = OpenSSL::BN.new UrlSafeBase64.decode64(public_key_jwks["keys"][0]["e"]), 2
|
48
|
+
public_key.n = OpenSSL::BN.new UrlSafeBase64.decode64(public_key_jwks["keys"][0]["n"]), 2
|
49
|
+
end
|
37
50
|
|
38
51
|
id_token = JWT.decode params[:id_token], public_key, true, { :algorithm => 'RS256' }
|
39
52
|
id_token = id_token[0]
|
@@ -43,7 +56,7 @@ module Sinatra
|
|
43
56
|
id_token["exp"] > Time.now.to_i &&
|
44
57
|
id_token["email_verified"] &&
|
45
58
|
id_token["nonce"] == session[:nonce])
|
46
|
-
session[:browserid_email] = id_token[
|
59
|
+
session[:browserid_email] = id_token['email']
|
47
60
|
session.delete(:nonce)
|
48
61
|
if session['redirect_url']
|
49
62
|
redirect session['redirect_url']
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sinatra-portier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pete Fritchman
|
8
8
|
- Malte Paskuda
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-09-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sinatra
|
@@ -53,7 +53,35 @@ dependencies:
|
|
53
53
|
- - ">="
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: 0.2.2
|
56
|
-
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: simpleidn
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 0.0.9
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 0.0.9
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: addressable
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '2.8'
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '2.8'
|
84
|
+
description:
|
57
85
|
email:
|
58
86
|
- malte@paskuda.biz
|
59
87
|
executables: []
|
@@ -63,7 +91,6 @@ files:
|
|
63
91
|
- README.md
|
64
92
|
- example/app.rb
|
65
93
|
- example/config.ru
|
66
|
-
- example/views/index.erb
|
67
94
|
- lib/sinatra/browserid.rb
|
68
95
|
- lib/sinatra/browserid/helpers.rb
|
69
96
|
- lib/sinatra/browserid/template.rb
|
@@ -71,7 +98,7 @@ files:
|
|
71
98
|
homepage: https://github.com/onli/sinatra-portier
|
72
99
|
licenses: []
|
73
100
|
metadata: {}
|
74
|
-
post_install_message:
|
101
|
+
post_install_message:
|
75
102
|
rdoc_options:
|
76
103
|
- "--inline-source"
|
77
104
|
require_paths:
|
@@ -87,9 +114,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
87
114
|
- !ruby/object:Gem::Version
|
88
115
|
version: '0'
|
89
116
|
requirements: []
|
90
|
-
|
91
|
-
|
92
|
-
signing_key:
|
117
|
+
rubygems_version: 3.2.22
|
118
|
+
signing_key:
|
93
119
|
specification_version: 4
|
94
120
|
summary: Sinatra extension for user authentication with portier
|
95
121
|
test_files: []
|
data/example/views/index.erb
DELETED
@@ -1,21 +0,0 @@
|
|
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>
|