heroku-bouncer 0.4.0.pre2 → 0.4.0.pre3

Sign up to get free protection for your applications and to get access to all the features.
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