omniauth-heroku 0.1.1 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +132 -9
- data/lib/omniauth/strategies/heroku.rb +79 -4
- metadata +21 -30
- data/.gitignore +0 -17
- data/.rspec +0 -1
- data/Rakefile +0 -2
- data/omniauth-heroku.gemspec +0 -16
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7114a261c4657b1093fa15c002dc0c5dc501c3a147670c99b31bb82bb2173290
|
4
|
+
data.tar.gz: 409fe3bd640e82ec72fc30f92ef9a0fd383bb95260b4f1d8d7d9d070b6d325b4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 36e9c08495d7941cf3a19b8e2b972ec2d70fd992c326f88586141892c5bc445ab4ee9ff28927062d6a5babd58351f7b16fda97fcea9e5933750bc73178f5d6fd
|
7
|
+
data.tar.gz: 6d8bcd09cd0847c01f870ad2d955a90b21ac449b56ba0aafcd275790a9fc8efbca5aae86252a80f3ec916583780d352516b4065e275a9b9450c6201d034c4703
|
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,8 +1,19 @@
|
|
1
1
|
# OmniAuth Heroku
|
2
2
|
|
3
|
-
[
|
3
|
+
[![Build Status](https://github.com/heroku/omniauth-heroku/actions/workflows/ci.yml/badge.svg)](https://github.com/heroku/omniauth-heroku/actions)
|
4
4
|
|
5
|
-
|
5
|
+
[OmniAuth](https://github.com/intridea/omniauth) strategy for authenticating
|
6
|
+
Heroku users.
|
7
|
+
|
8
|
+
Mount this with your Rack application (be it Rails or Sinatra) to simplify the
|
9
|
+
[OAuth flow with Heroku](https://devcenter.heroku.com/articles/oauth).
|
10
|
+
|
11
|
+
This is intended for apps already using OmniAuth, for apps that authenticate
|
12
|
+
against more than one service (eg: Heroku and GitHub), or apps that have
|
13
|
+
specific needs on session management. If your app doesn't fall in any of these
|
14
|
+
you should consider using [Heroku Bouncer][heroku-bouncer] instead.
|
15
|
+
|
16
|
+
[heroku-bouncer]: https://github.com/heroku/heroku-bouncer
|
6
17
|
|
7
18
|
|
8
19
|
## Configuration
|
@@ -11,20 +22,116 @@ OmniAuth works as a Rack middleware. Mount this Heroku adapter with:
|
|
11
22
|
|
12
23
|
```ruby
|
13
24
|
use OmniAuth::Builder do
|
14
|
-
provider :heroku, ENV
|
25
|
+
provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET")
|
15
26
|
end
|
16
27
|
```
|
17
28
|
|
18
|
-
|
29
|
+
Obtain a `HEROKU_OAUTH_ID` and `HEROKU_OAUTH_SECRET` by creating a client with
|
30
|
+
the [Heroku OAuth CLI plugin](https://github.com/heroku/heroku-oauth).
|
31
|
+
|
32
|
+
Your Heroku OAuth client should be set to receive callbacks on
|
33
|
+
`/auth/heroku/callback`.
|
19
34
|
|
20
35
|
|
21
36
|
## Usage
|
22
37
|
|
23
38
|
Initiate the OAuth flow sending users to `/auth/heroku`.
|
24
39
|
|
25
|
-
Once the authorization flow is complete and the user is bounced back to your
|
40
|
+
Once the authorization flow is complete and the user is bounced back to your
|
41
|
+
application, check `env["omniauth.auth"]["credentials"]`. It contains both a
|
42
|
+
refresh token and an access token (identified just as `"token"`) to the
|
43
|
+
account.
|
44
|
+
|
45
|
+
We recommend using this access token together with
|
46
|
+
the [Heroku Platform API gem][heroku-ruby-client] to make API calls on behalf of the user.
|
47
|
+
|
48
|
+
[heroku-ruby-client]: https://github.com/heroku/platform-api
|
49
|
+
|
50
|
+
Refer to the examples below to see how these work.
|
51
|
+
|
52
|
+
|
53
|
+
### Basic account information
|
54
|
+
|
55
|
+
If you want this middleware to fetch additional Heroku account information like
|
56
|
+
the user email address and name, use the `fetch_info` option, like:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
use OmniAuth::Builder do
|
60
|
+
provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET"),
|
61
|
+
fetch_info: true
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
This sets name and email in the [omniauth auth hash][auth-hash]. You can access
|
66
|
+
it from your app via `env["omniauth.auth"]["info"]`.
|
67
|
+
|
68
|
+
[auth-hash]: https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema
|
69
|
+
|
70
|
+
It will also add [additional Heroku account info][platform-api] to
|
71
|
+
`env["omniauth.auth"]["extra"]`.
|
72
|
+
|
73
|
+
[platform-api]: https://devcenter.heroku.com/articles/platform-api-reference#account
|
74
|
+
|
75
|
+
### OAuth scopes
|
76
|
+
|
77
|
+
[Heroku supports different OAuth scopes][oauth-scopes]. By default this
|
78
|
+
strategy will request global access to the account, but you're encouraged to
|
79
|
+
request for less permissions when possible.
|
80
|
+
|
81
|
+
[oauth-scopes]: https://devcenter.heroku.com/articles/oauth#scopes
|
82
|
+
|
83
|
+
To do so, configure it like:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
use OmniAuth::Builder do
|
87
|
+
provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET"),
|
88
|
+
scope: "identity"
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
This will trim down the permissions associated to the access token given back
|
93
|
+
to you.
|
94
|
+
|
95
|
+
The Oauth scope can also be decided dynamically at runtime. For example, you
|
96
|
+
could use a `scope` GET parameter if it exists, and revert to a default `scope`
|
97
|
+
if it does not:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
use OmniAuth::Builder do
|
101
|
+
provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET"),
|
102
|
+
scope: ->(request) { request.params["scope"] || "identity" }
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
|
107
|
+
## Example - Sinatra
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
class Myapp < Sinatra::Application
|
111
|
+
use Rack::Session::Cookie, secret: ENV.fetch("SESSION_SECRET")
|
112
|
+
|
113
|
+
use OmniAuth::Builder do
|
114
|
+
provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET")
|
115
|
+
end
|
116
|
+
|
117
|
+
get "/" do
|
118
|
+
redirect "/auth/heroku"
|
119
|
+
end
|
26
120
|
|
27
|
-
|
121
|
+
get "/auth/heroku/callback" do
|
122
|
+
access_token = env["omniauth.auth"]["credentials"]["token"]
|
123
|
+
# DO NOT store this token in an unencrypted cookie session
|
124
|
+
# Please read "A note on security" below!
|
125
|
+
heroku = PlatformAPI.connect_oauth(access_token)
|
126
|
+
"You have #{heroku.app.list.count} apps"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
```
|
130
|
+
|
131
|
+
Note that we're explicitly calling `Rack::Session::Cookie` with a secret. Using
|
132
|
+
`enable :sessions` is not recommended because the secret is generated randomly,
|
133
|
+
and not reused across processes – so your users can lose their session whenever
|
134
|
+
your app restarts.
|
28
135
|
|
29
136
|
|
30
137
|
## Example - Rails
|
@@ -33,7 +140,7 @@ Under `config/initializers/omniauth.rb`:
|
|
33
140
|
|
34
141
|
```ruby
|
35
142
|
Rails.application.config.middleware.use OmniAuth::Builder do
|
36
|
-
provider :heroku, ENV
|
143
|
+
provider :heroku, ENV.fetch("HEROKU_OAUTH_ID"), ENV.fetch("HEROKU_OAUTH_SECRET")
|
37
144
|
end
|
38
145
|
```
|
39
146
|
|
@@ -56,8 +163,10 @@ class SessionsController < ApplicationController
|
|
56
163
|
|
57
164
|
def create
|
58
165
|
access_token = request.env['omniauth.auth']['credentials']['token']
|
59
|
-
|
60
|
-
|
166
|
+
# DO NOT store this token in an unencrypted cookie session
|
167
|
+
# Please read "A note on security" below!
|
168
|
+
heroku = PlatformAPI.connect_oauth(access_token)
|
169
|
+
@apps = heroku.app.list
|
61
170
|
end
|
62
171
|
end
|
63
172
|
```
|
@@ -74,6 +183,20 @@ And view:
|
|
74
183
|
</ul>
|
75
184
|
```
|
76
185
|
|
186
|
+
## A note on security
|
187
|
+
|
188
|
+
**Make sure your cookie session is encrypted before storing sensitive
|
189
|
+
information on it, like access tokens**. [encrypted_cookie][encrypted-cookie]
|
190
|
+
is a popular gem to do that in Ruby.
|
191
|
+
|
192
|
+
[encrypted-cookie]: https://github.com/cvonkleist/encrypted_cookie
|
193
|
+
|
194
|
+
Both Rails and Sinatra take a cookie secret, but that is only used to protect
|
195
|
+
against tampering; any information stored on standard cookie sessions can
|
196
|
+
easily be read from the client side, which can be further exploited to leak
|
197
|
+
credentials off your app.
|
198
|
+
|
199
|
+
|
77
200
|
## Meta
|
78
201
|
|
79
202
|
Released under the MIT license.
|
@@ -3,13 +3,88 @@ require 'omniauth-oauth2'
|
|
3
3
|
module OmniAuth
|
4
4
|
module Strategies
|
5
5
|
class Heroku < OmniAuth::Strategies::OAuth2
|
6
|
-
|
6
|
+
AuthUrl = ENV["HEROKU_AUTH_URL"] || "https://id.heroku.com"
|
7
|
+
ApiUrl = ENV["HEROKU_API_URL"] || "https://api.heroku.com"
|
7
8
|
|
8
9
|
option :client_options, {
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
10
|
+
site: AuthUrl,
|
11
|
+
authorize_url: "#{AuthUrl}/oauth/authorize",
|
12
|
+
token_url: "#{AuthUrl}/oauth/token"
|
12
13
|
}
|
14
|
+
|
15
|
+
# whether we should make another API call to Heroku to fetch
|
16
|
+
# additional account info like the real user name and email
|
17
|
+
option :fetch_info
|
18
|
+
|
19
|
+
uid do
|
20
|
+
access_token.params["user_id"]
|
21
|
+
end
|
22
|
+
|
23
|
+
info do
|
24
|
+
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}"
|
28
|
+
|
29
|
+
{
|
30
|
+
name: account_info["name"],
|
31
|
+
email: account_info["email"],
|
32
|
+
image: image_url,
|
33
|
+
}
|
34
|
+
else
|
35
|
+
{ name: "Heroku user" } # only mandatory field
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
extra do
|
40
|
+
if options.fetch_info
|
41
|
+
account_info
|
42
|
+
else
|
43
|
+
{}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# override method in OmniAuth::Strategies::OAuth2 to error
|
48
|
+
# when we don't have a client_id or secret:
|
49
|
+
def request_phase
|
50
|
+
if missing_client_id?
|
51
|
+
fail!(:missing_client_id)
|
52
|
+
elsif missing_client_secret?
|
53
|
+
fail!(:missing_client_secret)
|
54
|
+
else
|
55
|
+
super
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def authorize_params
|
60
|
+
super.tap do |params|
|
61
|
+
# Allow the scope to be determined dynamically based on the request.
|
62
|
+
if params.scope.respond_to?(:call)
|
63
|
+
params.scope = params.scope.call(request)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def account_info
|
69
|
+
@account_info ||= MultiJson.decode(heroku_api.get("/account").body)
|
70
|
+
end
|
71
|
+
|
72
|
+
def heroku_api
|
73
|
+
@heroku_api ||= Faraday.new(
|
74
|
+
url: ApiUrl,
|
75
|
+
headers: {
|
76
|
+
"Accept" => "application/vnd.heroku+json; version=3",
|
77
|
+
"Authorization" => "Bearer #{access_token.token}",
|
78
|
+
})
|
79
|
+
end
|
80
|
+
|
81
|
+
def missing_client_id?
|
82
|
+
[nil, ""].include?(options.client_id)
|
83
|
+
end
|
84
|
+
|
85
|
+
def missing_client_secret?
|
86
|
+
[nil, ""].include?(options.client_secret)
|
87
|
+
end
|
13
88
|
end
|
14
89
|
end
|
15
90
|
end
|
metadata
CHANGED
@@ -1,48 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omniauth-heroku
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.4.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Pedro Belo
|
9
|
-
autorequire:
|
8
|
+
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2021-07-09 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: omniauth
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
19
|
+
version: 1.9.0
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- - ~>
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
26
|
+
version: 1.9.0
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: omniauth-oauth2
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- - ~>
|
31
|
+
- - "~>"
|
36
32
|
- !ruby/object:Gem::Version
|
37
|
-
version:
|
33
|
+
version: 1.6.0
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- - ~>
|
38
|
+
- - "~>"
|
44
39
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
40
|
+
version: 1.6.0
|
46
41
|
description: OmniAuth strategy for Heroku.
|
47
42
|
email:
|
48
43
|
- pedro@heroku.com
|
@@ -50,35 +45,31 @@ executables: []
|
|
50
45
|
extensions: []
|
51
46
|
extra_rdoc_files: []
|
52
47
|
files:
|
53
|
-
-
|
54
|
-
- .rspec
|
48
|
+
- LICENSE
|
55
49
|
- README.md
|
56
|
-
- Rakefile
|
57
50
|
- lib/omniauth-heroku.rb
|
58
51
|
- lib/omniauth/strategies/heroku.rb
|
59
|
-
- omniauth-heroku.gemspec
|
60
52
|
homepage: https://github.com/heroku/omniauth-heroku
|
61
|
-
licenses:
|
62
|
-
|
53
|
+
licenses:
|
54
|
+
- MIT
|
55
|
+
metadata: {}
|
56
|
+
post_install_message:
|
63
57
|
rdoc_options: []
|
64
58
|
require_paths:
|
65
59
|
- lib
|
66
60
|
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
-
none: false
|
68
61
|
requirements:
|
69
|
-
- -
|
62
|
+
- - ">="
|
70
63
|
- !ruby/object:Gem::Version
|
71
64
|
version: '0'
|
72
65
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
66
|
requirements:
|
75
|
-
- -
|
67
|
+
- - ">="
|
76
68
|
- !ruby/object:Gem::Version
|
77
69
|
version: '0'
|
78
70
|
requirements: []
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
specification_version: 3
|
71
|
+
rubygems_version: 3.2.14
|
72
|
+
signing_key:
|
73
|
+
specification_version: 4
|
83
74
|
summary: OmniAuth strategy for Heroku.
|
84
75
|
test_files: []
|
data/.gitignore
DELETED
data/.rspec
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
--colour
|
data/Rakefile
DELETED
data/omniauth-heroku.gemspec
DELETED
@@ -1,16 +0,0 @@
|
|
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"
|
7
|
-
|
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.1.1"
|
13
|
-
|
14
|
-
gem.add_dependency 'omniauth', '~> 1.0'
|
15
|
-
gem.add_dependency 'omniauth-oauth2', '~> 1.0'
|
16
|
-
end
|