heroku-bouncer 0.4.0.pre2 → 0.4.0.pre3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 251889f5d6ea897a0ff12014d09e83ecc1daec83
4
- data.tar.gz: 35458dfffc28c61a9b1ec3391a38039308a81840
3
+ metadata.gz: e309a66ada0259f78b01d8524259250a0cbba5ab
4
+ data.tar.gz: 66b98fb8a1fa87093aa6b632c1097077a3d13792
5
5
  SHA512:
6
- metadata.gz: c8f8233a0789b6be629ed528ff9d7e6b0529bf6c3a93ae16b673ba54538383655f793989d785a4dadf1b8c25052a7ba9dabb9cdcd662a9129d2c8cdc5eef6271
7
- data.tar.gz: cda090b0f6ce0803f1981d318f0ca02bd2dbf04362c18ee6603523d864efeccf696268a9db59c673867306585bb24038412dff9b7da81f1f49b0bd90cfa06629
6
+ metadata.gz: c334ee9efd1af0e1c6e9e9d9ea72c3c26f63b514179cb6a163cd7bb58859b3b6497811f7fada20ff59ae571f963ec430d4f4929d5d9c99d282e81c9d65cd4143
7
+ data.tar.gz: dd1ce965ccea7181e62189b361b5125d730a0cb30c5fdf3cbb543d07cae42b5bd8604b546ca7cc70d3f6c04e1a4c1747316664cd018396e4d1268963385fa77c
data/Gemfile.lock CHANGED
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- heroku-bouncer (0.3.3)
4
+ heroku-bouncer (0.4.0.pre2)
5
5
  faraday (~> 0.8)
6
- multi_json (~> 1.0)
7
6
  omniauth-heroku (>= 0.1.0)
7
+ rack (~> 1.0)
8
8
  sinatra (~> 1.0)
9
9
 
10
10
  GEM
@@ -12,12 +12,16 @@ GEM
12
12
  specs:
13
13
  faraday (0.8.8)
14
14
  multipart-post (~> 1.2.0)
15
- hashie (2.0.5)
15
+ hashie (1.2.0)
16
16
  httpauth (0.2.0)
17
17
  jwt (0.1.8)
18
18
  multi_json (>= 1.5)
19
+ metaclass (0.0.1)
19
20
  minitest (5.0.8)
20
- multi_json (1.8.0)
21
+ minitest-spec-context (0.0.3)
22
+ mocha (0.14.0)
23
+ metaclass (~> 0.0.1)
24
+ multi_json (1.8.2)
21
25
  multipart-post (1.2.0)
22
26
  oauth2 (0.8.1)
23
27
  faraday (~> 0.8)
@@ -37,7 +41,10 @@ GEM
37
41
  rack (1.5.2)
38
42
  rack-protection (1.5.0)
39
43
  rack
40
- sinatra (1.4.3)
44
+ rack-test (0.6.2)
45
+ rack (>= 1.0)
46
+ rake (10.1.0)
47
+ sinatra (1.4.4)
41
48
  rack (~> 1.4)
42
49
  rack-protection (~> 1.4)
43
50
  tilt (~> 1.3, >= 1.3.4)
@@ -49,3 +56,7 @@ PLATFORMS
49
56
  DEPENDENCIES
50
57
  heroku-bouncer!
51
58
  minitest (~> 5.0)
