identity_toolbox 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: []