keycloak_oauth 0.1.10 → 2.0.0

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
  SHA256:
3
- metadata.gz: 4ff0dc0f042c247d145da35d78002bd2df0661c2715961e613af8d3fdc29f4c7
4
- data.tar.gz: 8b388dd1ba17fa13d28963e6b358de48dc5e714a886e705842ad45020bb9b0c5
3
+ metadata.gz: baa20f03dc097cf9b5f18e60f1cd860e3590fa2eafe097989d39d1b29690dd57
4
+ data.tar.gz: 477b1887a6020aa95bd7e680bf1abe508ad90b99cc480606fdd5daec81adf210
5
5
  SHA512:
6
- metadata.gz: 1bde5d1f50e865d856c755af7ab87a0f5e93697941276cde3bde1d92d20f6551ba9a5d412dd4c1e41c680f34f4bbeb05ff81c39363a10ed62fd7ee15cfb6892b
7
- data.tar.gz: 13d1228bce48b5fffa1097d36726a3e5f1bcb0867f294b83d097a23422c81ef7f7f548224789a2b156c207c2767d9fcc51e2431c75cf58e570f1434494832e3b
6
+ metadata.gz: a5b936cdf70211176742efcad5d1b799d6c72ecc1047c141e07c55ddb6c1b33985879d018616f30ab6ce7bb9b4e2be970977c4a1bcecb417bcf0ebd9e0787d68
7
+ data.tar.gz: 6f99f5fd86bff651312a0477ca719fb227ae1b5a960c9ebf066cb7e3a2d7a150f1d42a69c0df25efc6ccd78fd733ab220982e053e73202dfadf87d9268c8a1e5
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # KeycloakOauth
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/keycloak_oauth`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ [Keycloak](https://www.keycloak.org) integration for Ruby on Rails.
6
4
 
7
5
  ## Installation
8
6
 
@@ -24,6 +22,12 @@ Or install it yourself as:
24
22
 
25
23
  ### Using `keycloak_oauth` in a Ruby on Rails app
26
24
 
25
+ Unless you plan to overwrite the oauth callback controller (see further below), mount the Rails engine into your application by specifying the following in `config/routes.rb`
26
+
27
+ ```ruby
28
+ mount KeycloakOauth::Engine => "/keycloak_oauth"
29
+ ```
30
+
27
31
  The configuration must be defined in the app by initialising the relevant attributes within a configuration block. For example, you could add an initializer script called `keycloak_oauth.rb` holding the following code:
28
32
 
29
33
  ```ruby
@@ -38,13 +42,22 @@ end
38
42
  This then allows you to access the `KeycloakOauth` APIs:
39
43
  `KeycloakOauth.connection.authorization_endpoint`
40
44
 
41
- You can allow the user to log in with Keycloak by adding adding a link that points to `KeycloakOauth.connection.authorization_endpoint`:
45
+ Ensure you have `default_url_options` set. Here
46
+ is an example of `default_url_options` appropriate for a development environment
47
+ in `config/environments/development.rb`:
48
+
49
+ ```ruby
50
+ config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
51
+ ```
52
+
53
+ You can allow the user to log in with Keycloak by adding a link that points to `KeycloakOauth.connection.authorization_endpoint`:
42
54
  e.g.
43
- `<%= link_to 'Login with Keycloak', KeycloakOauth.connection.authorization_endpoint %>`
55
+ `<%= link_to 'Login with Keycloak', KeycloakOauth.connection.authorization_endpoint(options: { redirect_uri: keycloak_oauth.oauth2_url }) %>`
56
+
57
+ Once authentication is performed, the access and refresh tokens are stored in the session and can be used in your app as wished. As the session can become larger than we can store in a cookie (`CookieOverflow` exception), we recommend to use [activerecord-session_store](https://github.com/rails/activerecord-session_store).
44
58
 
45
- Once authentication is performed, the access and refresh tokens are stored in the session and can be used in your app as wished.
59
+ ### Customising redirect URIs
46
60
 
47
- ***Customising redirect URIs***
48
61
  There are situations where you would want to customise the oauth2 route (e.g. to use a localised version of the callback URL).
49
62
  In this case, you can do the following:
50
63
  - add a controller to your app: e.g. `CallbackOverrides`
@@ -64,7 +77,7 @@ If you need the user to be redirected to something other than the root path, you
64
77
  3. In the method, perform whatever logic you need to return the right path e.g.
65
78
  ```ruby
66
79
  def after_sign_in_path
67
- my_custom_path
80
+ main_app.my_custom_path
68
81
  end
69
82
  ```
70
83
  4. Tell the gem where you've overridden the paths by setting the following config in your configuration initializer file:
@@ -112,7 +125,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
112
125
 
113
126
  ## Contributing
114
127
 
115
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/keycloak_oauth. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/keycloak_oauth/blob/master/CODE_OF_CONDUCT.md).
128
+ Bug reports and pull requests are welcome on GitHub at https://github.com/simplificator/keycloak_oauth. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/simplificator/keycloak_oauth/blob/master/CODE_OF_CONDUCT.md).
116
129
 