59
+ minitest-spec-context
60
+ mocha
61
+ rack-test
62
+ rake
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Build Status](https://travis-ci.org/heroku/heroku-bouncer.png)](https://travis-ci.org/heroku/heroku-bouncer)
2
+
1
3
  # Heroku Bouncer
2
4
 
3
5
  Heroku Bouncer is a Rack middleware (implemented in Sinatra) that
@@ -40,7 +42,8 @@ Sinatra app that uses heroku-bouncer.
40
42
 
41
43
  # use `openssl rand -base64 32` to generate a secret
42
44
  use Rack::Session::Cookie, secret: "..."
43
- use Heroku::Bouncer
45
+ use Heroku::Bouncer,
46
+ oauth: { id: "...", secret: "..." }, secret: "..."
44
47
  run MyApp
45
48
  ```
46
49
 
@@ -54,7 +57,8 @@ Sinatra app that uses heroku-bouncer.
54
57
  class MyApp < Sinatra::Base
55
58
  ...
56
59
  enable :sessions, secret: "..."
57
- use ::Heroku::Bouncer
60
+ use ::Heroku::Bouncer,
61
+ oauth: { id: "...", secret: "..." }, secret: "..."
58
62
  ...
59
63
  ```
60
64
 
@@ -63,10 +67,11 @@ Sinatra app that uses heroku-bouncer.
63
67
  Add a middleware configuration line to `config/application.rb`:
64
68
 
65
69
  ```ruby
66
- config.middleware.use ::Heroku::Bouncer
70
+ config.middleware.use ::Heroku::Bouncer,
71
+ oauth: { id: "...", secret: "..." }, secret: "..."
67
72
  ```
68
73
 
69
- 4. Add the required options `:oauth` and `:secret` as explained
74
+ 4. Fill in the required settings `:oauth` and `:secret` as explained
70
75
  below.
71
76
 
72
77
  ## Settings
@@ -77,15 +82,15 @@ Two settings are **required**:
77
82
  * `secret`: A random string used as an encryption secret used to secure
78
83
  the user information in the session.
79
84
 
80
- For example:
85
+ Using environment variables for these is recommended, for example:
81
86
 
82
87
  ```ruby
83
88
  use Heroku::Bouncer,
84
- oauth: { id: "...", secret: "..." },
85
- secret: "..."
89
+ oauth: { id: ENV['HEROKU_OAUTH_ID'], secret: ENV['HEROKU_OAUTH_SECRET'] },
90
+ secret: ENV['HEROKU_BOUNCER_SECRET']
86
91
  ```
87
92
 
88
- There are 5 options you can pass to the middleware:
93
+ There are 7 additional options you can pass to the middleware:
89
94
 
90
95
  * `oauth[:scope]`: The [OAuth scope][] to use when requesting the OAuth
91
96
  token. Default: `identity`.
@@ -98,9 +103,13 @@ There are 5 options you can pass to the middleware:
98
103
  Default: `true`
99
104
  * `expose_user`: Expose the user attributes in the session. Default:
100
105
  `true`
106
+ * `session_sync_nonce`: If present, determines the name of a cookie shared across properties under a same domain in order to keep their sessions synchronized. Default: `nil`
107
+ * `allow_anonymous`: Accepts a lambda that gets called with each request. If the lambda evals to true, the request will not enforce authentication (e.g: `allow_anonymous: lambda { |req| !/\A\/admin/.match(req.fullpath) }` will allow anonymous requests except those with under the `/admin` path). Default: `nil`, which does not allow anonymous access to any URL.
108
+
101
109
 
102
110
  You use these by passing a hash to the `use` call, for example:
103
111
 
112
+
104
113
  ```ruby
105
114
  use Heroku::Bouncer,
106
115
  oauth: { id: "...", secret: "...", scope: "global" },
@@ -124,7 +133,7 @@ You can access this in Sinatra and Rails by `request.env[key]`, e.g.
124
133
 
125
134
  If you set `expose_token` to `true`, you'll get an API token that you
126
135
  can use to make Heroku API calls on behalf of the logged-in user using
127
- [heroku.rb](https://github.com/heroku/heroku.rb).
136
+ [heroku.rb][] .
128
137
 
129
138
  ```ruby
130
139
  heroku = Heroku::API.new(:api_key => request.env["bouncer.token"])
@@ -143,16 +152,35 @@ logging in again.
143
152
 
144
153
  ## Conditionally enable the middleware
145
154
 
146
- Don't want to OAuth on every request? Use a middleware to conditionally
147
- enable this middleware, like [Rack::Builder][].
148
- Alternatively, [use inheritance to extend the middleware to act any way
149
- you like][inheritance].
155
+ > Don't want to OAuth on every request? Use a middleware to conditionally
156
+ > enable this middleware, like [Rack::Builder][].
157
+ > Alternatively, [use inheritance to extend the middleware to act any way
158
+ > you like][inheritance].
150
159
 
151
- ## There be dragons
160
+ Due to changes in how the middleware stack is built, this is currently
161
+ broken in the 0.4.0 prereleases.
152
162
 
153
- * There's no tests yet. You may encounter bugs. Please report them (or
154
- fix them in a pull request).
163
+ ## Security Model: A Tale of Three Secrets
164
+
165
+ There are three secrets in use:
166
+
167
+ * A OAuth secret. Paired with the OAuth ID, this is how the Heroku
168
+ authorizes your OAuth requests with your particular OAuth client.
169
+ * A bouncer secret. Bouncer encrypts and signs all user data placed in
170
+ the session. This ensures such data cannot be viewed by anyone but the
171
+ application.
172
+ * A session secret. This is used to sign the session, which validates
173
+ the session was generated by your application. Strictly speaking,
174
+ however, this is outside of Bouncer and is not a part of its security
175
+ model.
176
+
177
+ In totality, Heroku Bouncer ensures session data can only be generated
178
+ and read by your application. However, they do not protect against
179
+ replay attacks if the data is obtained in its entirety. SSL and session
180
+ timeouts should be used to help mitigate this risk. CSRF tokens for any
181
+ actions that modify data are also recommended.
155
182
 
