keycloak_oauth 0.1.7 → 0.1.8
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/app/controllers/keycloak_oauth/callbacks_controller.rb +2 -3
- data/app/services/keycloak_oauth/authentication_service.rb +13 -41
- data/app/services/keycloak_oauth/authorizable_service.rb +31 -5
- data/app/services/keycloak_oauth/logout_service.rb +2 -2
- data/app/services/keycloak_oauth/post_token_service.rb +40 -0
- data/app/services/keycloak_oauth/post_users_service.rb +49 -0
- data/app/services/keycloak_oauth/user_info_retrieval_service.rb +2 -2
- data/lib/keycloak_oauth/connection.rb +3 -3
- data/lib/keycloak_oauth/endpoints.rb +4 -0
- data/lib/keycloak_oauth/version.rb +1 -1
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b84ab145e8572eebc11e31faff2080a82ec5f157fe5579c7076f32149f4b2b7
|
4
|
+
data.tar.gz: '0308c1a7e95dbd136e1cb1c659d203b355d78faecfefa4bd56d31fc222040245'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a9c847ab0c59e5d6c4d28c51bbc5ad8ae515874cd680b312b31e264edc97748e813a319eb83f51c75ee463edaa02a9eba65ad6a444b82c59bc805b1a6eb1cfbf
|
7
|
+
data.tar.gz: fab61c415c9a09a4cc66a6e9986998dfc1db3c126205698938ef4f76c59a3571d1078f74456ab97201f7fa578b323430767fedd5687315a6233404f3610fb01d
|
@@ -7,8 +7,7 @@ module KeycloakOauth
|
|
7
7
|
def oauth2
|
8
8
|
authentication_service = KeycloakOauth::AuthenticationService.new(
|
9
9
|
authentication_params: authentication_params,
|
10
|
-
session: session
|
11
|
-
redirect_uri: current_uri_without_params
|
10
|
+
session: session
|
12
11
|
)
|
13
12
|
authentication_service.authenticate
|
14
13
|
map_authenticatable_if_implemented(session)
|
@@ -19,7 +18,7 @@ module KeycloakOauth
|
|
19
18
|
private
|
20
19
|
|
21
20
|
def authentication_params
|
22
|
-
params.permit(:code)
|
21
|
+
params.permit(:code).merge({ redirect_uri: current_uri_without_params })
|
23
22
|
end
|
24
23
|
|
25
24
|
def map_authenticatable_if_implemented(request)
|
@@ -1,59 +1,31 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
|
3
1
|
module KeycloakOauth
|
4
|
-
class AuthenticationError < StandardError; end
|
5
|
-
|
6
2
|
class AuthenticationService
|
7
|
-
GRANT_TYPE = 'authorization_code'.freeze
|
8
|
-
CONTENT_TYPE = 'application/x-www-form-urlencoded'.freeze
|
9
3
|
ACCESS_TOKEN_KEY = 'access_token'.freeze
|
10
4
|
REFRESH_TOKEN_KEY = 'refresh_token'.freeze
|
11
5
|
|
12
|
-
attr_reader :session
|
6
|
+
attr_reader :session, :authentication_params
|
13
7
|
|
14
|
-
def initialize(authentication_params:, session
|
15
|
-
@
|
8
|
+
def initialize(authentication_params:, session:)
|
9
|
+
@authentication_params = authentication_params
|
16
10
|
@session = session
|
17
|
-
@redirect_uri = redirect_uri
|
18
11
|
end
|
19
12
|
|
20
13
|
def authenticate
|
21
|
-
|
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)
|
22
20
|
end
|
23
21
|
|
24
22
|
private
|
25
23
|
|
26
|
-
|
27
|
-
|
28
|
-
def get_tokens
|
29
|
-
uri = URI.parse(KeycloakOauth.connection.authentication_endpoint)
|
30
|
-
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
|
31
|
-
request = Net::HTTP::Post.new(uri)
|
32
|
-
request.set_content_type(CONTENT_TYPE)
|
33
|
-
request.set_form_data(token_request_params)
|
34
|
-
http.request(request)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def token_request_params
|
39
|
-
{
|
40
|
-
client_id: KeycloakOauth.connection.client_id,
|
41
|
-
client_secret: KeycloakOauth.connection.client_secret,
|
42
|
-
grant_type: GRANT_TYPE,
|
43
|
-
code: code,
|
44
|
-
redirect_uri: redirect_uri
|
45
|
-
}
|
46
|
-
end
|
47
|
-
|
48
|
-
def store_credentials(http_response)
|
49
|
-
response_hash = JSON.parse(http_response.body)
|
24
|
+
def store_credentials(post_token_service)
|
25
|
+
response_hash = post_token_service.parsed_response_body
|
50
26
|
|
51
|
-
|
52
|
-
|
53
|
-
session[:refresh_token] = response_hash[REFRESH_TOKEN_KEY]
|
54
|
-
else
|
55
|
-
raise KeycloakOauth::AuthenticationError.new(response_hash)
|
56
|
-
end
|
27
|
+
session[:access_token] = response_hash[ACCESS_TOKEN_KEY]
|
28
|
+
session[:refresh_token] = response_hash[REFRESH_TOKEN_KEY]
|
57
29
|
end
|
58
30
|
end
|
59
31
|
end
|
@@ -4,21 +4,47 @@ module KeycloakOauth
|
|
4
4
|
class AuthorizableError < StandardError; end
|
5
5
|
|
6
6
|
class AuthorizableService
|
7
|
-
HTTP_SUCCESS_CODES = [Net::HTTPOK, Net::HTTPNoContent]
|
7
|
+
HTTP_SUCCESS_CODES = [Net::HTTPOK, Net::HTTPNoContent, Net::HTTPCreated]
|
8
8
|
DEFAULT_CONTENT_TYPE = 'application/x-www-form-urlencoded'.freeze
|
9
9
|
AUTHORIZATION_HEADER = 'Authorization'.freeze
|
10
10
|
|
11
|
+
attr_reader :http_response, :parsed_response_body
|
12
|
+
|
13
|
+
def perform
|
14
|
+
@http_response = send_request
|
15
|
+
@parsed_response_body ||= parse_response_body(http_response)
|
16
|
+
end
|
17
|
+
|
11
18
|
private
|
12
19
|
|
13
|
-
def
|
14
|
-
|
20
|
+
def parse_response_body(http_response)
|
21
|
+
response_body = http_response.body.present? ? JSON.parse(http_response.body) : http_response.body
|
15
22
|
|
16
|
-
return
|
23
|
+
return response_body if HTTP_SUCCESS_CODES.include?(http_response.code_type)
|
17
24
|
|
18
25
|
# TODO: For now, we assume that the access token is always valid.
|
19
26
|
# We do not yet handle the case where a refresh token is passed in and
|
20
27
|
# used if the access token has expired.
|
21
|
-
raise KeycloakOauth::AuthorizableError.new(
|
28
|
+
raise KeycloakOauth::AuthorizableError.new(error_message_from(response_body))
|
29
|
+
end
|
30
|
+
|
31
|
+
def error_message_from(response)
|
32
|
+
# Keycloak sometimes sends back a hash containing the "errorMessage" key,
|
33
|
+
# other times it returns a hash containing the "error_description key" key
|
34
|
+
# and other times it returns an empty string. There could be more cases,
|
35
|
+
# but for the moment we are only handling these three.
|
36
|
+
case response.class.to_s
|
37
|
+
when 'Hash'
|
38
|
+
if response.has_key?('errorMessage')
|
39
|
+
return response['errorMessage']
|
40
|
+
elsif response.has_key?('error_description')
|
41
|
+
return response['error_description']
|
42
|
+
end
|
43
|
+
when 'String'
|
44
|
+
return response
|
45
|
+
else
|
46
|
+
'Unexpected Keycloak error'
|
47
|
+
end
|
22
48
|
end
|
23
49
|
end
|
24
50
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module KeycloakOauth
|
4
|
+
class PostTokenService < KeycloakOauth::AuthorizableService
|
5
|
+
DEFAULT_GRANT_TYPE = 'authorization_code'.freeze
|
6
|
+
|
7
|
+
attr_reader :request_params, :connection
|
8
|
+
|
9
|
+
def initialize(connection:, request_params:)
|
10
|
+
@connection = connection
|
11
|
+
@request_params = request_params
|
12
|
+
end
|
13
|
+
|
14
|
+
def send_request
|
15
|
+
post_token
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :code, :redirect_uri
|
21
|
+
|
22
|
+
def post_token
|
23
|
+
uri = URI.parse(connection.authentication_endpoint)
|
24
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
25
|
+
request = Net::HTTP::Post.new(uri)
|
26
|
+
request.set_content_type(DEFAULT_CONTENT_TYPE)
|
27
|
+
request.set_form_data(token_request_params)
|
28
|
+
http.request(request)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def token_request_params
|
33
|
+
{
|
34
|
+
client_id: connection.client_id,
|
35
|
+
client_secret: connection.client_secret,
|
36
|
+
grant_type: DEFAULT_GRANT_TYPE
|
37
|
+
}.merge(request_params)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module KeycloakOauth
|
4
|
+
class DuplicationError < StandardError; end
|
5
|
+
|
6
|
+
class PostUsersService < KeycloakOauth::AuthorizableService
|
7
|
+
CONTENT_TYPE = 'application/json'.freeze
|
8
|
+
|
9
|
+
attr_reader :request_params, :connection, :user_params
|
10
|
+
|
11
|
+
def initialize(connection:, access_token:, refresh_token:, user_params:)
|
12
|
+
@connection = connection
|
13
|
+
@access_token = access_token
|
14
|
+
@refresh_token = refresh_token
|
15
|
+
@user_params = user_params
|
16
|
+
end
|
17
|
+
|
18
|
+
def send_request
|
19
|
+
post_users
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_accessor :access_token, :refresh_token
|
25
|
+
|
26
|
+
def post_users
|
27
|
+
uri = URI.parse(connection.post_users_endpoint)
|
28
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
29
|
+
request = Net::HTTP::Post.new(uri)
|
30
|
+
request.set_content_type(CONTENT_TYPE)
|
31
|
+
request[AUTHORIZATION_HEADER] = "Bearer #{access_token}"
|
32
|
+
request.body = user_params.to_json
|
33
|
+
http.request(request)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse_response_body(http_response)
|
38
|
+
super
|
39
|
+
rescue KeycloakOauth::AuthorizableError => exception
|
40
|
+
raise exception unless is_exception_a_duplication?(exception)
|
41
|
+
raise KeycloakOauth::DuplicationError.new(exception)
|
42
|
+
end
|
43
|
+
|
44
|
+
def is_exception_a_duplication?(exception)
|
45
|
+
exception.message == "User exists with same email" ||
|
46
|
+
exception.message == "User exists with same username"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -19,13 +19,13 @@ module KeycloakOauth
|
|
19
19
|
access_token: access_token,
|
20
20
|
refresh_token: refresh_token
|
21
21
|
)
|
22
|
-
service.
|
23
|
-
service.
|
22
|
+
service.perform
|
23
|
+
service.parsed_response_body
|
24
24
|
end
|
25
25
|
|
26
26
|
def logout(session:)
|
27
27
|
service = KeycloakOauth::LogoutService.new(session)
|
28
|
-
service.
|
28
|
+
service.perform
|
29
29
|
end
|
30
30
|
end
|
31
31
|
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: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- simplificator
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-11-
|
11
|
+
date: 2020-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -58,7 +58,7 @@ dependencies:
|
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '0'
|
61
|
-
description:
|
61
|
+
description:
|
62
62
|
email:
|
63
63
|
- dev@simplificator.com
|
64
64
|
executables: []
|
@@ -71,6 +71,8 @@ files:
|
|
71
71
|
- app/services/keycloak_oauth/authentication_service.rb
|
72
72
|
- app/services/keycloak_oauth/authorizable_service.rb
|
73
73
|
- app/services/keycloak_oauth/logout_service.rb
|
74
|
+
- app/services/keycloak_oauth/post_token_service.rb
|
75
|
+
- app/services/keycloak_oauth/post_users_service.rb
|
74
76
|
- app/services/keycloak_oauth/user_info_retrieval_service.rb
|
75
77
|
- config/routes.rb
|
76
78
|
- lib/keycloak_oauth.rb
|
@@ -86,7 +88,7 @@ metadata:
|
|
86
88
|
homepage_uri: https://rubygems.org/gems/keycloak_oauth
|
87
89
|
source_code_uri: https://github.com/simplificator/keycloak_oauth
|
88
90
|
changelog_uri: https://github.com/simplificator/keycloak_oauth
|
89
|
-
post_install_message:
|
91
|
+
post_install_message:
|
90
92
|
rdoc_options: []
|
91
93
|
require_paths:
|
92
94
|
- lib
|
@@ -101,8 +103,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
103
|
- !ruby/object:Gem::Version
|
102
104
|
version: '0'
|
103
105
|
requirements: []
|
104
|
-
rubygems_version: 3.
|
105
|
-
signing_key:
|
106
|
+
rubygems_version: 3.1.4
|
107
|
+
signing_key:
|
106
108
|
specification_version: 4
|
107
109
|
summary: Implementing OAuth with Keycloak in Ruby
|
108
110
|
test_files: []
|