keycloak_oauth 1.1.0 → 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: a496f5188659a5cc6df091b040a10fea32e0f3f471144e3b70c61938258c03d0
4
- data.tar.gz: 594013ab742d6c3f8070b549ec47e692f6b5e2f7f5d2b370153af05858169007
3
+ metadata.gz: baa20f03dc097cf9b5f18e60f1cd860e3590fa2eafe097989d39d1b29690dd57
4
+ data.tar.gz: 477b1887a6020aa95bd7e680bf1abe508ad90b99cc480606fdd5daec81adf210
5
5
  SHA512:
6
- metadata.gz: 192606c85a86c75885da5117fead95dabb1f19ed1ad0bf926e353e5ceae893d6ab40e6b80c0355cd1156045c47ce4c972ae825cca62dcb5758fe708a7e4d7446
7
- data.tar.gz: 2e71b194442e2a76c207bb528f27de8e243a8b86d27ad575d896ac0d0996b68ca69dfd40ef89f340ce7340efedf3ebc75b1325d7d9cad1a0e1ed092aec6826b2
6
+ metadata.gz: a5b936cdf70211176742efcad5d1b799d6c72ecc1047c141e07c55ddb6c1b33985879d018616f30ab6ce7bb9b4e2be970977c4a1bcecb417bcf0ebd9e0787d68
7
+ data.tar.gz: 6f99f5fd86bff651312a0477ca719fb227ae1b5a960c9ebf066cb7e3a2d7a150f1d42a69c0df25efc6ccd78fd733ab220982e053e73202dfadf87d9268c8a1e5
data/README.md CHANGED
@@ -22,6 +22,12 @@ Or install it yourself as:
22
22
 
23
23
  ### Using `keycloak_oauth` in a Ruby on Rails app
24
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
+
25
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:
26
32
 
27
33
  ```ruby
@@ -36,13 +42,22 @@ end
36
42
  This then allows you to access the `KeycloakOauth` APIs:
37
43
  `KeycloakOauth.connection.authorization_endpoint`
38
44
 
39
- 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`:
40
54
  e.g.
41
- `<%= 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).
42
58
 
43
- 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
44
60
 
45
- ***Customising redirect URIs***
46
61
  There are situations where you would want to customise the oauth2 route (e.g. to use a localised version of the callback URL).
47
62
  In this case, you can do the following:
48
63
  - add a controller to your app: e.g. `CallbackOverrides`
@@ -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 = "1.1.0"
2
+ VERSION = "2.0.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keycloak_oauth
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
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: 2022-04-13 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
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
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'
97
111
  description:
98
112
  email:
99
113
  - dev@simplificator.com
@@ -105,12 +119,15 @@ files:
105
119
  - Rakefile
106
120
  - app/controllers/keycloak_oauth/callbacks_controller.rb
107
121
  - app/services/keycloak_oauth/authentication_service.rb
122
+ - app/services/keycloak_oauth/authentication_service_base.rb
108
123
  - app/services/keycloak_oauth/authorizable_service.rb
109
124
  - app/services/keycloak_oauth/get_users_service.rb
110
125
  - app/services/keycloak_oauth/logout_service.rb
111
- - 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
112
128
  - app/services/keycloak_oauth/post_users_service.rb
113
129
  - app/services/keycloak_oauth/put_execute_actions_email_service.rb
130
+ - app/services/keycloak_oauth/refresh_authentication_service.rb
114
131
  - app/services/keycloak_oauth/user_info_retrieval_service.rb
115
132
  - config/routes.rb
116
133
  - lib/keycloak_oauth.rb