156
- [OAuth scope]: https://devcenter.heroku.com/articles/oauth#scopes
157
183
  [Rack::Builder]: http://rack.rubyforge.org/doc/Rack/Builder.html
158
184
  [inheritance]: https://gist.github.com/wuputah/5534428
185
+ [OAuth scope]: https://devcenter.heroku.com/articles/oauth#scopes
186
+ [heroku.rb]: https://github.com/heroku/heroku.rb
data/Rakefile CHANGED
@@ -0,0 +1,9 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << "test"
5
+ t.test_files = FileList['test/**/*_test.rb']
6
+ t.verbose = true
7
+ end
8
+
9
+ task :default => :test
@@ -24,6 +24,8 @@ class Heroku::Bouncer::Middleware < Sinatra::Base
24
24
  @expose_token = extract_option(options, :expose_token, false)
25
25
  @expose_email = extract_option(options, :expose_email, true)
26
26
  @expose_user = extract_option(options, :expose_user, true)
27
+ @session_sync_nonce = extract_option(options, :session_sync_nonce, nil)
28
+ @allow_anonymous = extract_option(options, :allow_anonymous, nil)
27
29
  end
28
30
  end
29
31
 
@@ -44,10 +46,36 @@ class Heroku::Bouncer::Middleware < Sinatra::Base
44
46
  return_value
45
47
  end
46
48
 
49
+ def auth_request?
50
+ %w[/auth/heroku/callback /auth/heroku /auth/failure /auth/sso-logout /auth/logout /auth/login].include?(request.path)
51
+ end
52
+
53
+ def session_nonce_mismatch?
54
+ (store_read(@session_sync_nonce.to_sym).to_s != session_nonce_cookie.to_s) && !auth_request?
55
+ end
56
+
57
+ def session_nonce_cookie
58
+ @session_sync_nonce && request.cookies[@session_sync_nonce]
59
+ end
60
+
61
+ def anonymous_request_allowed?
62
+ auth_request? || (@allow_anonymous && @allow_anonymous.call(request))
63
+ end
64
+
47
65
  before do
66
+ if @session_sync_nonce && session_nonce_mismatch?
67
+ if session_nonce_cookie.to_s.empty?
68
+ destroy_session
69
+ redirect to(request.url)
70
+ else
71
+ store_write(:return_to, request.url)
72
+ redirect to('/auth/heroku')
73
+ end
74
+ end
75
+
48
76
  if store_read(:user)
