identity_toolbox 0.1.0 → 0.2.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: aa431f92f09944ba1dbcd6447b88bffefabf667e8de9a8edd8c66033e31efebb
4
- data.tar.gz: 3d63c5240c824ddade56157d6fc1537a9defe5ed97a7a1a7f1f638d7560083af
3
+ metadata.gz: 2760a7748ce88136bc592c1212db62e2d8c9eaaf8eca0ff9269b7b0b7af44b6f
4
+ data.tar.gz: 609492fe68a986327849a29336045db2f7704ed41b85b4a6e1623679a934eb5c
5
5
  SHA512:
6
- metadata.gz: 7d8ebea90398d0c57e49f2f94bfae2cbce2e3bead8298468d91c02739294af051936517f8d03c5bc9227475e52f8c4c6e0caa68649df668a3cd8aee2dc5d1a7b
7
- data.tar.gz: 11240ffdc42e984d36a7e3a12ab897ec490578c9a366a46ff396c547cc15016fcda17a84d456f2638ee5f13da905081b1f0088b4f6da59d6035b6a728c28c6e9
6
+ metadata.gz: ef3f924b5bbd0f5c15f45fe9e6c350772dae4cc0500ab8fa3d53a546dad1e9eb6196af293dea1ef589006e9521fc53e4c69708a10bbcaebd9fcb8a6fbce223be
7
+ data.tar.gz: bfc984fba81a5e57fb7a4ff6c160dab0c53c0f359046cbdba477dc9070e2a20c8fd91d944905e00b6b6cddfd5e7c27fa61b28a4fd87fd72c67162b288f6dd994
data/.env.pipelines CHANGED
@@ -1,2 +1,4 @@
1
1
  identity_service_url=http://wso2-apim-qa.guideinvestimentos.com.br/org_unit_user_identity/1.0.0
2
- identity_cache_url=redis://localhost:6379/0
2
+ identity_cache_url=redis://localhost:6379/0
3
+ cache_pool_timeout=5
4
+ cache_pool_size=5
data/CHANGELOG.md CHANGED
@@ -5,6 +5,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
+ ## [0.2.0] - 2018-10-15
9
+ ### Added
10
+ - Adds redis connection and cache handling
11
+ - Raises exception if identity_service_url or identity_cache_url aren't set
12
+
8
13
  ## [0.1.0] - 2018-08-14
9
- ### Fixed
14
+ ### Added
10
15
  - First release
data/Gemfile.lock CHANGED
@@ -1,9 +1,12 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- identity_toolbox (0.1.0)
4
+ identity_toolbox (0.2.0)
5
+ activesupport (>= 4.0.0)
6
+ connection_pool (~> 2.2)
5
7
  json_api_toolbox (~> 0.16)
6
8
  pundit (~> 2.0)
9
+ redis (~> 4.0)
7
10
  request_store (~> 1.3)
8
11
  rspec
9
12
 
@@ -41,6 +44,7 @@ GEM
41
44
  byebug (10.0.2)
42
45
  coderay (1.1.2)
43
46
  concurrent-ruby (1.0.5)
47
+ connection_pool (2.2.2)
44
48
  crack (0.4.3)
45
49
  safe_yaml (~> 1.0.0)
46
50
  crass (1.0.4)
@@ -100,6 +104,7 @@ GEM
100
104
  rails-html-sanitizer (1.0.4)
101
105
  loofah (~> 2.2, >= 2.2.2)
102
106
  rake (10.5.0)
107
+ redis (4.0.2)
103
108
  request_store (1.3.2)
104
109
  rest-client (2.0.2)
105
110
  http-cookie (>= 1.0.2, < 2.0)
