soar-policy-access_manager 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 25513f1e46e2e8a111b246d653f94550937ea03c
4
+ data.tar.gz: a91e20fb7a8360de3c25dfdaddfa85734480c74c
5
+ SHA512:
6
+ metadata.gz: e8c7cb96934366974567a139347a70a7f978042e90fba5e6c054bef1ebaf1b54a101f40d68aef4b95958148d9059f2d8a17ac7b852c497d5039a925516f5f4e8
7
+ data.tar.gz: deecf71bd5b3a85fb89210c9e31b1302f19b449eee5b8994b021c16a67489044cdbb48cdbc1b9d9bb97fd73b1fbdcaef65728d3374beac1dfd27c9a97a0211aa
@@ -0,0 +1,13 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .byebug_history
11
+ *.gem
12
+ *.swp
13
+ *.swo
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --require spec_helper
@@ -0,0 +1 @@
1
+ soar-policy-access_manager
@@ -0,0 +1 @@
1
+ ruby-2.3.0
@@ -0,0 +1,6 @@
1
+ FROM ruby:2.3.1
2
+ WORKDIR /usr/local/src
3
+ RUN gem install jsender rack
4
+ ADD config.ru /usr/local/src/
5
+ CMD rackup -E production ./config.ru -p 8080 --host 0.0.0.0
6
+
@@ -0,0 +1,14 @@
1
+ FROM ruby:2.3.1
2
+ ARG USER_ID
3
+ ARG USER_NAME
4
+ RUN useradd -u $USER_ID $USER_NAME -m
5
+ RUN gem install bundler
6
+ RUN chown -R $USER_NAME:$USER_NAME /usr/local
7
+ USER $USER_NAME
8
+ WORKDIR /usr/local/src
9
+ ADD Gemfile /usr/local/src/
10
+ ADD soar-policy-access_manager.gemspec /usr/local/src/
11
+ RUN bundle install --without development --with test
12
+ VOLUME /usr/local/src
13
+ CMD bundle exec cucumber && bundle exec rspec
14
+
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in soar_policy_access_manager.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'rspec', '~> 3.5'
8
+ gem 'rspec-expectations', '~> 3.5'
9
+ gem 'cucumber', '~> 2.4'
10
+ end
11
+
12
+
13
+
@@ -0,0 +1,183 @@
1
+ # SoarPolicyAccessManager
2
+
3
+ This Access Manager adheres to SoarAm::AmApi. It is initialized with a soar_sr service registy client (https://rubygems.org/gems/soar_sr)
4
+
5
+ This access manager denies access for unauthenticated requests, that is, request that do not have request.session['user'] set. If set, this access manager then queries the service registry for meta regarding the service identifier in question.
6
+
7
+ If the service meta indicates no policy, the request is allowed. It the service meta indicates a policy, the policy service is asked, given the authenticated subject identifier, service identifier, resource identifier and request parameters, whether the request should be allowed. This access manager then allows / denies accordingly.
8
+
9
+ In the case of the service not found in the service registry, or a failure of any kind, the request is denied. In the interest of security, exceptions while authorizing will be swallowed by this access manager. Only the last exception message will be reported to STDERR.
10
+
11
+ ## Quickstart
12
+ When using soar_sc the [soar_authorization](https://github.com/hetznerZA/soar_authorization) gem automagically passes values set in [your router](https://github.com/hetznerZA/soar_sc_routing) as post parameters in authorization requests to policies.
13
+
14
+ SoarSc Routing params | SoarAuthorization params | AccessManager Params | Policy Params
15
+ ----------------------|---------------------------|---------------------------|-----------------------
16
+ service_name | | service_identifier | requestor_identifier
17
+ path | | resource_identifier | resource_identifier
18
+ | authentication.identifier | authentication_identifier | subject_identifier
19
+
20
+ ### Stub provider
21
+ > Use this provider during tests and development when you don't want any http policy authorization requests.
22
+
23
+ Create meta variable mapping services to policy identifiers (names)
24
+ ```ruby
25
+ > meta = {
26
+ 'service_identifier1' => {
27
+ 'policy' => 'policy1'
28
+ }
29
+ }
30
+ ```
31
+ Create policies variable mapping policy identifiers to resources. Access to a resource is allowed if your authentication identifier (uuid) is present in the array.
32
+ ```ruby
33
+ > policies = {
34
+ 'policy1' => {
35
+ '/resource_identifier1' => ['authentication_identifier1'],
36
+ '/resource_identifier2' => []
37
+ }
38
+ }
39
+ ```
40
+ Instantiate the stub provider and pass it to the access manager model.
41
+ ```ruby
42
+ > provider = Soar::Policy::AccessManager::ModelProvider::Stub.new(meta: meta, policies: policies})
43
+ > policy_am = Soar::Policy::AccessManager::Model.new(provider)
44
+ > puts policy_am.authorized?({
45
+ service_identifier: 'service_identifier1',
46
+ resource_identifier: '/resource_identifier1',
47
+ request: {
48
+ params: {},
49
+ authentication_identifier: 'authentication_identifier1'
50
+ }
51
+ })
52
+ ```
53
+
54
+ ### Policy provider
55
+ > Use this provider during tests and development to send authorization requests directly to a policy.
56
+
57
+ Create meta variable mapping services to policy identifiers (names)
58
+ ```ruby
59
+ > meta = {
60
+ 'service_identifier1' => 'policy1',
61
+ 'service_identifier2' => 'policy2'
62
+ }
63
+ ```
64
+ Create policies variable mapping policy identifiers to policy endpoints.
65
+ ```ruby
66
+ > policies = {
67
+ 'policy1' => 'http://localhost:8080/allow',
68
+ 'policy2' => 'http://localhost:8080/deny'
69
+ }
70
+ ```
71
+
72
+ Instantiate the stub provider and pass it to the access manager model.
73
+ ```ruby
74
+ > provider = Soar::Policy::AccessManager::ModelProvider::Policy.new(meta: meta, policies: policies})
75
+ > policy_am = Soar::Policy::AccessManager::Model.new(provider)
76
+ > puts policy_am.authorized?({
77
+ service_identifier: 'service_identifier1',
78
+ resource_identifier: '',
79
+ request: {
80
+ params: {},
81
+ authentication_identifier: ''
82
+ }
83
+ })
84
+ ```
85
+
86
+ ### Service registry provider
87
+ > Use this provider during production. It reaches out to the service registry and policies. It's used by soar sc.
88
+
89
+ ```ruby
90
+ > service_registry = SoarSc::service_registry
91
+ > provider = Soar::Policy::AccessManager::ModelProvider::ServiceRegistry.new(service_registry)
92
+ > policy_am = Soar::Policy::AccessManager::Model.new(provider)
93
+ > puts policy_am.authorized?({
94
+ service_identifier: 'service_identifier1',
95
+ resource_identifier: '/path',
96
+ request: {
97
+ params: request.params,
98
+ authentication_identifier: SoarAuthentication::Authentication.new(request).identifier
99
+ }
100
+ })
101
+ ```
102
+
103
+ This access manager can be used with the SoarAuthorization::Authorize middleware:
104
+
105
+ ```ruby
106
+ > SoarAuthorization::Authorize::register_access_manager('/path', 'path-service', policy_am)
107
+ > use SoarAuthorization::Authorize
108
+ ```
109
+
110
+ ## Tests
111
+
112
+ ### Local
113
+
114
+ #### Unit Tests
115
+
116
+ ```bash
117
+ $ bundle exec rspec
118
+ ```
119
+
120
+ #### Provider Integration Tests
121
+
122
+ ##### Stub provider
123
+ ```bash
124
+ $ TEST_ORCHESTRATION_PROVIDER=Stub bundle exec cucumber
125
+ ```
126
+
127
+ ##### Service Registry provider
128
+
129
+ Serve two policies, *allow all* and *deny all*, locally via file *config.ru* using [Rack webserver](https://rack.github.io/).
130
+ ```bash
131
+ $ docker-compose up
132
+ ```
133
+
134
+ Test providers for the stub and service registry via the model api interface
135
+ ```bash
136
+ $ TEST_ORCHESTRATION_PROVIDER=ServiceRegistry bundle exec cucumber
137
+ ```
138
+
139
+ ##### Policy provider
140
+
141
+ Serve two policies, *allow all* and *deny all*, locally via file *config.ru* using [Rack webserver](https://rack.github.io/).
142
+ ```bash
143
+ $ docker-compose up
144
+ ```
145
+
146
+ Test providers for the stub and service registry via the model api interface
147
+ ```bash
148
+ $ TEST_ORCHESTRATION_PROVIDER=Policy bundle exec cucumber
149
+ ```
150
+
151
+ ### CI
152
+ ```
153
+ $ USER_NAME=$USER USER_ID=$(id -u) POLICY_HOST=policy:8080 TEST_ORCHESTRATION_PROVIDER=ServiceRegistry docker-compose --file docker-compose.test.yml up --abort-on-container-exit --remove-orphans
154
+ EXIT_CODE=$(docker ps -a -f "name=soar-policy-access_manager-tests" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
155
+ exit $EXIT_CODE
156
+ ```
157
+
158
+ #### Enviroment Variables explained
159
+ Sets USER_NAME and USER_ID to your currently logged in user. This is important when you're mounting volumes into a container. Root in the container = root on your local.
160
+ ```bash
161
+ USER_NAME=$USER
162
+ USER_ID=$(id -u)
163
+ ```
164
+
165
+ Select whether you're testing the *ServiceRegistry* , *Policy* or *Stub* provider. Defaults to *Stub*
166
+ ```bash
167
+ TEST_ORCHESTRATION_PROVIDER=Stub
168
+ ```
169
+
170
+ ## Contributing
171
+
172
+ Please send feedback and comments to the author at:
173
+
174
+ Ernst van Graan <ernst.van.graan@hetzner.co.za>
175
+
176
+ This gem is sponsored by Hetzner (Pty) Ltd - http://hetzner.co.za
177
+
178
+ ## License
179
+
180
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
181
+
182
+ ## Resources
183
+ * [soar_am](https://github.com/hetznerZA/soar_am)
@@ -0,0 +1,37 @@
1
+ require 'rack'
2
+ require 'rack/server'
3
+ require 'json'
4
+
5
+ ##
6
+ # Simulates two policies available on the network. One allows all requests, the other, denies all requests.
7
+ # Used for testing the access manager model with both the stub and service registry providers
8
+ ##
9
+ class StubPolicies
10
+
11
+ def self.call(env)
12
+ request = Rack::Request.new env
13
+ case request.path
14
+ when '/allow'
15
+ [200, {"Context-Type" => "application/json"}, [{ 'status' => 'success', 'data' => { 'allowed' => true, 'detail' => '', 'idm' => nil, 'rule_set' => 'allow all', 'notifications' => ['Policy approved authorization request'] }}.to_json]]
16
+ when '/deny'
17
+ [200, {"Context-Type" => "application/json"}, [{ 'status' => 'success', 'data' => { 'allowed' => false, 'detail' => '', 'idm' => nil, 'rule_set' => 'allow all', 'notifications' => ['Policy rejected authorization request'] }}.to_json]]
18
+ else
19
+ [200, {"Context-Type" => "application/json"}, [{ 'status' => 'success', 'data' => { 'notifications' => ['No policy associated with service'] }}.to_json]]
20
+ end
21
+
22
+ end
23
+ end
24
+
25
+ class PrintPolicies
26
+ def self.call(env)
27
+ request = Rack::Request.new env
28
+ [200, {"Context-Type" => "application/json"}, [{
29
+ "is a post request?" => request.post?,
30
+ "request path" => request.path,
31
+ "request params" => request.params
32
+ }.to_json]]
33
+ end
34
+ end
35
+
36
+ Rack::Server.start :app => StubPolicies
37
+ #Rack::Server.start :app => PrintPolicies
@@ -0,0 +1,30 @@
1
+ version: "2"
2
+ services:
3
+ policy:
4
+ build:
5
+ context: .
6
+ dockerfile: Dockerfile.policies
7
+ image: soar-policy-access_manager-policy
8
+ container_name: soar-policy-access_manager-policy
9
+ expose:
10
+ - "8080"
11
+
12
+ tests:
13
+ build:
14
+ context: .
15
+ dockerfile: Dockerfile.tests
16
+ args:
17
+ - USER_NAME
18
+ - USER_ID
19
+ image: soar-policy-access_manager-tests
20
+ container_name: soar-policy-access_manager-tests
21
+ volumes:
22
+ - .:/usr/local/src
23
+ links:
24
+ - policy
25
+ environment:
26
+ - TEST_ORCHESTRATION_PROVIDER=Stub
27
+ - POLICY_HOST=http://policy:8080
28
+
29
+
30
+
@@ -0,0 +1,14 @@
1
+ version: "2"
2
+ services:
3
+ stub_policy:
4
+ build:
5
+ context: .
6
+ dockerfile: Dockerfile.policies
7
+ ports:
8
+ - "8080:8080"
9
+ expose:
10
+ - "8080"
11
+ network_mode: "host"
12
+
13
+
14
+
@@ -0,0 +1,10 @@
1
+
2
+ module Soar
3
+ module Policy
4
+ module AccessManager
5
+ module Error
6
+ class PolicyAccessManagerException < StandardError; end;
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,23 @@
1
+ module Soar
2
+ module Policy
3
+ module AccessManager
4
+ class Model
5
+
6
+ def initialize(provider)
7
+ @provider = provider
8
+ end
9
+
10
+ ##
11
+ # @param service_identifier [String]
12
+ # @param resource_identifier [String]
13
+ # @param request [Hash]
14
+ ##
15
+ def authorized?(service_identifier: nil, resource_identifier: nil, request: nil)
16
+ @provider.authorized?(service_identifier, resource_identifier, request)
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,94 @@
1
+ require 'jsender'
2
+ require 'json'
3
+ require 'soar/policy/access_manager/error'
4
+
5
+ module Soar
6
+ module Policy
7
+ module AccessManager
8
+ module ModelProvider
9
+
10
+ class Policy
11
+
12
+ include Jsender
13
+
14
+ def initialize(meta: {}, policies: {})
15
+ @meta = meta
16
+ @policies = policies
17
+ end
18
+
19
+ def authorized?(service_identifier, resource_identifier, request)
20
+ notifications = []
21
+ decision = false
22
+
23
+ begin
24
+ if ENV['RACK_ENV'] == 'development'
25
+ notifications << 'Authorized in development environment'
26
+ decision = true
27
+ end
28
+
29
+ policy = get_policy(service_identifier)
30
+
31
+ if policy.nil?
32
+ decision = true
33
+ notifications << 'No policy associated with service'
34
+ else
35
+ decision, detail = ask_policy(policy, request[:authentication_identifier], service_identifier, resource_identifier, request)
36
+ notifications.concat(detail) if not detail.empty?
37
+ notifications << 'Policy rejected authorization request' if not decision
38
+ notifications << 'Policy approved authorization request' if decision
39
+ end
40
+ rescue SoarSr::ValidationError => ex
41
+ notifications << "AccessManager error authorizing #{service_identifier} for #{resource_identifier}: #{ex.message}"
42
+ decision = false
43
+ rescue Exception => ex
44
+ notifications << "AccessManager error authorizing #{service_identifier} for #{resource_identifier}: #{ex.message}"
45
+ decision = false
46
+ end
47
+
48
+ success(notifications, { 'approved' => decision } )
49
+ end
50
+
51
+ private
52
+
53
+ def get_policy(service_identifier)
54
+ @meta[service_identifier]
55
+ end
56
+
57
+ def ask_policy(policy, subject_identifier, service_identifier, resource_identifier, request)
58
+ notifications = []
59
+ uri = find_uri(policy)
60
+ if uri.nil?
61
+ notifications << "Could not retrieve policy for service"
62
+ return false, notifications
63
+ end
64
+ url = URI.parse(uri)
65
+ params = {
66
+ 'resource_identifier' => resource_identifier,
67
+ 'subject_identifier' => subject_identifier,
68
+ 'service_identifier' => service_identifier,
69
+ 'request' => {
70
+ 'params' => request['params']
71
+ }.to_json,
72
+ 'flow_identifier' => request['flow_identifier']
73
+ }
74
+ res = Net::HTTP.post_form(url, params)
75
+ result = JSON.parse(res.body)
76
+ if result['status'] == 'error'
77
+ notifications << 'Policy query result was not success'
78
+ return false, notifications
79
+ end
80
+ return result['data']['allowed'], notifications
81
+ rescue => ex
82
+ notifications << "Exception while asking policy #{ex.message}"
83
+ return false, notifications
84
+ end
85
+
86
+ def find_uri(policy)
87
+ @policies[policy]
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+
@@ -0,0 +1,99 @@
1
+ require 'jsender'
2
+ require "soar_sr"
3
+ require 'soar/policy/access_manager/error'
4
+
5
+ module Soar
6
+ module Policy
7
+ module AccessManager
8
+ module ModelProvider
9
+
10
+ class ServiceRegistry
11
+
12
+ include Jsender
13
+ attr_reader :service_registry
14
+
15
+ def initialize(service_registry)
16
+ @service_registry = service_registry
17
+ end
18
+
19
+ def authorized?(service_identifier, resource_identifier, request)
20
+ notifications = []
21
+ decision = false
22
+
23
+ begin
24
+ if ENV['RACK_ENV'] == 'development'
25
+ notifications << 'Authorized in development environment'
26
+ decision = true
27
+ end
28
+
29
+ meta = @service_registry.services.meta_for_service(service_identifier)
30
+ policy = meta['policy'] if meta and meta.is_a?(Hash) and meta['policy']
31
+
32
+ if policy.nil?
33
+ decision = true
34
+ notifications << 'No policy associated with service'
35
+ else
36
+ decision, detail = ask_policy(policy, request[:authentication_identifier], service_identifier, resource_identifier, request)
37
+ notifications.concat(detail) if not detail.empty?
38
+ notifications << 'Policy rejected authorization request' if not decision
39
+ notifications << 'Policy approved authorization request' if decision
40
+ end
41
+ rescue SoarSr::ValidationError => ex
42
+ notifications << "AccessManager error authorizing #{service_identifier} for #{resource_identifier}: #{ex.message}"
43
+ decision = false
44
+ rescue Exception => ex
45
+ notifications << "AccessManager error authorizing #{service_identifier} for #{resource_identifier}: #{ex.message}"
46
+ decision = false
47
+ end
48
+
49
+ success(notifications, { 'approved' => decision } )
50
+ end
51
+
52
+ private
53
+
54
+ def ask_policy(policy, subject_identifier, service_identifier, resource_identifier, request)
55
+ notifications = []
56
+ uri = find_first_uri(policy)
57
+ if uri.nil?
58
+ notifications << "Could not retrieve policy for service"
59
+ return false, notifications
60
+ end
61
+ url = URI.parse(uri)
62
+ params = {
63
+ 'resource_identifier' => resource_identifier,
64
+ 'subject_identifier' => subject_identifier,
65
+ 'service_identifier' => service_identifier,
66
+ 'request' => {
67
+ 'params' => request['params'],
68
+ }.to_json,
69
+ 'flow_identifier' => request['flow_identifier']
70
+ }
71
+ res = Net::HTTP.post_form(url, params)
72
+
73
+ result = JSON.parse(res.body)
74
+ if result['status'] == 'error'
75
+ notifications << 'Policy query result was not success'
76
+ return false, notifications
77
+ end
78
+ return result['data']['allowed'], notifications
79
+ rescue => ex
80
+ notifications << "Exception while asking policy #{ex.message}"
81
+ return false, notifications
82
+ end
83
+
84
+ def find_first_uri(policy)
85
+ result = @service_registry.services.service_by_name(policy)
86
+ return nil if not result['status'] == 'success'
87
+ return nil if result['data']['services'].nil? or result['data']['services'].first.nil?
88
+ service = result['data']['services'].first
89
+ return nil if service[1].nil? or service[1]['uris'].nil?
90
+ access = service[1]['uris'].first
91
+ return nil if access.nil? or access[1].nil? or access[1]['access_point'].nil?
92
+ access[1]['access_point']
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+
@@ -0,0 +1,95 @@
1
+ require 'jsender'
2
+
3
+ module Soar
4
+ module Policy
5
+ module AccessManager
6
+ module ModelProvider
7
+ class Stub
8
+
9
+ include Jsender
10
+
11
+ ##
12
+ # @param [Hash] meta mapping service identifiers to policy identifiers
13
+ # @param [Hash] policies, policy identifiers map to resource identifiers, that map to an array of authentication_identifiers that are allowed access
14
+ ##
15
+ def initialize(meta: {}, policies: {})
16
+ @meta = meta
17
+ @policies = policies
18
+ end
19
+
20
+ ##
21
+ # @param [String] service_identifier
22
+ # @param [String] resource_identifier
23
+ # @param [Hash] request
24
+ # @return [Hash] a jsend hash
25
+ ##
26
+ def authorized?(service_identifier, resource_identifier, request)
27
+ notifications = []
28
+ decision = false
29
+
30
+ begin
31
+ if ENV['RACK_ENV'] == 'development'
32
+ notifications << 'Authorized in development environment'
33
+ decision = true
34
+ end
35
+
36
+ meta = get_meta(service_identifier)
37
+ policy = meta['policy'] if meta and meta.is_a?(Hash) and meta['policy']
38
+
39
+ if policy.nil?
40
+ decision = true
41
+ notifications << 'No policy associated with service'
42
+ else
43
+ decision, detail = ask_policy(policy, request[:authentication_identifier], service_identifier, resource_identifier, request)
44
+ notifications.concat(detail) if not detail.empty?
45
+ notifications << 'Policy rejected authorization request' if not decision
46
+ notifications << 'Policy approved authorization request' if decision
47
+ end
48
+ rescue SoarSr::ValidationError => ex
49
+ notifications << "AccessManager error authorizing #{service_identifier} for #{resource_identifier}: #{ex.message}"
50
+ decision = false
51
+ rescue Exception => ex
52
+ notifications << "AccessManager error authorizing #{service_identifier} for #{resource_identifier}: #{ex.message}"
53
+ decision = false
54
+ end
55
+ success(notifications, { 'approved' => decision } )
56
+ end
57
+
58
+ private
59
+
60
+ ##
61
+ # @param [String] service identifier
62
+ # @return [Hash, nil] policy hash or nil
63
+ ##
64
+ def get_meta(service_identifier)
65
+ @meta[service_identifier]
66
+ end
67
+
68
+ ##
69
+ # @param [String] policy
70
+ # @param [String] authentication_identifier
71
+ # @param [String] service_identifier
72
+ # @param [String] resource_identifier
73
+ # @param [Hash] request
74
+ # @return [Bool] result
75
+ # @return [Array] notifications
76
+ ##
77
+ def ask_policy(policy, authentication_identifier, service_identifier, resource_identifier, params)
78
+ notifications = []
79
+ result = @policies[policy][resource_identifier].include?(authentication_identifier)
80
+
81
+ if not result
82
+ notifications << 'Policy query result was not success'
83
+ return false, notifications
84
+ end
85
+ return result, notifications
86
+ rescue => ex
87
+ notifications << "Exception while asking policy #{ex.message}"
88
+ return false, notifications
89
+ end
90
+
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,68 @@
1
+ require 'soar/policy/access_manager/model_provider/policy'
2
+ require 'soar/policy/access_manager/model'
3
+ require 'jsender'
4
+ require 'uri'
5
+ require 'ostruct'
6
+
7
+ module Soar
8
+ module Policy
9
+ module AccessManager
10
+ module Test
11
+ module OrchestrationProvider
12
+ class Policy
13
+
14
+ ##
15
+ # for a specific path and service
16
+ # I want to tell the access manager to query a specific url and paramaters for a policy
17
+ # service_identifier = service_name in router
18
+ # resource_identifier = path in router
19
+ ##
20
+ def initialize
21
+ policy_host = ENV['POLICY_HOST'] || 'localhost:8080'
22
+ @meta = {
23
+ 'service_identifier1' => 'allow_policy',
24
+ 'service_identifier2' => 'deny_policy'
25
+ }
26
+ @policies = {
27
+ 'allow_policy' => "http://#{policy_host}/allow",
28
+ 'deny_policy' => "http://#{policy_host}/deny"
29
+ }
30
+ @request = {
31
+ authentication_identifier: 'authentication_identifier1',
32
+ params: {},
33
+ }
34
+ @resource_identifier = 'resource_identifier1'
35
+ end
36
+
37
+ def grant_access
38
+ @service_identifier = 'service_identifier1'
39
+ end
40
+
41
+ def deny_access
42
+ @service_identifier = 'service_identifier2'
43
+ end
44
+
45
+ def no_policy
46
+ @service_identifier = 'service_identifier3'
47
+ end
48
+
49
+ def notification
50
+ @response['data']['notifications']
51
+ end
52
+
53
+ def authorized?
54
+ model_provider = Soar::Policy::AccessManager::ModelProvider::Policy.new(meta: @meta, policies: @policies )
55
+ model = Soar::Policy::AccessManager::Model.new(model_provider)
56
+ @response = model.authorized?(service_identifier: @service_identifier, resource_identifier: @resource_identifier, request: @request)
57
+ end
58
+
59
+ def authorized
60
+ @response['data']['approved']
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,103 @@
1
+ require 'soar/policy/access_manager/model_provider/service_registry'
2
+ require 'soar/policy/access_manager/model'
3
+ require 'jsender'
4
+ require 'uri'
5
+ require 'ostruct'
6
+
7
+ module Soar
8
+ module Policy
9
+ module AccessManager
10
+ module Test
11
+ module OrchestrationProvider
12
+ class ServiceRegistry
13
+
14
+ class Services
15
+ include Jsender
16
+
17
+ def initialize()
18
+ @policy_host = ENV['POLICY_HOST'] || 'localhost:8080'
19
+ @meta = {
20
+ 'service_identifier1' => {
21
+ 'policy' => 'allow'
22
+ },
23
+ 'service_identifier2' => {
24
+ 'policy' => 'deny'
25
+ }
26
+ }
27
+ end
28
+
29
+ def service_by_name(policy)
30
+ case policy
31
+ when 'allow' # allow policy
32
+ success_data({
33
+ "services" => [[{}, { "uris" => [[{}, { "access_point" => "http://#{@policy_host}/allow" }]]}]]
34
+ })
35
+ when 'deny' # deny policy
36
+ success_data({
37
+ "services" => [[{}, { "uris" => [[{}, { "access_point" => "http://#{@policy_host}/deny" }]]}]]
38
+ })
39
+ else # no policy
40
+ success_data({
41
+ "services" => [[{}, { "uris" => [[{}, { "access_point" => "http://#{@policy_host}/" }]]}]]
42
+ })
43
+ end
44
+ end
45
+
46
+ def meta_for_service(service_identifier)
47
+ @meta[service_identifier]
48
+ end
49
+
50
+ end
51
+
52
+ class Stub
53
+ include Jsender
54
+
55
+ attr_accessor :services
56
+
57
+ def initialize(services)
58
+ @services = services
59
+ end
60
+
61
+ end
62
+
63
+ def initialize
64
+ @resource_identifier = 'resource_identifier1'
65
+ @request = {
66
+ params: {},
67
+ authentication_identifier: 'authentication_identifier1'
68
+ }
69
+ end
70
+
71
+ def grant_access
72
+ @service_identifier = 'service_identifier1'
73
+ end
74
+
75
+ def deny_access
76
+ @service_identifier = 'service_identifier2'
77
+ end
78
+
79
+ def no_policy
80
+ @service_identifier = 'service_identifier3'
81
+ end
82
+
83
+ def notification
84
+ @response['data']['notifications']
85
+ end
86
+
87
+ def authorized?
88
+ service_registry = Stub.new(Services.new)
89
+ model_provider = Soar::Policy::AccessManager::ModelProvider::ServiceRegistry.new(service_registry)
90
+ model = Soar::Policy::AccessManager::Model.new(model_provider)
91
+ @response = model.authorized?(service_identifier: @service_identifier, resource_identifier: @resource_identifier, request: @request)
92
+ end
93
+
94
+ def authorized
95
+ @response['data']['approved']
96
+ end
97
+
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,64 @@
1
+ require 'securerandom'
2
+ require 'soar/policy/access_manager/model_provider/stub'
3
+ require 'soar/policy/access_manager/model'
4
+
5
+ module Soar
6
+ module Policy
7
+ module AccessManager
8
+ module Test
9
+ module OrchestrationProvider
10
+ class Stub
11
+
12
+ def initialize
13
+ @meta = {
14
+ 'service_identifier1' => {
15
+ 'policy' => 'policy1'
16
+ }
17
+ }
18
+ @policies = {
19
+ 'policy1' => {
20
+ 'resource_identifier1' => ['authentication_identifier1'],
21
+ 'resource_identifier2' => []
22
+ }
23
+ }
24
+ @request = {
25
+ params: {},
26
+ authentication_identifier: 'authentication_identifier1'
27
+ }
28
+ end
29
+
30
+ def grant_access
31
+ @service_identifier = 'service_identifier1'
32
+ @resource_identifier = 'resource_identifier1'
33
+ end
34
+
35
+ def deny_access
36
+ @service_identifier = 'service_identifier1'
37
+ @resource_identifier = 'resource_identifier2'
38
+ end
39
+
40
+ def no_policy
41
+ @service_identifier = 'service_identifier2'
42
+ @resource_identifier = nil
43
+ end
44
+
45
+ def notification
46
+ @response['data']['notifications']
47
+ end
48
+
49
+ def authorized?
50
+ model_provider = Soar::Policy::AccessManager::ModelProvider::Stub.new(meta: @meta, policies: @policies)
51
+ model = Soar::Policy::AccessManager::Model.new(model_provider)
52
+ @response = model.authorized?(service_identifier: @service_identifier, resource_identifier: @resource_identifier, request: @request)
53
+ end
54
+
55
+ def authorized
56
+ @response['data']['approved']
57
+ end
58
+
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,40 @@
1
+ module Soar
2
+ module Policy
3
+ module AccessManager
4
+ module Test
5
+ class Orchestrator
6
+
7
+ def initialize(orchestration_provider)
8
+ @orchestration_provider = orchestration_provider
9
+ end
10
+
11
+ def grant_access
12
+ @orchestration_provider.grant_access
13
+ end
14
+
15
+ def deny_access
16
+ @orchestration_provider.deny_access
17
+ end
18
+
19
+ def no_policy
20
+ @orchestration_provider.no_policy
21
+ end
22
+
23
+ def notification
24
+ @orchestration_provider.notification
25
+ end
26
+
27
+ def authorized?
28
+ @orchestration_provider.authorized?
29
+ end
30
+
31
+ def authorized
32
+ @orchestration_provider.authorized
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "soar-policy-access_manager"
7
+ spec.version = "1.0.0"
8
+ spec.authors = ["Ernst Van Graan", "Charles Mulder"]
9
+ spec.email = ["ernst.van.graan@hetzner.co.za", "charles.mulder@hetzner.co.za"]
10
+
11
+ spec.summary = %q{Access Manager that uses policy services to determine authorization}
12
+ spec.description = %q{Access Manager that uses policy services to determine authorization}
13
+ spec.homepage = "https://github.com/hetznerZA/soar_policy_access_manager"
14
+ spec.license = "MIT"
15
+
16
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ # if spec.respond_to?(:metadata)
19
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
20
+ # else
21
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
22
+ # end
23
+
24
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_dependency 'soar_sr', "~> 1.1.24"
30
+ spec.add_dependency "jsender", "~> 0.2.0"
31
+
32
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: soar-policy-access_manager
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Ernst Van Graan
8
+ - Charles Mulder
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2016-11-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: soar_sr
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: 1.1.24
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: 1.1.24
28
+ - !ruby/object:Gem::Dependency
29
+ name: jsender
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 0.2.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 0.2.0
42
+ description: Access Manager that uses policy services to determine authorization
43
+ email:
44
+ - ernst.van.graan@hetzner.co.za
45
+ - charles.mulder@hetzner.co.za
46
+ executables: []
47
+ extensions: []
48
+ extra_rdoc_files: []
49
+ files:
50
+ - ".gitignore"
51
+ - ".rspec"
52
+ - ".ruby-gemset"
53
+ - ".ruby-version"
54
+ - Dockerfile.policies
55
+ - Dockerfile.tests
56
+ - Gemfile
57
+ - README.md
58
+ - config.ru
59
+ - docker-compose.test.yml
60
+ - docker-compose.yml
61
+ - lib/soar/policy/access_manager/error.rb
62
+ - lib/soar/policy/access_manager/model.rb
63
+ - lib/soar/policy/access_manager/model_provider/policy.rb
64
+ - lib/soar/policy/access_manager/model_provider/service_registry.rb
65
+ - lib/soar/policy/access_manager/model_provider/stub.rb
66
+ - lib/soar/policy/access_manager/test/orchestration_provider/policy.rb
67
+ - lib/soar/policy/access_manager/test/orchestration_provider/service_registry.rb
68
+ - lib/soar/policy/access_manager/test/orchestration_provider/stub.rb
69
+ - lib/soar/policy/access_manager/test/orchestrator.rb
70
+ - soar-policy-access_manager.gemspec
71
+ homepage: https://github.com/hetznerZA/soar_policy_access_manager
72
+ licenses:
73
+ - MIT
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 2.5.1
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Access Manager that uses policy services to determine authorization
95
+ test_files: []