49
77
  expose_store
50
- elsif ! %w[/auth/heroku/callback /auth/heroku /auth/failure /auth/sso-logout /auth/logout].include?(request.path)
78
+ elsif !anonymous_request_allowed?
51
79
  store_write(:return_to, request.url)
52
80
  redirect to('/auth/heroku')
53
81
  end
@@ -67,7 +95,7 @@ class Heroku::Bouncer::Middleware < Sinatra::Base
67
95
  else
68
96
  store_write(:user, true)
69
97
  end
70
-
98
+ store_write(@session_sync_nonce.to_sym, session_nonce_cookie) if @session_sync_nonce
71
99
  store_write(:token, token) if @expose_token
72
100
  redirect to(store_delete(:return_to) || '/')
73
101
  end
@@ -82,7 +110,12 @@ class Heroku::Bouncer::Middleware < Sinatra::Base
82
110
  get '/auth/sso-logout' do
83
111
  destroy_session
84
112
  auth_url = ENV["HEROKU_AUTH_URL"] || "https://id.heroku.com"
85
- redirect to("#{auth_url}/logout")
113
+ logout_url = "#{auth_url}/logout"
114
+
115
+ # id.heroku.com whitelists this return_to param, as any auth provider should do
116
+ logout_url += "?url=#{params['return_to']}" if params['return_to']
117
+
118
+ redirect to(logout_url)
86
119
  end
87
120
 
88
121
  # logout but only locally
@@ -91,6 +124,12 @@ class Heroku::Bouncer::Middleware < Sinatra::Base
91
124
  redirect to("/")
92
125
  end
93
126
 
127
+ # login, setting the URL to return to
128
+ get '/auth/login' do
129
+ store_write(:return_to, params['return_to'])
130
+ redirect to('/auth/heroku')
131
+ end
132
+
94
133
  private
95
134
 
96
135
  def extract_option(options, option, default = nil)
@@ -132,7 +171,7 @@ private
132
171
  end
133
172
 
134
173
  def destroy_session
135
- session = nil if session
174
+ store.keys.each { |k| store_delete(k) }
136
175
  end
137
176
 
138
177
  def expose_store
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heroku-bouncer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0.pre2
4
+ version: 0.4.0.pre3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Dance
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-15 00:00:00.000000000 Z
11
+ date: 2013-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: omniauth-heroku
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: minitest
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +94,48 @@ dependencies:
80
94
  - - ~>
81
95
  - !ruby/object:Gem::Version
82
96
  version: '5.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest-spec-context
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rack-test
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: mocha
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
83
139
  description: ID please.
84
140
  email:
85
141
  - jd@heroku.com
@@ -88,12 +144,12 @@ extensions: []
88
144
  extra_rdoc_files:
89
145
  - README.md
90
146
  files:
91
- - lib/heroku/bouncer.rb
92
- - lib/heroku/bouncer/decrypted_hash.rb
93
147
  - lib/heroku/bouncer/lockbox.rb
94
- - lib/heroku/bouncer/json_parser.rb
148
+ - lib/heroku/bouncer/decrypted_hash.rb
95
149
  - lib/heroku/bouncer/builder.rb
150
+ - lib/heroku/bouncer/json_parser.rb
96
151
  - lib/heroku/bouncer/middleware.rb
152
+ - lib/heroku/bouncer.rb
97
153
  - README.md
98
154
  - Gemfile
99
155
  - Gemfile.lock
@@ -118,10 +174,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
174
  version: 1.3.1
119
175
  requirements: []
120
176
  rubyforge_project:
121
- rubygems_version: 2.0.3
177
+ rubygems_version: 2.0.14
122
178
  signing_key:
123
179
  specification_version: 4
124
- summary: Requires Heroku OAuth on all requests.
180
+ summary: Rapidly add Heroku OAuth to your Ruby app.
125
181
  test_files:
126
182
  - Gemfile
127
183
  - Gemfile.lock