@@ -4,6 +4,7 @@ lib = File.expand_path('lib', __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require 'identity_toolbox/version'
6
6
 
7
+ # rubocop:disable Metrics/BlockLength
7
8
  Gem::Specification.new do |spec|
8
9
  spec.name = 'identity_toolbox'
9
10
  spec.version = IdentityToolbox::VERSION
@@ -14,12 +15,14 @@ Gem::Specification.new do |spec|
14
15
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
15
16
  f.match(%r{^(test|spec|features)/})
16
17
  end
17
- spec.bindir = 'exe'
18
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
+
19
19
  spec.require_paths = ['lib']
20
20
 
21
+ spec.add_dependency 'activesupport', '>= 4.0.0'
22
+ spec.add_dependency 'connection_pool', '~> 2.2'
21
23
  spec.add_dependency 'json_api_toolbox', '~> 0.16'
22
24
  spec.add_dependency 'pundit', '~> 2.0'
25
+ spec.add_dependency 'redis', '~> 4.0'
23
26
  spec.add_dependency 'request_store', '~> 1.3'
24
27
  spec.add_dependency 'rspec'
25
28
 
@@ -34,3 +37,4 @@ Gem::Specification.new do |spec|
34
37
  spec.add_development_dependency 'vcr'
35
38
  spec.add_development_dependency 'webmock'
36
39
  end
40
+ # rubocop:enable Metrics/BlockLength
@@ -10,7 +10,13 @@ module IdentityToolbox
10
10
  end
11
11
 
12
12
  def current_user
13
- RequestStore.store[:token]
13
+ header = request.headers['user-identifier']
14
+
15
+ return unless header
16
+
17
+ user_identifier = JSON.parse(Base64.decode64(header),
18
+ symbolize_names: true)
19
+ UserEntity.new(user_identifier)
14
20
  end
15
21
 
16
22
  def render_forbidden(_exception)
@@ -2,6 +2,33 @@
2
2
 
3
3
  module IdentityToolbox
4
4
  class Configuration
5
- attr_accessor :identity_service_url, :identity_cache_url
5
+ DEFAULTS = { cache_pool_timeout: 5, cache_pool_size: 5 }.freeze
6
+
7
+ attr_writer :identity_service_url, :identity_cache_url,
8
+ :cache_pool_timeout, :cache_pool_size
9
+
10
+ def identity_service_url
11
+ raise 'identity_service_url is not set' unless @identity_service_url
12
+
13
+ @identity_service_url
14
+ end
15
+
16
+ def identity_cache_url
17
+ raise 'identity_cache_url is not set' unless @identity_cache_url
18
+
19
+ @identity_cache_url
20
+ end
21
+
22
+ def cache_pool_timeout
23
+ return DEFAULTS[:cache_pool_timeout] unless @cache_pool_timeout
24
+
25
+ @cache_pool_timeout.to_i
26
+ end
27
+
28
+ def cache_pool_size
29
+ return DEFAULTS[:cache_pool_size] unless @cache_pool_size
30
+
31
+ @cache_pool_size.to_i
32
+ end
6
33
  end
7
34
  end
@@ -12,11 +12,12 @@ module IdentityToolbox
12
12
  Class.new do
13
13
  include PolicyMethods
14
14
 
15
- attr_reader :scope
15
+ attr_reader :user, :scope
16
16
 
17
17
  delegate :attributes, to: klass.name.to_sym
18
18
 
19
- def initialize(_user, scope)
19
+ def initialize(user, scope)
20
+ @user = user
20
21
  @scope = scope
21
22
  end
22
23
 
@@ -70,9 +71,10 @@ module IdentityToolbox
70
71
 
71
72
  delegate :attributes, to: :class
72
73
 
73
- attr_reader :record
74
+ attr_reader :user, :record
74
75
 
75
- def initialize(_user, record)
76
+ def initialize(user, record)
77
+ @user = user
76
78
  @record = record
77
79
  end
78
80
 
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IdentityToolbox
4
+ class IdentityCache
5
+ def self.user_account(user_entity)
6
+ new(user_entity).user_account
7
+ end
8
+
9
+ attr_reader :user_entity
10
+
11
+ def initialize(user_entity)
12
+ @user_entity = user_entity
13
+ end
14
+
15
+ def user_account
16
+ return unless user_entity && user_string
17
+
18
+ JSON.parse(user_string, symbolize_names: true)
19
+ end
20
+
21
+ private
22
+
23
+ def cache_key
24
+ return unless user_entity.id && user_entity.user_name
25
+
26
+ @cache_key ||= "user_view:#{user_entity.id}|#{user_entity.user_name}"
27
+ end
28
+
29
+ def user_string
30
+ return unless cache_key
31
+
32
+ @user_string ||=
33
+ RedisClient.with do |connection|
34
+ connection.get(cache_key)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IdentityToolbox
4
+ class IdentityRepository
5
+ class << self
6
+ def user_account_views
7
+ new.user_account_views
8
+ end
9
+
10
+ def user_account(user_entity)
11
+ new(user_entity).user_account
12
+ end
13
+ end
14
+
15
+ attr_reader :user_entity
16
+
17
+ def initialize(user_entity = nil)
18
+ @user_entity = user_entity
19
+ end
20
+
21
+ def user_account_views
22
+ IdentityService.user_account_views.map(&method(:to_user_account_view))
23
+ end
24
+
25
+ def user_account
26
+ return cache_user_account_entity if cache_valid?
27
+
28
+ service_user_account_entity
29
+ end
30
+
31
+ private
32
+
33
+ def to_user_account_view(response)
34
+ UserAccountViewEntity.new(response.instance_values.symbolize_keys)
35
+ end
36
+
37
+ def cache_valid?
38
+ cache_user_account_entity.try(:created_at) &&
39
+ cache_user_account_entity.created_at >= Time.current - 1.hour
40
+ end
41
+
42
+ def cache_user_account
43
+ @cache_user_account ||= IdentityCache.user_account(user_entity)
44
+ end
45
+
46
+ def cache_user_account_entity
47
+ return unless cache_user_account
48
+
49
+ @cache_user_account_entity ||= UserAccountEntity.new(cache_user_account)
50
+ end
51
+
52
+ def service_user_account_entity
53
+ @service_user_account_entity ||=
54
+ UserAccountEntity.from_user_account_views(user_account_views)
55
+ end
56
+ end
57
+ end
@@ -2,12 +2,18 @@
2
2
 
3
3
  module IdentityToolbox
4
4
  class IdentityService < ::JsonApiToolbox::Service
5
- def self.find_view_models
6
- get(url: "#{config.identity_service_url}/users/accounts")
7
- end
5
+ class << self
6
+ def user_account_views
7
+ get(url: "#{config.identity_service_url}/users/accounts")
8
+ end
9
+
10
+ def find_view_models
11
+ user_account_views
12
+ end
8
13
 
9
- def self.config
10
- @config ||= IdentityToolbox.configuration
14
+ def config
15
+ @config ||= IdentityToolbox.configuration
16
+ end
11
17
  end
12
18
  end
13
19
  end
@@ -2,26 +2,13 @@
2
2
 
3
3
  module IdentityToolbox
4
4
  module PolicyMethods
5
- def identification_documents
6
- view_models.map(&:document).map(&:to_s).uniq
7
- end
8
-
9
- def client_ids
10
- view_models.map(&:client_id).map(&:to_s).uniq
11
- end
12
-
13
- def account_ids
14
- view_models.map(&:account_id).map(&:to_s).uniq
15
- end
16
-
17
- def sinacor_advisor_ids
18
- view_models.map(&:sinacor_advisor_id).map(&:to_s).uniq
19
- end
5
+ delegate :identification_documents, :client_ids, :account_ids,
6
+ :sinacor_advisor_ids, to: :user_account_entity
20
7
 
21
8
  private
22
9
 
23
- def view_models
24
- @view_models ||= IdentityService.find_view_models
10
+ def user_account_entity
11
+ @user_account_entity ||= IdentityRepository.user_account(user)
25
12
  end
26
13
  end
27
14
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IdentityToolbox
4
+ class RedisClient
5
+ class << self
6
+ delegate :with, to: :pool
7
+
8
+ def config
9
+ @config ||= IdentityToolbox.configuration
10
+ end
11
+
12
+ def pool
13
+ @pool ||= ConnectionPool.new(size: config.cache_pool_size,
14
+ timeout: config.cache_pool_timeout) do
15
+ Redis.new(url: config.identity_cache_url)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -28,12 +28,7 @@ module IdentityToolbox
28
28
  RSpec.shared_examples 'a default policy for' do |attributes|
29
29
  include_context 'default policy records', attributes
30
30
 
31
- before do
32
- allow(IdentityToolbox::IdentityService).
33
- to receive(:find_view_models).and_return(view_models)
34
- end
35
-
36
- subject { described_class.new(nil, record).allowed? }
31
+ subject { described_class.new('user', record).allowed? }
37
32
 
38
33
  def self.join(attributes)
39
34
  attributes.values.join(', ')
@@ -61,6 +56,16 @@ module IdentityToolbox
61
56
  end
62
57
 
63
58
  RSpec.shared_examples 'a default policy' do
59
+ let(:user_account) do
60
+ IdentityToolbox::UserAccountEntity.
61
+ from_user_account_views(view_models)
62
+ end
63
+
64
+ before do
65
+ allow(IdentityToolbox::IdentityRepository).
66
+ to receive(:user_account).with('user').and_return(user_account)
67
+ end
68
+
64
69
  def self.combinations
65
70
  (1..4).flat_map do |quantity|
66
71
  described_class.attributes.keys.combination(quantity).to_a
@@ -23,6 +23,10 @@ module IdentityToolbox
23
23
  except(nil))
