omniauth-heroku 0.2.0.pre → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- M2ZlY2IwZjQ5NmNhN2QyMjRhODI0MGE4MmQ5ODFkNzIxZDZiNThlYg==
5
- data.tar.gz: !binary |-
6
- MDEyNDQ1MjUzMThjMzQzYjU4NDFmMjQzNjYxYzBkZDVlOTE0OGU4Mw==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- MDJkMTc0MTBiNTIzZGU4ZDI4Y2YwYWRkOGEwNDJkNWFlYTczNzJiNzJmODRk
10
- YjJjNmNiZTk5NjU0MTNhNWE4ZDcyNTAyZGQwNWJjMGU5NTIzNjI0ZDIwYjVk
11
- YmRjODNlZGZlZDY5YjU1OGQ0ZTAzYWMxMTk2NGNlMGM3Njg4MTU=
12
- data.tar.gz: !binary |-
13
- NDFiYjc5NzNmMzE0MWZhYWFjYTdlZWE5MDdlM2ViOGU5MDNkNGFiZThjYmQz
14
- NTQ1NjczYzg2MDQ1MjMxNzU0OGIzNGNkMDUzMTMyZDI0ZWI0NGViOWFlNzJi
15
- YzI2NWNiNTViMTAwYzU1ZDBmMzRiYTE3YTc2MzNlMWYyNTQ4MzE=
2
+ SHA256:
3
+ metadata.gz: 5e748c5250cbb5edbba46f40b0f38d4a8cf54cd5c266b6df4deaebc57637e9d1
4
+ data.tar.gz: 4a5af940242e0cfb0a51ba7d73983303264846bb9278839cabadaaa890cf0227
5
+ SHA512:
6
+ metadata.gz: a623e6356f151b83eb7e370f8039e51012c9a76adf17187fe279aff23c10744b03514c46195198fd6261b9bcc206639ab7a15ea48875f6c06b300e3d8c72e45c
7
+ data.tar.gz: 61a1c1b3114cbf737de9de020572c98db82d3c29a180e0b135f3188ec6938123dc29766685475eff28e833d4d58ae600435411392b0a84579396757edccf5e19
@@ -0,0 +1,29 @@
1
+ name: CI
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ runs-on: ubuntu-latest
8
+
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ ruby: [ 2.3, 2.4, 2.5, 2.6, 2.7, 3.0 ]
13
+ gemfile: ["omniauth1", "omniauth2"]
14
+
15
+ env: # $BUNDLE_GEMFILE must be set at the job level, so it is set for all steps
16
+ BUNDLE_GEMFILE: Gemfile-${{ matrix.gemfile }}
17
+
18
+ steps:
19
+ - uses: actions/checkout@v2
20
+
21
+ - name: Setup Ruby
22
+ uses: ruby/setup-ruby@v1
23
+ with:
24
+ ruby-version: ${{ matrix.ruby }}
25
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
26
+
27
+ - name: Build and test
28
+ run: bin/rspec
29
+
data/.gitignore CHANGED
@@ -1,17 +1,17 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- /pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
1
+ # Ignore all logfiles and tempfiles
2
+ /coverage/
3
+ /log/
4
+ /spec/reports
5
+ /spec/rspec-status.txt
6
+ /tmp/
7
+ /tags
8
+
9
+ # Package and dependency caches
10
+ /.bundle
11
+ /Gemfile.lock
12
+ /pkg/
13
+
14
+ # Generated documentation
15
+ /doc/
16
+ /.yardoc
17
+ /_yardoc/
data/.rspec CHANGED
@@ -1 +1,3 @@
1
- --colour
1
+ --require spec_helper
2
+ --color
3
+ --format progress
data/CHANGELOG.md ADDED
@@ -0,0 +1,43 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
5
+ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [1.0.0] 2021-07-14
10
+
11
+ ### Changed
12
+
13
+ - Support `omniauth` versions `>= 1.9` but `< 3`.
14
+ i.e., support version `2` which addresses some CVEs.
15
+ - Standardize syntax and style via [Standard.rb](https://github.com/testdouble/standard)
16
+
17
+ ### Breaking
18
+
19
+ - Loosen `omniauth-oauth2` requirement to allow `>= 1.7.0`.
20
+ With this change, blocks give to dynamically determine the `:scope` argument will be passed the Rack `env`, rather than an instance of the `Rack::Request`.
21
+ See the [Upgrading to 1.0 docs](README.md#upgrading-to-10) for more.
22
+ - Remove `AuthUrl` and `ApiUrl` constants from `OmniAuth::Strategies::Heroku`.
23
+ These were internal details, not meant to be part of the public API.
24
+ - Require Ruby `>= 2.3.0`.
25
+ We were only supporting that anyway, but now it's explicit.
26
+ However, we do recommend only running on [actively supported Rubies](https://www.ruby-lang.org/en/downloads/branches/).
27
+
28
+ ## [0.4.1] 2021-07-06
29
+
30
+ ### Changed
31
+ - Lock to `omniauth-oauth2 ~> 1.6.0` to fix regression in dynamic `:scope` option.
32
+ With `omniauth-oauth2 >= 1.7.0`, the block is passed the Rack `env` as the parameter.
33
+ This breaks our expectation the will receive a `Rack::Request` instance as the argument to dynamically determine the `:scope` option.
34
+ i.e., this broken:
35
+
36
+ ```ruby
37
+ use OmniAuth::Builder do
38
+ provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET"),
39
+ scope: ->(request) { request.params["scope"] || "identity" }
40
+ end
41
+ ```
42
+
43
+ See [PR #22](https://github.com/heroku/omniauth-heroku/pull/22) for more context, workaround, etc...
data/Gemfile CHANGED
@@ -1,12 +1,3 @@
1
1
  source "https://www.rubygems.org"
2
2
 
3
3
  gemspec
4
-
5
- group :test do
6
- gem "multi_json"
7
- gem "rake"
8
- gem "rack-test"
9
- gem "rspec"
10
- gem "sinatra"
11
- gem "webmock"
12
- end
data/Gemfile-omniauth1 ADDED
@@ -0,0 +1,5 @@
1
+ source "https://www.rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "omniauth", "~> 1.9"
data/Gemfile-omniauth2 ADDED
@@ -0,0 +1,5 @@
1
+ source "https://www.rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "omniauth", "~> 2.0"
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Pedro Belo
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,12 +1,20 @@
1
1
  # OmniAuth Heroku
2
2
 
3
- [OmniAuth](https://github.com/intridea/omniauth) strategy for authenticating Heroku users.
3
+ [![Build Status](https://github.com/heroku/omniauth-heroku/actions/workflows/ci.yml/badge.svg)](https://github.com/heroku/omniauth-heroku/actions)
4
+ [![Gem Version](https://badge.fury.io/rb/omniauth-heroku.svg)](https://badge.fury.io/rb/omniauth-heroku)
4
5
 
5
- [![Build Status](https://travis-ci.org/heroku/omniauth-heroku.svg?branch=master)](https://travis-ci.org/heroku/omniauth-heroku)
6
+ [OmniAuth](https://github.com/intridea/omniauth) strategy for authenticating
7
+ Heroku users.
6
8
 
7
- Mount this with your Rack application (be it Rails or Sinatra) to simplify the [OAuth flow with Heroku](https://devcenter.heroku.com/articles/oauth).
9
+ Mount this with your Rack application (be it Rails or Sinatra) to simplify the
10
+ [OAuth flow with Heroku](https://devcenter.heroku.com/articles/oauth).
8
11
 
9
- This is intended for apps already using OmniAuth, for apps that authenticate against more than one service (eg: Heroku and GitHub), or apps that have specific needs on session management. If your app doesn't fall in any of these you should consider using [Heroku Bouncer](https://github.com/heroku/heroku-bouncer) instead.
12
+ This is intended for apps already using OmniAuth, for apps that authenticate
13
+ against more than one service (eg: Heroku and GitHub), or apps that have
14
+ specific needs on session management. If your app doesn't fall in any of these
15
+ you should consider using [Heroku Bouncer][heroku-bouncer] instead.
16
+
17
+ [heroku-bouncer]: https://github.com/heroku/heroku-bouncer
10
18
 
11
19
 
12
20
  ## Configuration
@@ -15,67 +23,117 @@ OmniAuth works as a Rack middleware. Mount this Heroku adapter with:
15
23
 
16
24
  ```ruby
17
25
  use OmniAuth::Builder do
18
- provider :heroku, ENV['HEROKU_OAUTH_ID'], ENV['HEROKU_OAUTH_SECRET']
26
+ provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET")
19
27
  end
20
28
  ```
21
29
 
22
- Obtain a `HEROKU_OAUTH_ID` and `HEROKU_OAUTH_SECRET` by creating a client with the [Heroku OAuth CLI plugin](https://github.com/heroku/heroku-oauth).
30
+ Obtain a `HEROKU_OAUTH_ID` and `HEROKU_OAUTH_SECRET` by creating a client with
31
+ the [Heroku OAuth CLI plugin](https://github.com/heroku/heroku-oauth).
23
32
 
24
- Your Heroku OAuth client should be set to receive callbacks on `/auth/heroku/callback`.
33
+ Your Heroku OAuth client should be set to receive callbacks on
34
+ `/auth/heroku/callback`.
25
35
 
26
36
 
27
37
  ## Usage
28
38
 
29
39
  Initiate the OAuth flow sending users to `/auth/heroku`.
30
40
 
31
- Once the authorization flow is complete and the user is bounced back to your application, check `env["omniauth.auth"]["credentials"]`. It contains both a refresh token and an access token (identified just as `"token"`) to the account.
41
+ Once the authorization flow is complete and the user is bounced back to your
42
+ application, check `env["omniauth.auth"]["credentials"]`. It contains both a
43
+ refresh token and an access token (identified just as `"token"`) to the
44
+ account.
45
+
46
+ We recommend using this access token together with
47
+ the [Heroku Platform API gem][heroku-ruby-client] to make API calls on behalf of the user.
32
48
 
33
- We recommend using this access token together with [Heroku.rb](https://github.com/heroku/heroku.rb) to make API calls on behalf of the user.
49
+ [heroku-ruby-client]: https://github.com/heroku/platform-api
34
50
 
35
51
  Refer to the examples below to see how these work.
36
52
 
37
53
 
38
54
  ### Basic account information
39
55
 
40
- If you want this middleware to fetch additional Heroku account information like the user email address and name, use the `fetch_info` option, like:
56
+ If you want this middleware to fetch additional Heroku account information like
57
+ the user email address and name, use the `fetch_info` option, like:
41
58
 
42
59
  ```ruby
43
60
  use OmniAuth::Builder do
44
- provider :heroku, ENV['HEROKU_OAUTH_ID'], ENV['HEROKU_OAUTH_SECRET'],
61
+ provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET"),
45
62
  fetch_info: true
46
63
  end
47
64
  ```
48
65
 
49
- This sets name and email in the [omniauth auth hash](https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema). You can access it from your app via `env["omniauth.auth"]["info"]`.
66
+ This sets name and email in the [omniauth auth hash][auth-hash]. You can access
67
+ it from your app via `env["omniauth.auth"]["info"]`.
68
+
69
+ [auth-hash]: https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema
70
+
71
+ It will also add [additional Heroku account info][platform-api] to
72
+ `env["omniauth.auth"]["extra"]`.
50
73
 
51
- It will also add [additional Heroku account info](https://devcenter.heroku.com/articles/platform-api-reference#account) to `env["omniauth.auth"]["extra"]`.
74
+ [platform-api]: https://devcenter.heroku.com/articles/platform-api-reference#account
52
75
 
53
76
  ### OAuth scopes
54
77
 
55
- [Heroku supports different OAuth scopes](https://devcenter.heroku.com/articles/oauth#scopes). By default this strategy will request global access to the account, but you're encouraged to request for less permissions when possible.
78
+ [Heroku supports different OAuth scopes][oauth-scopes]. By default this
79
+ strategy will request global access to the account, but you're encouraged to
80
+ request for less permissions when possible.
81
+
82
+ [oauth-scopes]: https://devcenter.heroku.com/articles/oauth#scopes
56
83
 
57
84
  To do so, configure it like:
58
85
 
59
86
  ```ruby
60
87
  use OmniAuth::Builder do
61
- provider :heroku, ENV['HEROKU_OAUTH_ID'], ENV['HEROKU_OAUTH_SECRET'],
88
+ provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET"),
62
89
  scope: "identity"
63
90
  end
64
91
  ```
65
92
 
66
93
  This will trim down the permissions associated to the access token given back to you.
67
94
 
95
+ The OAuth scope can also be decided dynamically at runtime.
96
+ For example, you could use a `scope` parameter from the request, if it exists, with a default value if it does not:
97
+
98
+ ```ruby
99
+ use OmniAuth::Builder do
100
+ provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET"),
101
+ scope: ->(env) { Rack::Request.new(env).params["scope"] || "identity" }
102
+ end
103
+ ```
104
+
105
+ #### Upgrading to 1.0+
106
+
107
+ Versions before `1.0` allowed you to pass `:scope` option as a block, just as today.
108
+ However, that block received a `Rack::Request` instance, rather than the `Rack` `env`.
109
+ If you used the `Rack::Request` argument in your `:scope` block you can update your code to create a new instance, from the `env`.
110
+
111
+ For example, `< 1.0` code that looked like this:
112
+
113
+ ```ruby
114
+ use OmniAuth::Builder do
115
+ provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET"),
116
+ scope: ->(request) { request.params["scope"] }
117
+ end
118
+ ```
119
+
120
+ need to be updated to something like this:
121
+
122
+ ```ruby
123
+ use OmniAuth::Builder do
124
+ provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET"),
125
+ scope: ->(env) { Rack::Request.new(env).params["scope"] }
126
+ end
127
+ ```
68
128
 
69
129
  ## Example - Sinatra
70
130
 
71
131
  ```ruby
72
132
  class Myapp < Sinatra::Application
73
- configure do
74
- enable :sessions
75
- end
133
+ use Rack::Session::Cookie, secret: ENV.fetch("SESSION_SECRET")
76
134
 
77
135
  use OmniAuth::Builder do
78
- provider :heroku, ENV["HEROKU_OAUTH_ID"], ENV["HEROKU_OAUTH_SECRET"]
136
+ provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET")
79
137
  end
80
138
 
81
139
  get "/" do
@@ -83,20 +141,28 @@ class Myapp < Sinatra::Application
83
141
  end
84
142
 
85
143
  get "/auth/heroku/callback" do
86
- access_token = env['omniauth.auth']['credentials']['token']
87
- heroku_api = Heroku::API.new(api_key: access_token)
88
- "You have #{heroku_api.get_apps.body.size} apps"
144
+ access_token = env["omniauth.auth"]["credentials"]["token"]
145
+ # DO NOT store this token in an unencrypted cookie session
146
+ # Please read "A note on security" below!
147
+ heroku = PlatformAPI.connect_oauth(access_token)
148
+ "You have #{heroku.app.list.count} apps"
89
149
  end
90
150
  end
91
151
  ```
92
152
 
153
+ Note that we're explicitly calling `Rack::Session::Cookie` with a secret. Using
154
+ `enable :sessions` is not recommended because the secret is generated randomly,
155
+ and not reused across processes – so your users can lose their session whenever
156
+ your app restarts.
157
+
158
+
93
159
  ## Example - Rails
94
160
 
95
161
  Under `config/initializers/omniauth.rb`:
96
162
 
97
163
  ```ruby
98
164
  Rails.application.config.middleware.use OmniAuth::Builder do
99
- provider :heroku, ENV['HEROKU_OAUTH_ID'], ENV['HEROKU_OAUTH_SECRET']
165
+ provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET")
100
166
  end
101
167
  ```
102
168
 
@@ -118,9 +184,11 @@ class SessionsController < ApplicationController
118
184
  end
119
185
 
120
186
  def create
121
- access_token = request.env['omniauth.auth']['credentials']['token']
122
- heroku_api = Heroku::API.new(api_key: access_token)
123
- @apps = heroku_api.get_apps.body
187
+ access_token = request.env["omniauth.auth"]["credentials"]["token"]
188
+ # DO NOT store this token in an unencrypted cookie session
189
+ # Please read "A note on security" below!
190
+ heroku = PlatformAPI.connect_oauth(access_token)
191
+ @apps = heroku.app.list
124
192
  end
125
193
  end
126
194
  ```
@@ -139,11 +207,16 @@ And view:
139
207
 
140
208
  ## A note on security
141
209
 
142
- Be careful if you intend to store access tokens in cookie-based sessions.
210
+ **Make sure your cookie session is encrypted before storing sensitive
211
+ information on it, like access tokens**. [encrypted_cookie][encrypted-cookie]
212
+ is a popular gem to do that in Ruby.
143
213
 
144
- Many web frameworks offer protection against session tampering, but still store sessions with no encryption. This allows attackers with some access to the user session to obtain valuable information from cookies.
214
+ [encrypted-cookie]: https://github.com/cvonkleist/encrypted_cookie
145
215
 
146
- Rails, Sinatra and others can be configured to encrypt cookies, but don't do it by default. So make sure to encrypt cookie-based sessions before storing confidential data on it!
216
+ Both Rails and Sinatra take a cookie secret, but that is only used to protect
217
+ against tampering; any information stored on standard cookie sessions can
218
+ easily be read from the client side, which can be further exploited to leak
219
+ credentials off your app.
147
220
 
148
221
 
149
222
  ## Meta
data/bin/rake ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rake' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rake", "rake")
data/bin/rspec ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rspec-core", "rspec")
@@ -1 +1,2 @@
1
- require 'omniauth/strategies/heroku'
1
+ require "omniauth/heroku/version"
2
+ require "omniauth/strategies/heroku"
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OmniAuth
4
+ module Heroku
5
+ VERSION = "1.0.0"
6
+ end
7
+ end
@@ -1,20 +1,25 @@
1
- require 'omniauth-oauth2'
1
+ # frozen_string_literal: true
2
+
3
+ require "omniauth-oauth2"
2
4
 
3
5
  module OmniAuth
4
6
  module Strategies
5
7
  class Heroku < OmniAuth::Strategies::OAuth2
6
- AuthUrl = ENV["HEROKU_AUTH_URL"] || "https://id.heroku.com"
7
- ApiUrl = ENV["HEROKU_API_URL"] || "https://api.heroku.com"
8
+ # This style of overriding the default means it can only be done when the class is loaded.
9
+ # Which is problematic for testing, and a bit against the grain of how the base class
10
+ # expects this to work, where consumers would explicitly override by passing in the option.
11
+ AUTH_URL = ENV.fetch("HEROKU_AUTH_URL", "https://id.heroku.com")
12
+ private_constant :AUTH_URL
8
13
 
9
- option :client_options, {
10
- site: AuthUrl,
11
- authorize_url: "#{AuthUrl}/oauth/authorize",
12
- token_url: "#{AuthUrl}/oauth/token"
13
- }
14
+ option(:client_options, {
15
+ site: AUTH_URL,
16
+ authorize_url: "#{AUTH_URL}/oauth/authorize",
17
+ token_url: "#{AUTH_URL}/oauth/token"
18
+ })
14
19
 
15
- # whether we should make another API call to Heroku to fetch
20
+ # Configure whether we make another API call to Heroku to fetch
16
21
  # additional account info like the real user name and email
17
- option :fetch_info
22
+ option :fetch_info, false
18
23
 
19
24
  uid do
20
25
  access_token.params["user_id"]
@@ -22,17 +27,16 @@ module OmniAuth
22
27
 
23
28
  info do
24
29
  if options.fetch_info
25
- email_hash = Digest::MD5.hexdigest(account_info['email'].to_s)
26
- default_image_url = "https://dashboard.heroku.com/ninja-avatar-48x48.png"
27
- image_url = "https://secure.gravatar.com/avatar/#{email_hash}.png?d=#{default_image_url}"
30
+ email_hash = Digest::MD5.hexdigest(account_info["email"].to_s)
31
+ image_url = "https://secure.gravatar.com/avatar/#{email_hash}.png?d=#{DEFAULT_IMAGE_URL}"
28
32
 
29
33
  {
30
- name: account_info["name"],
34
+ name: account_info["name"],
31
35
  email: account_info["email"],
32
- image: image_url,
36
+ image: image_url
33
37
  }
34
38
  else
35
- { name: "Heroku user" } # only mandatory field
39
+ {name: "Heroku user"} # only mandatory field
36
40
  end
37
41
  end
38
42
 
@@ -44,17 +48,50 @@ module OmniAuth
44
48
  end
45
49
  end
46
50
 
51
+ # override method in OmniAuth::Strategies::OAuth2 to error
52
+ # when we don't have a client_id or secret:
53
+ def request_phase
54
+ if missing_client_id?
55
+ fail!(:missing_client_id)
56
+ elsif missing_client_secret?
57
+ fail!(:missing_client_secret)
58
+ else
59
+ super
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ DEFAULT_API_URL = "https://api.heroku.com"
66
+ private_constant :DEFAULT_API_URL
67
+
68
+ DEFAULT_IMAGE_URL = "https://dashboard.heroku.com/ninja-avatar-48x48.png"
69
+ private_constant :DEFAULT_IMAGE_URL
70
+
47
71
  def account_info
48
72
  @account_info ||= MultiJson.decode(heroku_api.get("/account").body)
49
73
  end
50
74
 
75
+ def api_url
76
+ @api_url ||= ENV.fetch("HEROKU_API_URL", DEFAULT_API_URL)
77
+ end
78
+
51
79
  def heroku_api
52
80
  @heroku_api ||= Faraday.new(
53
- url: ApiUrl,
81
+ url: api_url,
54
82
  headers: {
55
83
  "Accept" => "application/vnd.heroku+json; version=3",
56
- "Authorization" => "Bearer #{access_token.token}",
57
- })
84
+ "Authorization" => "Bearer #{access_token.token}"
85
+ }
86
+ )
87
+ end
88
+
89
+ def missing_client_id?
90
+ [nil, ""].include?(options.client_id)
91
+ end
92
+
93
+ def missing_client_secret?
94
+ [nil, ""].include?(options.client_secret)
58
95
  end
59
96
  end
60
97
  end
@@ -1,16 +1,39 @@
1
- Gem::Specification.new do |gem|
2
- gem.authors = ["Pedro Belo"]
3
- gem.email = ["pedro@heroku.com"]
4
- gem.description = %q{OmniAuth strategy for Heroku.}
5
- gem.summary = %q{OmniAuth strategy for Heroku.}
6
- gem.homepage = "https://github.com/heroku/omniauth-heroku"
1
+ require File.expand_path("lib/omniauth/heroku/version", __dir__)
7
2
 
8
- gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
9
- gem.files = `git ls-files`.split("\n")
10
- gem.name = "omniauth-heroku"
11
- gem.require_paths = ["lib"]
12
- gem.version = "0.2.0.pre"
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "omniauth-heroku"
5
+ spec.version = OmniAuth::Heroku::VERSION
6
+ spec.authors = ["Pedro Belo"]
7
+ spec.email = ["pedro@heroku.com"]
13
8
 
14
- gem.add_dependency 'omniauth', '~> 1.2'
15
- gem.add_dependency 'omniauth-oauth2', '~> 1.2'
9
+ spec.summary = "OmniAuth strategy for Heroku."
10
+ spec.description = "OmniAuth strategy for Heroku, for apps already using OmniAuth that authenticate against more than one service (eg: Heroku and GitHub), or apps that have specific needs on session management."
11
+ spec.homepage = "https://github.com/heroku/omniauth-heroku"
12
+ spec.license = "MIT"
13
+
14
+ spec.metadata = {
15
+ "homepage_uri" => spec.homepage,
16
+ "source_code_uri" => spec.homepage,
17
+ "bug_tracker_uri" => "#{spec.homepage}/issues",
18
+ "changelog_uri" => "#{spec.homepage}/blob/master/CHANGELOG.md"
19
+ }
20
+
21
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = []
30
+ spec.require_paths = ["lib"]
31
+
32
+ spec.add_runtime_dependency("omniauth", [">= 1.9", "< 3"])
33
+ spec.add_runtime_dependency("omniauth-oauth2", "~> 1.7")
34
+
35
+ spec.add_development_dependency("multi_json", "~> 1.12")
36
+ spec.add_development_dependency("rake", "~> 13.0")
37
+ spec.add_development_dependency("rspec", "~> 3.4")
38
+ spec.add_development_dependency("webmock", "~> 3.13")
16
39
  end
metadata CHANGED
@@ -1,82 +1,155 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-heroku
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0.pre
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pedro Belo
8
- autorequire:
9
- bindir: bin
8
+ autorequire:
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2014-09-11 00:00:00.000000000 Z
11
+ date: 2021-07-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: omniauth
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.2'
19
+ version: '1.9'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '3'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - ~>
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1.9'
30
+ - - "<"
25
31
  - !ruby/object:Gem::Version
26
- version: '1.2'
32
+ version: '3'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: omniauth-oauth2
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
- - - ~>
37
+ - - "~>"
32
38
  - !ruby/object:Gem::Version
33
- version: '1.2'
39
+ version: '1.7'
34
40
  type: :runtime
35
41
  prerelease: false
36
42
  version_requirements: !ruby/object:Gem::Requirement
37
43
  requirements:
38
- - - ~>
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.7'
47
+ - !ruby/object:Gem::Dependency
48
+ name: multi_json
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.12'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.12'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '13.0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
39
73
  - !ruby/object:Gem::Version
40
- version: '1.2'
41
- description: OmniAuth strategy for Heroku.
74
+ version: '13.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.4'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '3.4'
89
+ - !ruby/object:Gem::Dependency
90
+ name: webmock
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.13'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.13'
103
+ description: 'OmniAuth strategy for Heroku, for apps already using OmniAuth that authenticate
104
+ against more than one service (eg: Heroku and GitHub), or apps that have specific
105
+ needs on session management.'
42
106
  email:
43
107
  - pedro@heroku.com
44
108
  executables: []
45
109
  extensions: []
46
110
  extra_rdoc_files: []
47
111
  files:
48
- - .gitignore
49
- - .rspec
50
- - .travis.yml
112
+ - ".github/workflows/ci.yml"
113
+ - ".gitignore"
114
+ - ".rspec"
115
+ - CHANGELOG.md
51
116
  - Gemfile
117
+ - Gemfile-omniauth1
118
+ - Gemfile-omniauth2
119
+ - LICENSE
52
120
  - README.md
53
121
  - Rakefile
122
+ - bin/rake
123
+ - bin/rspec
54
124
  - lib/omniauth-heroku.rb
125
+ - lib/omniauth/heroku/version.rb
55
126
  - lib/omniauth/strategies/heroku.rb
56
127
  - omniauth-heroku.gemspec
57
- - spec/omniauth_heroku_spec.rb
58
- - spec/spec_helper.rb
59
128
  homepage: https://github.com/heroku/omniauth-heroku
60
- licenses: []
61
- metadata: {}
62
- post_install_message:
129
+ licenses:
130
+ - MIT
131
+ metadata:
132
+ homepage_uri: https://github.com/heroku/omniauth-heroku
133
+ source_code_uri: https://github.com/heroku/omniauth-heroku
134
+ bug_tracker_uri: https://github.com/heroku/omniauth-heroku/issues
135
+ changelog_uri: https://github.com/heroku/omniauth-heroku/blob/master/CHANGELOG.md
136
+ post_install_message:
63
137
  rdoc_options: []
64
138
  require_paths:
65
139
  - lib
66
140
  required_ruby_version: !ruby/object:Gem::Requirement
67
141
  requirements:
68
- - - ! '>='
142
+ - - ">="
69
143
  - !ruby/object:Gem::Version
70
- version: '0'
144
+ version: 2.3.0
71
145
  required_rubygems_version: !ruby/object:Gem::Requirement
72
146
  requirements:
73
- - - ! '>'
147
+ - - ">="
74
148
  - !ruby/object:Gem::Version
75
- version: 1.3.1
149
+ version: '0'
76
150
  requirements: []
77
- rubyforge_project:
78
- rubygems_version: 2.0.7
79
- signing_key:
151
+ rubygems_version: 3.2.14
152
+ signing_key:
80
153
  specification_version: 4
81
154
  summary: OmniAuth strategy for Heroku.
82
155
  test_files: []
data/.travis.yml DELETED
@@ -1,14 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.1.2
4
- - 2.1.0
5
- - 1.9.3
6
- cache: bundler
7
- notifications:
8
- hipchat:
9
- rooms:
10
- - 5bc7785d2feb4f25901124279daede@API
11
- template:
12
- - '%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message} (<a href="%{build_url}">Details</a> | <a href="%{compare_url}">Change view</a>)'
13
- format: html
14
- script: bundle exec rake
@@ -1,78 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe OmniAuth::Strategies::Heroku do
4
- before do
5
- @token = "6e441b93-4c6d-4613-abed-b9976e7cff6c"
6
- @user_id = "ddc4beff-f08f-4856-99d2-ba5ac63c3eb9"
7
-
8
- # stub the API call made by the strategy to start the oauth dance
9
- stub_request(:post, "https://id.heroku.com/oauth/token").
10
- to_return(
11
- headers: { "Content-Type" => "application/json" },
12
- body: MultiJson.encode(
13
- access_token: @token,
14
- expires_in: 3600,
15
- user_id: @user_id))
16
- end
17
-
18
- it "redirects to start the OAuth flow" do
19
- get "/auth/heroku"
20
- assert_equal 302, last_response.status
21
- redirect = URI.parse(last_response.headers["Location"])
22
- redirect_params = CGI::parse(redirect.query)
23
- assert_equal "https", redirect.scheme
24
- assert_equal "id.heroku.com", redirect.host
25
- assert_equal [ENV["HEROKU_OAUTH_ID"]], redirect_params["client_id"]
26
- assert_equal ["code"], redirect_params["response_type"]
27
- assert_equal ["http://example.org/auth/heroku/callback"],
28
- redirect_params["redirect_uri"]
29
- end
30
-
31
- it "receives the callback" do
32
- # start the callback, get the session state
33
- get "/auth/heroku"
34
- assert_equal 302, last_response.status
35
- state = last_response.headers["Location"].match(/state=([\w\d]+)/)[1]
36
-
37
- # trigger the callback setting the state as a param and in the session
38
- get "/auth/heroku/callback", { "state" => state },
39
- { "rack.session" => { "omniauth.state" => state }}
40
- assert_equal 200, last_response.status
41
-
42
- omniauth_env = MultiJson.decode(last_response.body)
43
- assert_equal "heroku", omniauth_env["provider"]
44
- assert_equal @user_id, omniauth_env["uid"]
45
- assert_equal "Heroku user", omniauth_env["info"]["name"]
46
- end
47
-
48
- it "fetches additional info when requested" do
49
- # change the app being tested:
50
- @app = make_app(fetch_info: true)
51
-
52
- # stub the API call to heroku
53
- account_info = {
54
- "email" => "john@example.org",
55
- "name" => "John"
56
- }
57
- stub_request(:get, "https://api.heroku.com/account").
58
- with(headers: { "Authorization" => "Bearer #{@token}" }).
59
- to_return(body: MultiJson.encode(account_info))
60
-
61
- # do the oauth dance
62
- get "/auth/heroku"
63
- assert_equal 302, last_response.status
64
- state = last_response.headers["Location"].match(/state=([\w\d]+)/)[1]
65
-
66
- get "/auth/heroku/callback", { "state" => state },
67
- { "rack.session" => { "omniauth.state" => state }}
68
- assert_equal 200, last_response.status
69
-
70
- # now make sure there's additional info in the omniauth env
71
- omniauth_env = MultiJson.decode(last_response.body)
72
- assert_equal "heroku", omniauth_env["provider"]
73
- assert_equal @user_id, omniauth_env["uid"]
74
- assert_equal "john@example.org", omniauth_env["info"]["email"]
75
- assert_equal "John", omniauth_env["info"]["name"]
76
- assert_equal account_info, omniauth_env["extra"]
77
- end
78
- end
data/spec/spec_helper.rb DELETED
@@ -1,48 +0,0 @@
1
- ENV["SESSION_SECRET"] = "abcdefghjij"
2
- ENV["HEROKU_OAUTH_ID"] = "12345"
3
- ENV["HEROKU_OAUTH_SECRET"] = "klmnopqrstu"
4
-
5
- require "rubygems"
6
- require "bundler"
7
- Bundler.setup(:default, :test)
8
- require "omniauth/strategies/heroku"
9
-
10
- require "cgi"
11
- require "rspec"
12
- require "rack/test"
13
- require "sinatra"
14
- require "webmock/rspec"
15
-
16
- Dir["./spec/support/*.rb"].each { |f| require f }
17
-
18
- WebMock.disable_net_connect!
19
-
20
- OmniAuth.config.logger = Logger.new(StringIO.new)
21
-
22
- RSpec.configure do |config|
23
- config.include Rack::Test::Methods
24
- config.expect_with :minitest
25
-
26
- def app
27
- @app || make_app
28
- end
29
-
30
- def make_app(omniauth_heroku_options={})
31
- Sinatra.new do
32
- configure do
33
- enable :sessions
34
- set :show_exceptions, false
35
- set :session_secret, ENV["SESSION_SECRET"]
36
- end
37
-
38
- use OmniAuth::Builder do
39
- provider :heroku, ENV["HEROKU_OAUTH_ID"], ENV["HEROKU_OAUTH_SECRET"],
40
- omniauth_heroku_options
41
- end
42
-
43
- get "/auth/heroku/callback" do
44
- MultiJson.encode(env['omniauth.auth'])
45
- end
46
- end
47
- end
48
- end