heroku-bouncer 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +7 -0
- data/README.md +36 -15
- data/lib/heroku/bouncer/builder.rb +2 -0
- data/lib/heroku/bouncer/middleware.rb +35 -7
- data/lib/heroku/bouncer/views/login.erb +15 -0
- metadata +41 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c50847511ce57c696fca30c5a7cfa9c6bf8f70d16ee66130b9f83f81c612c252
|
4
|
+
data.tar.gz: 0ace5e96d9dc4dd373b670fddcf7dccc23db906166ccefeeda5761b70a037c67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 341161c33386f2db7f369ad4dfa68e54046e4a2d794ae785d883a3925cb2c10a3ba178beeae65b8197ac9e8571248c7949a17d5ba6d020cb0763c7f1f72906eb
|
7
|
+
data.tar.gz: a79e4c4d4866135fd34d88fb9d4f66096fc20941d306f8bf343eee57f2c007af1672ea9604ea1548f3b99e46424d208fe0dad93ab5cf0aa1698663591f830c1a
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# 0.9.0
|
2
|
+
|
3
|
+
* #68: Loosen `omniauth-heroku` constraint, allowing `>= 0.1, < 2`,
|
4
|
+
enabling support of OmniAuth 2. This also adds the new [`:login_path`
|
5
|
+
option](README#prompt-to-login). @stevenharman
|
6
|
+
* #66: Loosen Faraday constraints, allowing `>= 0.8", < 2`. @stevenharman
|
7
|
+
|
1
8
|
# 0.8.0
|
2
9
|
|
3
10
|
* #55: Ruby >= 2.4 support and Ruby <2.2 deprecation. Thanks @maxbeizer!
|
data/README.md
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
[![Build Status](https://
|
2
|
-
[![Dependency Status](https://gemnasium.com/heroku/heroku-bouncer.png)](https://gemnasium.com/heroku/heroku-bouncer)
|
1
|
+
[![Build Status](https://github.com/sharpstone/heroku-bouncer/actions/workflows/ci.yml/badge.svg)](https://github.com/sharpstone/heroku-bouncer/actions)
|
3
2
|
|
4
3
|
# Heroku Bouncer
|
5
4
|
|
@@ -8,9 +7,9 @@ requires Heroku OAuth on all requests.
|
|
8
7
|
|
9
8
|
## Ruby and Rack compatibility
|
10
9
|
|
11
|
-
* **Ruby**: Versions
|
12
|
-
that works with prior versions of Ruby, please use version `~> 0.7.1`.
|
13
|
-
Note, however, that 0.7.1 does not support Rack 2 (Rails 5).
|
10
|
+
* **Ruby**: Versions `>= 0.8.0` require Ruby >= 2.2.
|
11
|
+
If you need a version that works with prior versions of Ruby, please use version `~> 0.7.1`.
|
12
|
+
Note, however, that `0.7.1` does not support Rack 2 (Rails 5+).
|
14
13
|
|
15
14
|
* **Rack**: Rack 1 and 2 are supported.
|
16
15
|
|
@@ -23,7 +22,7 @@ Sinatra app that uses heroku-bouncer.
|
|
23
22
|
|
24
23
|
1. Install the Heroku OAuth CLI plugin.
|
25
24
|
|
26
|
-
```
|
25
|
+
```console
|
27
26
|
heroku plugins:install heroku-cli-oauth
|
28
27
|
```
|
29
28
|
|
@@ -31,7 +30,7 @@ Sinatra app that uses heroku-bouncer.
|
|
31
30
|
callback endpoint. Use `http://localhost:5000/auth/heroku/callback`
|
32
31
|
for local development with Foreman.
|
33
32
|
|
34
|
-
```
|
33
|
+
```console
|
35
34
|
heroku clients:create localhost http://localhost:5000/auth/heroku/callback
|
36
35
|
heroku clients:create myapp https://myapp.herokuapp.com/auth/heroku/callback
|
37
36
|
```
|
@@ -113,8 +112,8 @@ Here are the supported options you can pass to the middleware:
|
|
113
112
|
representing the user. If the lambda evaluates to true, allow the user
|
114
113
|
through. If false, redirects to `redirect_url`. By default, all users are
|
115
114
|
allowed through after authenticating.
|
116
|
-
* `
|
117
|
-
|
115
|
+
* `login_path`: Where unauthorized users are redirected so they can be [prompted to login](#prompt-to-login). Defaults to `heroku-bouncer`'s own `/auth/login` path.
|
116
|
+
* `redirect_url`: Where unauthorized users are redirected during the OAuth callback phase. Defaults to `www.heroku.com`.
|
118
117
|
* `expose_token`: Expose the OAuth token in the session, allowing you to
|
119
118
|
make API calls as the user. Default: `false`
|
120
119
|
* `expose_email`: Expose the user's email address in the session.
|
@@ -138,7 +137,6 @@ Here are the supported options you can pass to the middleware:
|
|
138
137
|
|
139
138
|
You use these by passing a hash to the `use` call, for example:
|
140
139
|
|
141
|
-
|
142
140
|
```ruby
|
143
141
|
use Heroku::Bouncer,
|
144
142
|
oauth: { id: "...", secret: "...", scope: "global" },
|
@@ -146,6 +144,29 @@ use Heroku::Bouncer,
|
|
146
144
|
expose_token: true
|
147
145
|
```
|
148
146
|
|
147
|
+
### Prompt to Login
|
148
|
+
|
149
|
+
To mitigate Cross-Site Request Forgery attacks, [OmniAuth no longer allows `GET` requests to the `/auth/heroku`](https://github.com/omniauth/omniauth/wiki/Upgrading-to-2.0) path.
|
150
|
+
To support this, `heroku-bouncer` no longer redirects unauthorized requests to the `/auth/heroku` path.
|
151
|
+
Instead users are redirected to `/auth/login` where a simple HTML template is rendered, prompting the user to authenticate with Heroku.
|
152
|
+
|
153
|
+
The template includes a `<form>` with a button which will `POST` to the `/auth/heroku` path.
|
154
|
+
It also includes the Authenticity Token from `Rack::Protection`.
|
155
|
+
The view provides no styling; it is the most basic example of what's required.
|
156
|
+
|
157
|
+
To render your own prompt UI, provide the `:login_path` option.
|
158
|
+
Unauthenticated users will be redirected to this path, allowing you to control the UI.
|
159
|
+
The resulting page should render an HTML `<form>` which will `POST` to the `/auth/heroku` path.
|
160
|
+
The form needs to include a field named `authenticity_token` with the token from `Rack::Protection`.
|
161
|
+
|
162
|
+
An example to get you started:
|
163
|
+
|
164
|
+
```erb
|
165
|
+
<form method="post" action="/auth/heroku">
|
166
|
+
<input type="hidden" name="authenticity_token" value="<%= request.env["rack.session"]["csrf"] %>">
|
167
|
+
<button type="submit">Sign in via Heroku</button>
|
168
|
+
```
|
169
|
+
|
149
170
|
## How to get the data
|
150
171
|
|
151
172
|
Based on your choice of the expose options above, the middleware adds
|
@@ -161,13 +182,13 @@ You can access this in Sinatra and Rails by `request.env[key]`, e.g.
|
|
161
182
|
|
162
183
|
## Using the Heroku API
|
163
184
|
|
164
|
-
If you set `expose_token` to `true`, you'll get an
|
185
|
+
If you set `expose_token` to `true`, you'll get an OAuth token that you
|
165
186
|
can use to make Heroku API calls on behalf of the logged-in user using
|
166
|
-
[
|
187
|
+
the [platform API][platform-api].
|
167
188
|
|
168
189
|
```ruby
|
169
|
-
heroku =
|
170
|
-
|
190
|
+
heroku = PlatformAPI.connect_oauth(request.env["bouncer.token"])
|
191
|
+
info = heroku.app.info('sushi')
|
171
192
|
```
|
172
193
|
|
173
194
|
Keep in mind that this adds substantial security risk to your
|
@@ -209,4 +230,4 @@ actions that modify data are also recommended.
|
|
209
230
|
[Rack::Builder]: http://rack.rubyforge.org/doc/Rack/Builder.html
|
210
231
|
[inheritance]: https://gist.github.com/wuputah/5534428
|
211
232
|
[OAuth scope]: https://devcenter.heroku.com/articles/oauth#scopes
|
212
|
-
[
|
233
|
+
[platform-api]: https://github.com/heroku/platform-api
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'heroku/bouncer/middleware'
|
2
2
|
require 'rack/builder'
|
3
|
+
require 'rack/protection'
|
3
4
|
require 'omniauth-heroku'
|
4
5
|
|
5
6
|
class Heroku::Bouncer::Builder
|
@@ -8,6 +9,7 @@ class Heroku::Bouncer::Builder
|
|
8
9
|
builder = Rack::Builder.new
|
9
10
|
id, secret, scope = extract_options!(options)
|
10
11
|
unless options[:disabled]
|
12
|
+
builder.use Rack::Protection
|
11
13
|
builder.use OmniAuth::Builder do
|
12
14
|
provider :heroku, id, secret, :scope => scope
|
13
15
|
end
|
@@ -6,10 +6,12 @@ require 'heroku/bouncer/json_parser'
|
|
6
6
|
require 'heroku/bouncer/decrypted_hash'
|
7
7
|
|
8
8
|
class Heroku::Bouncer::Middleware < Sinatra::Base
|
9
|
-
|
10
9
|
DecryptedHash = ::Heroku::Bouncer::DecryptedHash
|
11
10
|
UnableToFetchUserError = Class.new(RuntimeError)
|
12
11
|
|
12
|
+
DEFAULT_LOGIN_PATH = "/auth/login".freeze
|
13
|
+
private_constant :DEFAULT_LOGIN_PATH
|
14
|
+
|
13
15
|
enable :raise_errors
|
14
16
|
disable :show_exceptions
|
15
17
|
|
@@ -20,8 +22,10 @@ class Heroku::Bouncer::Middleware < Sinatra::Base
|
|
20
22
|
# super is not called; we're not using sinatra if we're disabled
|
21
23
|
else
|
22
24
|
super(app)
|
25
|
+
@disabled = false
|
23
26
|
@cookie_secret = extract_option(options, :secret, SecureRandom.hex(64))
|
24
27
|
@allow_if_user = extract_option(options, :allow_if_user, nil)
|
28
|
+
@login_path = extract_option(options, :login_path, DEFAULT_LOGIN_PATH)
|
25
29
|
@redirect_url = extract_option(options, :redirect_url, 'https://www.heroku.com')
|
26
30
|
|
27
31
|
# backwards-compatibilty for `herokai_only`:
|
@@ -125,7 +129,7 @@ class Heroku::Bouncer::Middleware < Sinatra::Base
|
|
125
129
|
auth_url = ENV["HEROKU_AUTH_URL"] || "https://id.heroku.com"
|
126
130
|
logout_url = "#{auth_url}/logout"
|
127
131
|
|
128
|
-
# id.heroku.com
|
132
|
+
# id.heroku.com allowlists this return_to param, as any auth provider should do
|
129
133
|
logout_url += "?url=#{params['return_to']}" if params['return_to']
|
130
134
|
|
131
135
|
redirect to(logout_url)
|
@@ -138,15 +142,24 @@ class Heroku::Bouncer::Middleware < Sinatra::Base
|
|
138
142
|
end
|
139
143
|
|
140
144
|
# login, setting the URL to return to
|
141
|
-
get
|
145
|
+
get DEFAULT_LOGIN_PATH do
|
142
146
|
if params['return_to'] && params['return_to'].length <= 255
|
143
147
|
store_write(:return_to, params['return_to'])
|
144
148
|
end
|
145
|
-
|
149
|
+
|
150
|
+
if custom_login_path?
|
151
|
+
redirect to(login_path)
|
152
|
+
else
|
153
|
+
erb(:login, locals: {
|
154
|
+
authenticity_token: request.env["rack.session"]["csrf"]
|
155
|
+
})
|
156
|
+
end
|
146
157
|
end
|
147
158
|
|
148
159
|
private
|
149
160
|
|
161
|
+
attr_reader :login_path
|
162
|
+
|
150
163
|
def unlock_session_data(env, &block)
|
151
164
|
decrypt_store(env)
|
152
165
|
yield
|
@@ -154,8 +167,20 @@ private
|
|
154
167
|
encrypt_store(env)
|
155
168
|
end
|
156
169
|
|
170
|
+
def auth_paths
|
171
|
+
@auth_paths ||= [
|
172
|
+
"/auth/heroku/callback",
|
173
|
+
"/auth/heroku",
|
174
|
+
"/auth/failure",
|
175
|
+
"/auth/sso-logout",
|
176
|
+
"/auth/logout",
|
177
|
+
DEFAULT_LOGIN_PATH,
|
178
|
+
login_path
|
179
|
+
].compact.freeze
|
180
|
+
end
|
181
|
+
|
157
182
|
def auth_request?
|
158
|
-
|
183
|
+
auth_paths.include?(request.path_info)
|
159
184
|
end
|
160
185
|
|
161
186
|
def session_nonce_mismatch?
|
@@ -175,13 +200,17 @@ private
|
|
175
200
|
ts.nil? || Time.now.to_i > ts
|
176
201
|
end
|
177
202
|
|
203
|
+
def custom_login_path?
|
204
|
+
login_path != DEFAULT_LOGIN_PATH
|
205
|
+
end
|
206
|
+
|
178
207
|
def skip?(env)
|
179
208
|
@skip && @skip.call(env)
|
180
209
|
end
|
181
210
|
|
182
211
|
def require_authentication
|
183
212
|
store_write(:return_to, request.url)
|
184
|
-
redirect to(
|
213
|
+
redirect to(login_path)
|
185
214
|
end
|
186
215
|
|
187
216
|
def extract_option(options, option, default = nil)
|
@@ -257,5 +286,4 @@ private
|
|
257
286
|
return_to.port = port unless port == 80
|
258
287
|
return_to.to_s
|
259
288
|
end
|
260
|
-
|
261
289
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<title>Login with Heroku</title>
|
6
|
+
<%# Avoid extra requests for favicon.ico %>
|
7
|
+
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
|
8
|
+
</head>
|
9
|
+
<body class="heroku_bouncer">
|
10
|
+
<form method="post" action="/auth/heroku" class="heroku_bouncer-login_form">
|
11
|
+
<input type="hidden" name="authenticity_token" value="<%= authenticity_token %>">
|
12
|
+
<button type="submit">Login with Heroku</button>
|
13
|
+
</form>
|
14
|
+
</body>
|
15
|
+
</html>
|
metadata
CHANGED
@@ -1,29 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heroku-bouncer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Dance
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: omniauth-heroku
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0.1'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2'
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
|
-
- - "
|
27
|
+
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: '0.1'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2'
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: sinatra
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -48,16 +54,22 @@ dependencies:
|
|
48
54
|
name: faraday
|
49
55
|
requirement: !ruby/object:Gem::Requirement
|
50
56
|
requirements:
|
51
|
-
- - "
|
57
|
+
- - ">="
|
52
58
|
- !ruby/object:Gem::Version
|
53
59
|
version: '0.8'
|
60
|
+
- - "<"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '2'
|
54
63
|
type: :runtime
|
55
64
|
prerelease: false
|
56
65
|
version_requirements: !ruby/object:Gem::Requirement
|
57
66
|
requirements:
|
58
|
-
- - "
|
67
|
+
- - ">="
|
59
68
|
- !ruby/object:Gem::Version
|
60
69
|
version: '0.8'
|
70
|
+
- - "<"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '2'
|
61
73
|
- !ruby/object:Gem::Dependency
|
62
74
|
name: rack
|
63
75
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,16 +94,16 @@ dependencies:
|
|
82
94
|
name: rake
|
83
95
|
requirement: !ruby/object:Gem::Requirement
|
84
96
|
requirements:
|
85
|
-
- - "
|
97
|
+
- - ">="
|
86
98
|
- !ruby/object:Gem::Version
|
87
|
-
version:
|
99
|
+
version: 12.3.3
|
88
100
|
type: :development
|
89
101
|
prerelease: false
|
90
102
|
version_requirements: !ruby/object:Gem::Requirement
|
91
103
|
requirements:
|
92
|
-
- - "
|
104
|
+
- - ">="
|
93
105
|
- !ruby/object:Gem::Version
|
94
|
-
version:
|
106
|
+
version: 12.3.3
|
95
107
|
- !ruby/object:Gem::Dependency
|
96
108
|
name: minitest
|
97
109
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,14 +138,14 @@ dependencies:
|
|
126
138
|
requirements:
|
127
139
|
- - "~>"
|
128
140
|
- !ruby/object:Gem::Version
|
129
|
-
version: '
|
141
|
+
version: '1.1'
|
130
142
|
type: :development
|
131
143
|
prerelease: false
|
132
144
|
version_requirements: !ruby/object:Gem::Requirement
|
133
145
|
requirements:
|
134
146
|
- - "~>"
|
135
147
|
- !ruby/object:Gem::Version
|
136
|
-
version: '
|
148
|
+
version: '1.1'
|
137
149
|
- !ruby/object:Gem::Dependency
|
138
150
|
name: mocha
|
139
151
|
requirement: !ruby/object:Gem::Requirement
|
@@ -148,6 +160,20 @@ dependencies:
|
|
148
160
|
- - "~>"
|
149
161
|
- !ruby/object:Gem::Version
|
150
162
|
version: '1.1'
|
163
|
+
- !ruby/object:Gem::Dependency
|
164
|
+
name: nokogiri
|
165
|
+
requirement: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - "~>"
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '1.9'
|
170
|
+
type: :development
|
171
|
+
prerelease: false
|
172
|
+
version_requirements: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - "~>"
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: '1.9'
|
151
177
|
- !ruby/object:Gem::Dependency
|
152
178
|
name: delorean
|
153
179
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,7 +190,7 @@ dependencies:
|
|
164
190
|
version: '2.1'
|
165
191
|
description: ID please.
|
166
192
|
email:
|
167
|
-
- jd@
|
193
|
+
- jd@wuputah.com
|
168
194
|
executables: []
|
169
195
|
extensions: []
|
170
196
|
extra_rdoc_files:
|
@@ -183,6 +209,7 @@ files:
|
|
183
209
|
- lib/heroku/bouncer/json_parser.rb
|
184
210
|
- lib/heroku/bouncer/lockbox.rb
|
185
211
|
- lib/heroku/bouncer/middleware.rb
|
212
|
+
- lib/heroku/bouncer/views/login.erb
|
186
213
|
homepage: https://github.com/heroku/heroku-bouncer
|
187
214
|
licenses:
|
188
215
|
- MIT
|
@@ -202,8 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
202
229
|
- !ruby/object:Gem::Version
|
203
230
|
version: '0'
|
204
231
|
requirements: []
|
205
|
-
|
206
|
-
rubygems_version: 2.5.1
|
232
|
+
rubygems_version: 3.0.3
|
207
233
|
signing_key:
|
208
234
|
specification_version: 4
|
209
235
|
summary: Rapidly add Heroku OAuth to your Ruby app.
|