24
24
  end
25
25
  let(:scope) { model_name.constantize.all }
26
+ let(:user_account) do
27
+ IdentityToolbox::UserAccountEntity.
28
+ from_user_account_views(view_models)
29
+ end
26
30
  end
27
31
 
28
32
  RSpec.shared_examples 'resolve method' do |attributes|
@@ -57,15 +61,15 @@ module IdentityToolbox
57
61
 
58
62
  RSpec.shared_examples 'a default policy scope' do
59
63
  describe described_class::Scope do
64
+ before do
65
+ allow(IdentityToolbox::IdentityRepository).
66
+ to receive(:user_account).with('user').and_return(user_account)
67
+ end
68
+
60
69
  shared_examples 'a default policy scope for' do |attributes|
61
70
  include_context 'default policy scope records', attributes
62
71
 
63
- before do
64
- allow(IdentityToolbox::IdentityService).
65
- to receive(:find_view_models).and_return(view_models)
66
- end
67
-
68
- subject { described_class.new(nil, scope).resolve }
72
+ subject { described_class.new('user', scope).resolve }
69
73
 
70
74
  include_examples 'resolve method', attributes
71
75
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IdentityToolbox
4
+ class UserAccountEntity
5
+ ACCESS_LISTS = %i[account_ids client_ids documents
6
+ sinacor_advisor_ids].freeze
7
+ ATTRS = %i[id username created_at].freeze
8
+
9
+ ATTRS.each { |item| attr_reader item }
10
+ ACCESS_LISTS.each { |item| attr_reader item }
11
+
12
+ def initialize(**args)
13
+ ATTRS.each { |key| instance_variable_set("@#{key}", args[key]) }
14
+ ACCESS_LISTS.each do |key|
15
+ instance_variable_set("@#{key}", args[key].map(&:to_s).uniq)
16
+ end
17
+ end
18
+
19
+ def identification_documents
20
+ documents
21
+ end
22
+
23
+ def created_at
24
+ return unless @created_at
25
+
26
+ Time.parse(@created_at)
27
+ end
28
+
29
+ def self.from_user_account_views(user_account_views)
30
+ new(id: user_account_views.try(:first).try(:user),
31
+ documents: user_account_views.map(&:document),
32
+ client_ids: user_account_views.map(&:client_id),
33
+ account_ids: user_account_views.map(&:account_id),
34
+ sinacor_advisor_ids:
35
+ user_account_views.map(&:sinacor_advisor_id))
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IdentityToolbox
4
+ class UserAccountViewEntity
5
+ ATTRS = %i[id user document client_id account_id sinacor_advisor_id].freeze
6
+
7
+ ATTRS.each { |item| attr_reader item }
8
+
9
+ def initialize(**args)
10
+ ATTRS.each { |key| instance_variable_set("@#{key}", args[key]) }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IdentityToolbox
4
+ class UserEntity
5
+ ATTRS = %i[id user_name email remote_ip].freeze
6
+
7
+ ATTRS.each { |item| attr_reader item }
8
+
9
+ def initialize(**args)
10
+ ATTRS.each { |key| instance_variable_set("@#{key}", args[key]) }
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IdentityToolbox
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
@@ -1,12 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_support/core_ext/object/instance_variables'
4
+ require 'active_support/core_ext/hash/keys'
5
+ require 'connection_pool'
6
+ require 'redis'
3
7
  require 'dotenv/load'
