oauth_im 0.5.0 → 0.7.1
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 +4 -4
- data/README.md +32 -14
- data/app/controllers/concerns/oauth_im/authenticable.rb +4 -1
- data/app/controllers/oauth_im/client_controller.rb +14 -40
- data/app/helpers/oauth_im/application_helper.rb +3 -2
- data/app/services/oauth_im/client.rb +66 -0
- data/app/services/oauth_im/token_decoder.rb +20 -9
- data/config/initializers/app_context.rb +29 -0
- data/config/routes.rb +1 -1
- data/lib/oauth_im/configuration.rb +1 -2
- data/lib/oauth_im/version.rb +1 -1
- data/lib/oauth_im.rb +5 -5
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a5e7322e6a158fea186973bf430407b662f5e8f9062767da8f736dfe3722fc09
|
4
|
+
data.tar.gz: c9444faa60059de5c4f29c50440e9b0eb63e77b70f644d538979a9dd71e647f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e001cb039986d3aa5d9e44730e490065b8358ee781f8857e9166d243f3c3c76108cdf689d943e7c97615880cc7761ab95cc6993a5790c5bb4923d05ef31f6f7
|
7
|
+
data.tar.gz: 82c38b140fa0191f9c4f4e0b3f150d795c1d5925b72fa078d719fae87a069c28adfd180ab38597f3addc91650c4a4a745c783f80ab28980fa80dedde7b367185
|
data/README.md
CHANGED
@@ -23,29 +23,28 @@ Once the gem is installed, add an initializer. Here is an example:
|
|
23
23
|
# config/initializers/oauth_im.rb
|
24
24
|
module OauthIm
|
25
25
|
configure do |config|
|
26
|
-
config.api_key
|
27
|
-
config.
|
28
|
-
config.client_id
|
29
|
-
config.client_secret
|
30
|
-
config.domain
|
31
|
-
config.hmac
|
32
|
-
config.iss_domain
|
33
|
-
config.
|
34
|
-
config.
|
35
|
-
config.token_url = ENV['FUSION_AUTH_TOKEN_URL'] || DEFAULT_TOKEN_URL
|
26
|
+
config.api_key = ENV['FUSION_AUTH_API_KEY']
|
27
|
+
config.callback_route = ENV['FUSION_CALLBACK_ROUTE] || DEFAULT_CALLBACK_ROUTE
|
28
|
+
config.client_id = ENV['FUSION_AUTH_CLIENT_ID']
|
29
|
+
config.client_secret = ENV['FUSION_AUTH_CLIENT_SECRET']
|
30
|
+
config.domain = ENV['FUSION_AUTH_DOMAIN']
|
31
|
+
config.hmac = ENV['FUSION_AUTH_HMAC']
|
32
|
+
config.iss_domain = ENV['FUSION_AUTH_ISS_DOMAIN']
|
33
|
+
config.authorize_url = ENV['FUSION_AUTH_AUTHORIZE_URL'] || DEFAULT_AUTHORIZE_URL
|
34
|
+
config.token_url = ENV['FUSION_AUTH_TOKEN_URL'] || DEFAULT_TOKEN_URL
|
36
35
|
end
|
37
36
|
end
|
38
37
|
```
|
39
38
|
|
40
39
|
* The `ENV` variable values can be obtained from the OAuth provider.
|
41
|
-
* The `
|
40
|
+
* The `callback_route` setting is used in two related ways:
|
42
41
|
* It [defines a route](https://github.com/illustrativemathematics/oauth_im/blob/main/config/routes.rb#L4) to the [`OAuthIm::ClientController#callback`
|
43
42
|
action](https://github.com/illustrativemathematics/oauth_im/blob/main/app/controllers/oauth_im/client_controller.rb#L7-L12).
|
44
43
|
* It defines a [callback URL](https://github.com/illustrativemathematics/oauth_im/blob/main/app/controllers/oauth_im/client_controller.rb#L69) used by the OAuth provider.
|
45
44
|
* Note that this callback URL must be whitelisted at the provider.
|
46
45
|
At FusionAuth, this is done under the `Applications|OAuth` tab.
|
47
46
|
* For instance, for the app `staging-kh-iiab.herokuapp.com`, if
|
48
|
-
`config.
|
47
|
+
`config.callback_route` is set to `callback` (the default), then
|
49
48
|
the URL `https://staging-kh-iiab.herokuapp.com/oauth_im/callback`
|
50
49
|
must be entered in the OAuth provider's list of authorized
|
51
50
|
redirect URLs.
|
@@ -79,11 +78,20 @@ some other appropriate location, e.g.:
|
|
79
78
|
class ApplicationController < ActionController::Base
|
80
79
|
include OauthIm::Authenticable
|
81
80
|
|
82
|
-
# etc.
|
81
|
+
# etc.
|
83
82
|
end
|
84
|
-
|
85
83
|
```
|
86
84
|
|
85
|
+
### Initializer
|
86
|
+
* The gem provides a single initializer, `AppContext`.
|
87
|
+
* This module is **not** name-spaced.
|
88
|
+
* It provides a single method, `provide_authentication?`, which by
|
89
|
+
default is `true`.
|
90
|
+
* Client apps can override this initializer method.
|
91
|
+
* For example, `iiab` overrides this initializer so that the
|
92
|
+
`provide_authentication?` method returns `false` unless the app is
|
93
|
+
`kh_iiab` (not `demo_im`).
|
94
|
+
|
87
95
|
## Gem Maintenance
|
88
96
|
After many false starts, this repo includes two (seemingly functional) github workflows.
|
89
97
|
|
@@ -113,3 +121,13 @@ After many false starts, this repo includes two (seemingly functional) github wo
|
|
113
121
|
this reason, you shouldn't try to force-push updates to gem version
|
114
122
|
numbers. Instead, let the automatic process manage versioning for
|
115
123
|
you.
|
124
|
+
|
125
|
+
## Version History
|
126
|
+
|
127
|
+
### 0.7.1
|
128
|
+
* Improving separation of concerns by way of a separate service object to manage oauth client.
|
129
|
+
|
130
|
+
### 0.6.0
|
131
|
+
* Remove coupling between gem and `iiab` app via the `AppContext`
|
132
|
+
module. Added default `AppContext` settings to be overridden in
|
133
|
+
client app (in this case, `iiab`).
|
@@ -12,7 +12,8 @@ module OauthIm
|
|
12
12
|
private
|
13
13
|
|
14
14
|
def authenticated?
|
15
|
-
AppContext.
|
15
|
+
AppContext.authenticated_for_specs? ||
|
16
|
+
(AppContext.provide_authentication? && logged_in?)
|
16
17
|
end
|
17
18
|
|
18
19
|
def email
|
@@ -39,6 +40,8 @@ module OauthIm
|
|
39
40
|
else
|
40
41
|
head :forbidden
|
41
42
|
end
|
43
|
+
else
|
44
|
+
AppContext.current_user
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
@@ -5,72 +5,46 @@ require 'oauth2'
|
|
5
5
|
module OauthIm
|
6
6
|
class ClientController < OauthIm::ApplicationController
|
7
7
|
def callback
|
8
|
-
session[:user_jwt] =
|
8
|
+
session[:user_jwt] = user_jwt
|
9
9
|
redirect_to main_app.root_path
|
10
10
|
rescue StandardError
|
11
11
|
head :forbidden
|
12
12
|
end
|
13
13
|
|
14
14
|
def login
|
15
|
-
redirect_to oauth_client.
|
15
|
+
redirect_to oauth_client.login_url
|
16
16
|
end
|
17
17
|
|
18
18
|
def logout
|
19
19
|
reset_session
|
20
|
-
redirect_to
|
20
|
+
redirect_to logout_url
|
21
21
|
end
|
22
22
|
|
23
23
|
def local_login
|
24
|
-
|
24
|
+
head :forbidden if Rails.env.production?
|
25
25
|
|
26
|
-
session[:userinfo] =
|
27
|
-
redirect_back
|
26
|
+
session[:userinfo] = local_login_userinfo
|
27
|
+
redirect_back fallback_location: main_app.root_path
|
28
28
|
end
|
29
29
|
|
30
30
|
def local_logout
|
31
|
+
head :forbidden if Rails.env.production?
|
32
|
+
|
31
33
|
reset_session
|
32
|
-
redirect_back
|
34
|
+
redirect_back fallback_location: main_app.root_path
|
33
35
|
end
|
34
36
|
|
35
37
|
private
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
-
"?post_logout_redirect_uri=#{post_logout_redirect_uri}" \
|
40
|
-
"&client_id=#{configuration.client_id}"
|
41
|
-
end
|
42
|
-
|
43
|
-
def post_logout_redirect_uri
|
44
|
-
@post_logout_redirect_uri ||= params[:return_to]
|
45
|
-
end
|
46
|
-
|
47
|
-
def decoded_token
|
48
|
-
@decoded_token ||= TokenDecoder.new(access_token, oauth_client.id).decode
|
49
|
-
end
|
50
|
-
|
51
|
-
def access_token
|
52
|
-
@access_token ||= response_hash[:access_token]
|
53
|
-
end
|
54
|
-
|
55
|
-
def response_hash
|
56
|
-
@response_hash ||= auth_code.get_token(params[:code]).to_hash
|
57
|
-
end
|
58
|
-
|
59
|
-
def auth_code
|
60
|
-
@auth_code ||= oauth_client.auth_code
|
61
|
-
end
|
39
|
+
delegate :logout_url, :user_jwt,
|
40
|
+
to: :oauth_client
|
62
41
|
|
63
42
|
def oauth_client
|
64
|
-
@oauth_client
|
65
|
-
configuration.client_secret,
|
66
|
-
authorize_url: configuration.authorize_url,
|
67
|
-
site: configuration.domain,
|
68
|
-
token_url: configuration.token_url,
|
69
|
-
redirect_uri: callback_url
|
43
|
+
@oauth_client ||= OauthIm::Client.new request: request
|
70
44
|
end
|
71
45
|
|
72
|
-
def
|
73
|
-
|
46
|
+
def local_login_userinfo
|
47
|
+
{ info: { email: 'local_login@example.com' } }.freeze
|
74
48
|
end
|
75
49
|
end
|
76
50
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OauthIm
|
4
|
+
class Client
|
5
|
+
attr_reader :request
|
6
|
+
|
7
|
+
def initialize(request:)
|
8
|
+
@request = request
|
9
|
+
end
|
10
|
+
|
11
|
+
def login_url
|
12
|
+
@login_url ||= auth_code.authorize_url
|
13
|
+
end
|
14
|
+
|
15
|
+
def logout_url
|
16
|
+
@logout_url ||= "#{domain}/oauth2/logout" \
|
17
|
+
"?post_logout_redirect_uri=#{return_to_url}" \
|
18
|
+
"&client_id=#{client_id}"
|
19
|
+
end
|
20
|
+
|
21
|
+
def user_jwt
|
22
|
+
@user_jwt ||= { value: decoded_token, httponly: httponly? }
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
delegate :host_with_port, :params, to: :request
|
28
|
+
delegate :configuration, to: OauthIm
|
29
|
+
delegate :authorize_url, :client_id, :client_secret, :domain, :token_url,
|
30
|
+
to: :configuration
|
31
|
+
delegate :auth_code, to: :oauth_client
|
32
|
+
|
33
|
+
def httponly?
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def return_to_url
|
38
|
+
@return_to_url ||= params.fetch :return_to
|
39
|
+
end
|
40
|
+
|
41
|
+
def redirect_url
|
42
|
+
@redirect_url ||= Engine.routes.url_helpers.callback_url(host: host_with_port)
|
43
|
+
end
|
44
|
+
|
45
|
+
def decoded_token
|
46
|
+
@decoded_token ||= TokenDecoder.new(access_token, oauth_client.id).decode
|
47
|
+
end
|
48
|
+
|
49
|
+
def access_token
|
50
|
+
@access_token ||= response_hash[:access_token]
|
51
|
+
end
|
52
|
+
|
53
|
+
def oauth_client
|
54
|
+
@oauth_client ||= ::OAuth2::Client.new client_id,
|
55
|
+
client_secret,
|
56
|
+
authorize_url: authorize_url,
|
57
|
+
site: domain,
|
58
|
+
token_url: token_url,
|
59
|
+
redirect_uri: redirect_url
|
60
|
+
end
|
61
|
+
|
62
|
+
def response_hash
|
63
|
+
@response_hash ||= auth_code.get_token(params[:code]).to_hash
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -6,7 +6,7 @@ module OauthIm
|
|
6
6
|
class TokenDecoder
|
7
7
|
attr_reader :token, :aud
|
8
8
|
|
9
|
-
|
9
|
+
DEFAULT_DECODE_ALGORITHM = 'HS256'
|
10
10
|
|
11
11
|
def initialize(token, aud)
|
12
12
|
@token = token
|
@@ -19,20 +19,31 @@ module OauthIm
|
|
19
19
|
|
20
20
|
private
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
22
|
+
delegate :configuration, to: OauthIm
|
23
|
+
delegate :hmac, :iss_domain, to: :configuration
|
25
24
|
|
26
25
|
def decoded_token
|
27
|
-
@decoded_token ||= JWT.decode token,
|
26
|
+
@decoded_token ||= JWT.decode token, hmac, true, decode_params
|
27
|
+
end
|
28
|
+
|
29
|
+
def decode_algorithm
|
30
|
+
DEFAULT_DECODE_ALGORITHM
|
31
|
+
end
|
32
|
+
|
33
|
+
def verify_iss?
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def verify_aud?
|
38
|
+
true
|
28
39
|
end
|
29
40
|
|
30
41
|
def decode_params
|
31
|
-
@decode_params ||= { verify_iss:
|
32
|
-
iss:
|
33
|
-
verify_aud:
|
42
|
+
@decode_params ||= { verify_iss: verify_iss?,
|
43
|
+
iss: iss_domain,
|
44
|
+
verify_aud: verify_aud?,
|
34
45
|
aud: aud,
|
35
|
-
algorithm:
|
46
|
+
algorithm: decode_algorithm }.freeze
|
36
47
|
end
|
37
48
|
end
|
38
49
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppContext
|
4
|
+
def self.provide_authentication?
|
5
|
+
true
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.authenticated_for_specs?
|
9
|
+
@authenticated_for_specs
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.privileged?
|
13
|
+
@privileged
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.current_user
|
17
|
+
@current_user
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.authenticate_for_specs(current_user: nil, privileged: false)
|
21
|
+
@authenticated_for_specs = true
|
22
|
+
@current_user = current_user
|
23
|
+
@privileged = privileged
|
24
|
+
yield
|
25
|
+
@privileged = false
|
26
|
+
@current_user = nil
|
27
|
+
@authenticated_for_specs = false
|
28
|
+
end
|
29
|
+
end
|
data/config/routes.rb
CHANGED
data/lib/oauth_im/version.rb
CHANGED
data/lib/oauth_im.rb
CHANGED
@@ -5,9 +5,9 @@ require 'oauth_im/engine'
|
|
5
5
|
require 'oauth_im/configuration'
|
6
6
|
|
7
7
|
module OauthIm
|
8
|
-
DEFAULT_AUTHORIZE_URL
|
9
|
-
DEFAULT_TOKEN_URL
|
10
|
-
|
8
|
+
DEFAULT_AUTHORIZE_URL = '/oauth2/authorize'
|
9
|
+
DEFAULT_TOKEN_URL = '/oauth2/token'
|
10
|
+
DEFAULT_CALLBACK_ROUTE = 'callback'
|
11
11
|
|
12
12
|
class << self
|
13
13
|
attr_reader :configuration
|
@@ -22,7 +22,7 @@ module OauthIm
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.
|
26
|
-
configuration&.
|
25
|
+
def self.callback_route
|
26
|
+
configuration&.callback_route || DEFAULT_CALLBACK_ROUTE
|
27
27
|
end
|
28
28
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oauth_im
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Connally
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jwt
|
@@ -125,8 +125,10 @@ files:
|
|
125
125
|
- app/controllers/oauth_im/application_controller.rb
|
126
126
|
- app/controllers/oauth_im/client_controller.rb
|
127
127
|
- app/helpers/oauth_im/application_helper.rb
|
128
|
+
- app/services/oauth_im/client.rb
|
128
129
|
- app/services/oauth_im/token_decoder.rb
|
129
130
|
- app/views/layouts/oauth_im/application.html.erb
|
131
|
+
- config/initializers/app_context.rb
|
130
132
|
- config/routes.rb
|
131
133
|
- lib/oauth_im.rb
|
132
134
|
- lib/oauth_im/configuration.rb
|