117
130
 
118
131
  ## License
@@ -121,4 +134,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
121
134
 
122
135
  ## Code of Conduct
123
136
 
124
- Everyone interacting in the KeycloakOauth project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/keycloak_oauth/blob/master/CODE_OF_CONDUCT.md).
137
+ Everyone interacting in the KeycloakOauth project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/simplificator/keycloak_oauth/blob/master/CODE_OF_CONDUCT.md).
@@ -12,7 +12,7 @@ module KeycloakOauth
12
12
  authentication_service.authenticate
13
13
  map_authenticatable_if_implemented(session)
14
14
 
15
- redirect_to self.class.method_defined?(:after_sign_in_path) ? after_sign_in_path(request) : '/'
15
+ redirect_to self.class.method_defined?(:after_sign_in_path) ? after_sign_in_path(request) : main_app.root_path
16
16
  end
17
17
 
18
18
  private
@@ -24,8 +24,6 @@ module KeycloakOauth
24
24
  def map_authenticatable_if_implemented(request)
25
25
  if self.class.method_defined?(:map_authenticatable)
26
26
  map_authenticatable(request)
27
- else
28
- raise NotImplementedError.new('User mapping must be handled by the host app. See README for more information.')
29
27
  end
30
28
  end
31
29
 
@@ -36,7 +34,7 @@ module KeycloakOauth
36
34
  main_app.url_for(only_path: false, overwrite_params: nil)
37
35
  rescue ActionController::UrlGenerationError
38
36
  # If the host app does not override the oauth2 path, use the engine's path.
39
- oauth2_path
37
+ oauth2_url
40
38
  end
41
39
  end
42
40
  end
@@ -1,31 +1,24 @@
1
1
  module KeycloakOauth
2
- class AuthenticationService
3
- ACCESS_TOKEN_KEY = 'access_token'.freeze
4
- REFRESH_TOKEN_KEY = 'refresh_token'.freeze
2
+ class AuthenticationService < AuthenticationServiceBase
5
3
 
6
- attr_reader :session, :authentication_params
4
+ attr_reader :authentication_params
7
5
 
8
- def initialize(authentication_params:, session:)
6
+ def initialize(session:, authentication_params:)
9
7
  @authentication_params = authentication_params
10
- @session = session
11
- end
12
-
13
- def authenticate
14
- post_token_service = KeycloakOauth::PostTokenService.new(
15
- connection: KeycloakOauth.connection,
16
- request_params: authentication_params
17
- )
18
- post_token_service.perform
19
- store_credentials(post_token_service)
8
+ super session: session
20
9
  end
21
10
 
22
11
  private
23
12
 
24
- def store_credentials(post_token_service)
25
- response_hash = post_token_service.parsed_response_body
13
+ def post_service_name
14
+ KeycloakOauth::PostAuthorizationCodeService
15
+ end
26
16
 
27
- session[:access_token] = response_hash[ACCESS_TOKEN_KEY]
28
- session[:refresh_token] = response_hash[REFRESH_TOKEN_KEY]
17
+ def post_service_arguments
18
+ {
19
+ connection: KeycloakOauth.connection,
20
+ request_params: authentication_params
21
+ }
29
22
  end
30
23
  end
31
24
  end
@@ -0,0 +1,42 @@
1
+ module KeycloakOauth
2
+ class AuthenticationServiceBase
3
+ ACCESS_TOKEN_KEY = 'access_token'.freeze
4
+ ACCESS_TOKEN_EXPIRES_IN = 'expires_in'.freeze
5
+ REFRESH_TOKEN_KEY = 'refresh_token'.freeze
6
+ REFRESH_TOKEN_EXPIRES_IN = 'refresh_expires_in'.freeze
7
+
8
+ attr_reader :session
9
+
10
+ def initialize(session:)
11
+ @session = session
12
+ end
13
+
14
+ def authenticate
15
+ request_time = Time.zone.now
16
+ post_token_service = post_service_name.new(**post_service_arguments)
17
+ post_token_service.perform
18
+ store_credentials_in_session(post_token_service, request_time)
19
+ end
20
+
21
+ private
22
+
23
+ def post_service_name
24
+ raise "Implement in subclass"
25
+ end
26
+
27
+ def post_service_arguments
28
+ raise "Implement in subclass"
29
+ end
30
+
31
+
32
+ def store_credentials_in_session(post_token_service, request_time)
33
+ response_hash = post_token_service.parsed_response_body
34
+
35
+ session[:access_token] = response_hash[ACCESS_TOKEN_KEY]
36
+ session[:refresh_token] = response_hash[REFRESH_TOKEN_KEY]
37
+
38
+ session[:access_token_expires_at] = request_time + response_hash[ACCESS_TOKEN_EXPIRES_IN].to_i.seconds
39
+ session[:refresh_token_expires_at] = request_time + response_hash[REFRESH_TOKEN_EXPIRES_IN].to_i.seconds
40
+ end
41
+ end
42
+ end
@@ -1,7 +1,7 @@
1
1
  require 'net/http'