4
8
  require 'pundit'
5
9
  require 'json_api_toolbox'
6
10
  require 'request_store'
11
+ require 'base64'
7
12
  require 'identity_toolbox/configuration'
8
13
  require 'identity_toolbox/version'
9
14
  require 'identity_toolbox/identity_service'
15
+ require 'identity_toolbox/redis_client'
16
+ require 'identity_toolbox/identity_cache'
17
+ require 'identity_toolbox/user_entity'
18
+ require 'identity_toolbox/user_account_entity'
19
+ require 'identity_toolbox/user_account_view_entity'
20
+ require 'identity_toolbox/identity_repository'
10
21
  require 'identity_toolbox/policy_methods'
11
22
  require 'identity_toolbox/default_policy'
12
23
  require 'identity_toolbox/authorizable'
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: identity_toolbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Codeminer 42
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-02 00:00:00.000000000 Z
11
+ date: 2018-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 4.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 4.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: connection_pool
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.2'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: json_api_toolbox
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +66,20 @@ dependencies:
38
66
  - - "~>"
39
67
  - !ruby/object:Gem::Version
40
68
  version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: redis
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '4.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '4.0'
41
83
  - !ruby/object:Gem::Dependency
42
84
  name: request_store
43
85
  requirement: !ruby/object:Gem::Requirement
@@ -232,13 +274,19 @@ files:
232
274
  - lib/identity_toolbox/authorizable.rb
233
275
  - lib/identity_toolbox/configuration.rb
234
276
  - lib/identity_toolbox/default_policy.rb
277
+ - lib/identity_toolbox/identity_cache.rb
278
+ - lib/identity_toolbox/identity_repository.rb
235
279
  - lib/identity_toolbox/identity_service.rb
236
280
  - lib/identity_toolbox/policy_methods.rb
281
+ - lib/identity_toolbox/redis_client.rb
237
282
  - lib/identity_toolbox/spec_support/authorization_steps.rb
238
283
  - lib/identity_toolbox/spec_support/shared_examples_for_controllers.rb
239
284
  - lib/identity_toolbox/spec_support/shared_examples_for_policies.rb
240
285
  - lib/identity_toolbox/spec_support/shared_examples_for_policy_scopes.rb
241
286
  - lib/identity_toolbox/spec_support/tags.rb
287
+ - lib/identity_toolbox/user_account_entity.rb
288
+ - lib/identity_toolbox/user_account_view_entity.rb
289
+ - lib/identity_toolbox/user_entity.rb
242
290
  - lib/identity_toolbox/version.rb
243
291
  homepage:
244
292
  licenses: []