2
2
 
3
3
  module KeycloakOauth
4
- class PostTokenService < KeycloakOauth::AuthorizableService
4
+ class PostAuthorizationCodeService < KeycloakOauth::AuthorizableService
5
5
  DEFAULT_GRANT_TYPE = 'authorization_code'.freeze
6
6
 
7
7
  attr_reader :request_params, :connection
@@ -0,0 +1,39 @@
1
+ require 'net/http'
2
+
3
+ module KeycloakOauth
4
+ class PostRefreshTokenService < KeycloakOauth::AuthorizableService
5
+ DEFAULT_GRANT_TYPE = 'refresh_token'.freeze
6
+
7
+ def initialize(connection:, refresh_token:)
8
+ @connection = connection
9
+ @refresh_token = refresh_token
10
+ end
11
+
12
+ def send_request
13
+ post_token
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :connection, :refresh_token
19
+
20
+ def post_token
21
+ uri = URI.parse(connection.authentication_endpoint)
22
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
23
+ request = Net::HTTP::Post.new(uri)
24
+ request.set_content_type(CONTENT_TYPE_X_WWW_FORM_URLENCODED)
25
+ request.set_form_data(token_request_params)
26
+ http.request(request)
27
+ end
28
+ end
29
+
30
+ def token_request_params
31
+ {
32
+ client_id: connection.client_id,
33
+ client_secret: connection.client_secret,
34
+ grant_type: DEFAULT_GRANT_TYPE,
35
+ refresh_token: refresh_token
36
+ }
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,21 @@
1
+ module KeycloakOauth
2
+ class RefreshAuthenticationService < AuthenticationServiceBase
3
+
4
+ def initialize(session:)
5
+ super
6
+ end
7
+
8
+ private
9
+
10
+ def post_service_name
11
+ KeycloakOauth::PostRefreshTokenService
12
+ end
13
+
14
+ def post_service_arguments
15
+ {
16
+ connection: KeycloakOauth.connection,
17
+ refresh_token: session[:refresh_token]
18
+ }
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module KeycloakOauth
2
- VERSION = "0.1.10"
2
+ VERSION = "2.0.0"
3
3
  end
metadata CHANGED
@@ -1,35 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keycloak_oauth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - simplificator
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-11-26 00:00:00.000000000 Z
11
+ date: 2022-06-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: 6.0.3
20
17
  - - ">="
21
18
  - !ruby/object:Gem::Version
22
- version: 6.0.3.2
19
+ version: '6.0'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
- - - "~>"
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activerecord-session_store
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: appraisal
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
28
53
  - !ruby/object:Gem::Version
29
- version: 6.0.3
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: combustion
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
30
59
  - - ">="
31
60
  - !ruby/object:Gem::Version
32
- version: 6.0.3.2
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
33
69
  - !ruby/object:Gem::Dependency
34
70
  name: rspec-rails
35
71
  requirement: !ruby/object:Gem::Requirement
@@ -58,6 +94,20 @@ dependencies:
58
94
  - - ">="
59
95
  - !ruby/object:Gem::Version
60
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: timecop
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'
61
111
  description:
62
112
  email:
63
113
  - dev@simplificator.com
@@ -69,12 +119,15 @@ files:
69
119
  - Rakefile
70
120
  - app/controllers/keycloak_oauth/callbacks_controller.rb
71
121
  - app/services/keycloak_oauth/authentication_service.rb
122
+ - app/services/keycloak_oauth/authentication_service_base.rb
72
123
  - app/services/keycloak_oauth/authorizable_service.rb
73
124
  - app/services/keycloak_oauth/get_users_service.rb
74
125
  - app/services/keycloak_oauth/logout_service.rb
75
- - app/services/keycloak_oauth/post_token_service.rb
126
+ - app/services/keycloak_oauth/post_authorization_code_service.rb
127
+ - app/services/keycloak_oauth/post_refresh_token_service.rb
76
128
  - app/services/keycloak_oauth/post_users_service.rb
77
129
  - app/services/keycloak_oauth/put_execute_actions_email_service.rb
130
+ - app/services/keycloak_oauth/refresh_authentication_service.rb
78
131
  - app/services/keycloak_oauth/user_info_retrieval_service.rb
79
132
  - config/routes.rb
80
133
  - lib/keycloak_oauth.rb
@@ -98,14 +151,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
98
151
  requirements:
99
152
  - - ">="
100
153
  - !ruby/object:Gem::Version
101
- version: 2.3.0
154
+ version: 2.6.0
102
155
  required_rubygems_version: !ruby/object:Gem::Requirement
103
156
  requirements:
104
157
  - - ">="
105
158
  - !ruby/object:Gem::Version
106
159
  version: '0'
107
160
  requirements: []
108
- rubygems_version: 3.1.4
161
+ rubygems_version: 3.1.6
109
162
  signing_key:
110
163
  specification_version: 4
111
164
  summary: Implementing OAuth with Keycloak in Ruby