soar-registry-directory 1.0.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 +4 -4
- data/README.md +35 -4
- data/lib/soar/registry/directory/error.rb +1 -0
- data/lib/soar/registry/directory/model.rb +1 -0
- data/lib/soar/registry/directory/provider/dynamo_db.rb +3 -4
- data/lib/soar/registry/directory/provider/ldap.rb +103 -0
- data/lib/soar/registry/directory/provider/stub.rb +2 -2
- data/lib/soar/registry/directory/test/fixtures/entries.json +0 -4
- data/lib/soar/registry/directory/test/fixtures/entries.ldif +0 -0
- data/lib/soar/registry/directory/test/fixtures/table_structure.json +1 -22
- data/lib/soar/registry/directory/test/orchestrator.rb +1 -0
- data/lib/soar/registry/directory/test/provider/dynamo_db.rb +0 -1
- data/lib/soar/registry/directory/test/provider/ldap.rb +132 -0
- data/lib/soar/registry/directory/test/provider/stub.rb +1 -2
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70a565fb09b0f4af26cfb869c32c41aa5809b27e
|
4
|
+
data.tar.gz: 2fb0d1201fce3c266bf570315b2524005a61776b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cfbebba8afea49661752f2fe56a23f57c3874c3595af6b23f90fee6a30697258733b83836254df42e9552f1d841de4c8025ee7b7359f7be5871bd428cb72a049
|
7
|
+
data.tar.gz: 12784a7f75d25c92dabdcd1f3fa88ec779bac1dfd5173507f0a29767ffc8ac60ef3e5816e52ac9ddb05b57f92bb92a32e69320dee5a1c0616f4b191c97b66181
|
data/README.md
CHANGED
@@ -23,7 +23,6 @@ Create an instance of the stub provider by passing in the name, primary key and
|
|
23
23
|
> require 'soar/registry/directory'
|
24
24
|
> provider = Soar::Registry::Directory::Provider::Stub.new({
|
25
25
|
table: "mytable",
|
26
|
-
primary_key: "uuid",
|
27
26
|
index: ["uuid", "email"]
|
28
27
|
})
|
29
28
|
```
|
@@ -36,7 +35,6 @@ Create an instance of the stub provider by passing in the name, primary key and
|
|
36
35
|
},
|
37
36
|
table: "mytable",
|
38
37
|
index: ['uuid', 'email'],
|
39
|
-
primary_key: "uuid",
|
40
38
|
configuration: {
|
41
39
|
region: 'us-west-2'
|
42
40
|
endpoint: 'http://localhost:8000'
|
@@ -45,6 +43,23 @@ Create an instance of the stub provider by passing in the name, primary key and
|
|
45
43
|
|
46
44
|
```
|
47
45
|
|
46
|
+
### LDAP Provider
|
47
|
+
```ruby
|
48
|
+
> provider = Soar::Registry::Directory::Provider::Ldap.new({
|
49
|
+
base: 'dc=hetzner,dc=co,dc=za',
|
50
|
+
index: ['entryuuid', 'mail'],
|
51
|
+
config: {
|
52
|
+
host: 'localhost',
|
53
|
+
port: 389
|
54
|
+
},
|
55
|
+
attributes: ['entryuuid', 'cn', 'mail', 'sn'],
|
56
|
+
credentials: {
|
57
|
+
username: 'cn=admin,dc=hetzner,dc=co,dc=za'
|
58
|
+
password: 'secret'
|
59
|
+
}
|
60
|
+
})
|
61
|
+
```
|
62
|
+
|
48
63
|
### The Model
|
49
64
|
```ruby
|
50
65
|
> directory = Soar::Registry::Directory.new(provider)
|
@@ -70,8 +85,8 @@ exit $EXIT_CODE
|
|
70
85
|
|
71
86
|
#### Local
|
72
87
|
```bash
|
73
|
-
$ docker-compose --file docker-compose.dynamo_db.yml up
|
74
|
-
$ CONFIG_FILE=config.dynamo_db.yml
|
88
|
+
$ docker-compose --file docker-compose.dynamo_db.yml up --remove-orphans
|
89
|
+
$ CONFIG_FILE=config.dynamo_db.yml TEST_ORCHESTRATION_PROVIDER=DynamoDb cucumber
|
75
90
|
```
|
76
91
|
|
77
92
|
#### CI
|
@@ -80,3 +95,19 @@ docker-compose --file docker-compose.ci.dynamo_db.yml up --abort-on-container-ex
|
|
80
95
|
EXIT_CODE=$(docker ps -a -f "name=soar-registry-directory-test-provider-dynamo_db" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
|
81
96
|
exit $EXIT_CODE
|
82
97
|
```
|
98
|
+
|
99
|
+
### LDAP provider
|
100
|
+
|
101
|
+
#### Local
|
102
|
+
```bash
|
103
|
+
$ docker-compose --file docker-compose.ldap.yml up --remove-orphans
|
104
|
+
$ CONFIG_FILE=config.ldap.yml TEST_ORCHESTRATION_PROVIDER=Ldap cucumber
|
105
|
+
```
|
106
|
+
|
107
|
+
#### CI
|
108
|
+
```bash
|
109
|
+
docker-compose --file docker-compose.ci.ldap.yml up --abort-on-container-exit --remove-orphans --build --force-recreate
|
110
|
+
EXIT_CODE=$(docker ps -a -f "name=soar-registry-directory-test-provider-ldap" -q | xargs docker inspect -f "{{ .State.ExitCode }}")
|
111
|
+
exit $EXIT_CODE
|
112
|
+
```
|
113
|
+
|
@@ -14,13 +14,12 @@ module Soar
|
|
14
14
|
##
|
15
15
|
# @param credentials [Hash] { username: 'username', password: 'secret'}
|
16
16
|
# @param table [String]
|
17
|
-
# @param primary_key [String]
|
18
17
|
# @param index [Array] primary key should be the first item
|
19
18
|
# @param configuration [Hash] { region: 'us-west-2', endpoint: 'http://localhost:8000' }
|
20
19
|
##
|
21
|
-
def initialize(credentials:
|
20
|
+
def initialize(credentials: , table: , index: , configuration: )
|
22
21
|
@table_name = table
|
23
|
-
@primary_key =
|
22
|
+
@primary_key = index[0]
|
24
23
|
@index = index
|
25
24
|
@credentials = Hashie.symbolize_keys(credentials)
|
26
25
|
configuration[:credentials] = Aws::Credentials.new(@credentials[:username], @credentials[:password])
|
@@ -70,7 +69,7 @@ module Soar
|
|
70
69
|
}
|
71
70
|
}
|
72
71
|
|
73
|
-
options.merge!({index_name: "#{key}
|
72
|
+
options.merge!({index_name: "#{key}-index"}) if @index.include?(key)
|
74
73
|
identity = @client.query(options)
|
75
74
|
identity.items.map { |item|
|
76
75
|
Hashie.stringify_keys(item)
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'soar/registry/directory/error'
|
2
|
+
require 'net/ldap'
|
3
|
+
|
4
|
+
module Soar
|
5
|
+
module Registry
|
6
|
+
module Directory
|
7
|
+
module Provider
|
8
|
+
class Ldap
|
9
|
+
|
10
|
+
##
|
11
|
+
# @param config [Hash]
|
12
|
+
# @param base [String] ldap tree base eg 'dc=hetzner,dc=co,dc=za'
|
13
|
+
# @param attributes [Array] array of attributes to return for queries
|
14
|
+
# @param credentials [Hash]
|
15
|
+
##
|
16
|
+
def initialize(config: , base: , attributes: , index: , credentials: )
|
17
|
+
@base = base
|
18
|
+
@index = index
|
19
|
+
@attributes = attributes
|
20
|
+
@config = {
|
21
|
+
host: config[:host],
|
22
|
+
port: config[:port],
|
23
|
+
auth: {
|
24
|
+
method: :simple,
|
25
|
+
username: credentials[:username],
|
26
|
+
password: credentials[:password]
|
27
|
+
}
|
28
|
+
}
|
29
|
+
@ldap = Net::LDAP.new(@config)
|
30
|
+
@ldap.bind
|
31
|
+
end
|
32
|
+
|
33
|
+
def put(entry)
|
34
|
+
@ldap.add({
|
35
|
+
dn: entry[:dn],
|
36
|
+
attributes: entry[:attributes]
|
37
|
+
})
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# @param [String] uuid primary key of the identity
|
42
|
+
# @return [Hash] the identity
|
43
|
+
# @raise [Soar::Registry::Directory::Error::NoEntriesFound] if primary key not found
|
44
|
+
# @raise [Soar::Registry::Directory::Error::MultipleEntriesFound] if multiple matches found
|
45
|
+
##
|
46
|
+
def fetch(uuid)
|
47
|
+
result = @ldap.search({
|
48
|
+
base: @base,
|
49
|
+
attributes: @attributes,
|
50
|
+
filter: Net::LDAP::Filter.eq(@index[0], uuid),
|
51
|
+
return_result: true
|
52
|
+
})
|
53
|
+
raise Soar::Registry::Directory::Error::NoEntriesFound if result.empty?
|
54
|
+
raise Soar::Registry::Directory::Error::MultipleEntriesFound if result.length > 1
|
55
|
+
response = {}
|
56
|
+
@attributes.each { |attribute|
|
57
|
+
response[attribute.to_sym] = result[0][attribute.to_sym][0]
|
58
|
+
}
|
59
|
+
response
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
##
|
64
|
+
# @param key, named index [String]
|
65
|
+
# @param value [String]
|
66
|
+
# @return [Array] list of identities
|
67
|
+
# @raise [ArgumentError] if value or named index is not specified
|
68
|
+
##
|
69
|
+
def search(key, value)
|
70
|
+
result = []
|
71
|
+
entries = @ldap.search({
|
72
|
+
base: @base,
|
73
|
+
filter: Net::LDAP::Filter.eq(key, value),
|
74
|
+
attributes: @attributes,
|
75
|
+
return_result: true
|
76
|
+
})
|
77
|
+
|
78
|
+
entries.each { |entry|
|
79
|
+
response = {}
|
80
|
+
@attributes.each { |attribute|
|
81
|
+
response[attribute.to_sym] = entry[attribute.to_sym][0]
|
82
|
+
}
|
83
|
+
result << response
|
84
|
+
}
|
85
|
+
return result
|
86
|
+
end
|
87
|
+
|
88
|
+
##
|
89
|
+
# @return [Array] a list of primary keys and global secondary indexes
|
90
|
+
##
|
91
|
+
def index
|
92
|
+
@index
|
93
|
+
end
|
94
|
+
|
95
|
+
def delete(dn)
|
96
|
+
@ldap.delete(dn: dn)
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -16,9 +16,9 @@ module Soar
|
|
16
16
|
# @param primary_key [String]
|
17
17
|
# @param index [Array] primary key should be the first item
|
18
18
|
##
|
19
|
-
def initialize(table:
|
19
|
+
def initialize(table: , index: )
|
20
20
|
@table = table
|
21
|
-
@primary_key =
|
21
|
+
@primary_key = index[0]
|
22
22
|
@index = index
|
23
23
|
@@interface.clear
|
24
24
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
[
|
2
2
|
{
|
3
3
|
"uuid": "identity-62936e70-1815-439b-bf89-8492855a7e6b",
|
4
|
-
"entity_id": "entity-2d931510-d99f-494a-8c67-87feb05e1594",
|
5
4
|
"email": "test+publisher@hetzner.co.za",
|
6
5
|
"roles": {
|
7
6
|
"staff": {
|
@@ -14,7 +13,6 @@
|
|
14
13
|
},
|
15
14
|
{
|
16
15
|
"uuid": "identity-43353f18-8afe-11e6-ae22-56b6b6499611",
|
17
|
-
"entity_id": "entity-2d931510-d99f-494a-8c67-87feb05e1594",
|
18
16
|
"email": "test+consumer@hetzner.co.za",
|
19
17
|
"roles": {
|
20
18
|
"staff": {},
|
@@ -26,7 +24,6 @@
|
|
26
24
|
},
|
27
25
|
{
|
28
26
|
"uuid": "identity-820d5660-2204-4f7d-8c04-746313439b81",
|
29
|
-
"entity_id": "entity-bad85eb9-0713-4da7-8d36-07a8e4b00eab",
|
30
27
|
"email": "admin@hetzner.co.za",
|
31
28
|
"roles": {
|
32
29
|
"staff": {},
|
@@ -48,7 +45,6 @@
|
|
48
45
|
},
|
49
46
|
{
|
50
47
|
"uuid": "identity-1ff472a6-8df3-4f13-82c3-89fde26db3cf",
|
51
|
-
"entity_id": "entity-bad85eb9-0713-4da7-8d36-07a8e4b00eab",
|
52
48
|
"email": "none@example.com",
|
53
49
|
"client_nr": "C123456789",
|
54
50
|
"roles": {
|
File without changes
|
@@ -11,10 +11,6 @@
|
|
11
11
|
"attribute_name": "uuid",
|
12
12
|
"attribute_type": "S"
|
13
13
|
},
|
14
|
-
{
|
15
|
-
"attribute_name": "entity_id",
|
16
|
-
"attribute_type": "S"
|
17
|
-
},
|
18
14
|
{
|
19
15
|
"attribute_name": "email",
|
20
16
|
"attribute_type": "S"
|
@@ -22,7 +18,7 @@
|
|
22
18
|
],
|
23
19
|
"global_secondary_indexes": [
|
24
20
|
{
|
25
|
-
"index_name": "
|
21
|
+
"index_name": "email-index",
|
26
22
|
"key_schema": [
|
27
23
|
{
|
28
24
|
"attribute_name": "email",
|
@@ -32,23 +28,6 @@
|
|
32
28
|
"projection": {
|
33
29
|
"projection_type": "ALL"
|
34
30
|
|
35
|
-
},
|
36
|
-
"provisioned_throughput": {
|
37
|
-
"read_capacity_units": 10,
|
38
|
-
"write_capacity_units": 10
|
39
|
-
}
|
40
|
-
},
|
41
|
-
{
|
42
|
-
"index_name": "entity_id_index",
|
43
|
-
"key_schema": [
|
44
|
-
{
|
45
|
-
"attribute_name": "entity_id",
|
46
|
-
"key_type": "HASH"
|
47
|
-
}
|
48
|
-
],
|
49
|
-
"projection": {
|
50
|
-
"projection_type": "ALL"
|
51
|
-
|
52
31
|
},
|
53
32
|
"provisioned_throughput": {
|
54
33
|
"read_capacity_units": 10,
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'soar/registry/directory'
|
2
|
+
|
3
|
+
module Soar
|
4
|
+
module Registry
|
5
|
+
module Directory
|
6
|
+
module Test
|
7
|
+
module Provider
|
8
|
+
class Ldap
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@configuration = YAML.load_file("config/#{ENV['CONFIG_FILE']}")
|
12
|
+
@base = @configuration['provider']['base']
|
13
|
+
@config = {
|
14
|
+
host: @configuration['provider']['config']['host'],
|
15
|
+
port: @configuration['provider']['config']['port']
|
16
|
+
}
|
17
|
+
@credentials = {
|
18
|
+
username: @configuration['provider']['credentials']['username'],
|
19
|
+
password: @configuration['provider']['credentials']['password']
|
20
|
+
}
|
21
|
+
@index = @configuration['provider']['index']
|
22
|
+
@entries = [{
|
23
|
+
dn: "cn=John Smith,#{@base}",
|
24
|
+
attributes: {
|
25
|
+
cn: "John Smith",
|
26
|
+
mail: "test@example.com",
|
27
|
+
objectclass: ["inetOrgPerson", "top"],
|
28
|
+
sn: "Smith"
|
29
|
+
}
|
30
|
+
}, {
|
31
|
+
dn: "cn=Sarel Cilliers,#{@base}",
|
32
|
+
attributes: {
|
33
|
+
cn: "Sarel Cilliers",
|
34
|
+
mail: "sarel@example.com",
|
35
|
+
objectclass: ["inetOrgPerson", "top"],
|
36
|
+
sn: "Cilliers"
|
37
|
+
}
|
38
|
+
}]
|
39
|
+
end
|
40
|
+
|
41
|
+
def given_configured_directory
|
42
|
+
provider = Soar::Registry::Directory::Provider::Ldap.new({
|
43
|
+
base: @base,
|
44
|
+
index: @index,
|
45
|
+
config: {
|
46
|
+
host: @config[:host],
|
47
|
+
port: @config[:port]
|
48
|
+
},
|
49
|
+
attributes: ['entryuuid', 'cn', 'mail', 'sn'],
|
50
|
+
credentials: {
|
51
|
+
username: @credentials[:username],
|
52
|
+
password: @credentials[:password]
|
53
|
+
}
|
54
|
+
})
|
55
|
+
@directory = Soar::Registry::Directory.new(provider)
|
56
|
+
@entries.each { |entry|
|
57
|
+
provider.delete(entry[:dn])
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Adds @entries to datastore using ldap protocol
|
63
|
+
# Adds entryuuid to @entries
|
64
|
+
##
|
65
|
+
def given_existing_data
|
66
|
+
@entries.each{ |entry|
|
67
|
+
@directory.put(entry)
|
68
|
+
result = @directory.search("mail", entry[:attributes][:mail])
|
69
|
+
entry[:attributes][:entryuuid] = result[0][:entryuuid]
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def put_entry
|
74
|
+
@directory.put(@entries[0])
|
75
|
+
result = @directory.search("mail", @entries[0][:attributes][:mail])
|
76
|
+
@entries[0][:attributes][:entryuuid] = result[0][:entryuuid]
|
77
|
+
end
|
78
|
+
|
79
|
+
def search_for_entry
|
80
|
+
@result = @directory.search("mail", @entries[0][:attributes][:mail])
|
81
|
+
end
|
82
|
+
|
83
|
+
def request_index
|
84
|
+
@result = @directory.index
|
85
|
+
end
|
86
|
+
|
87
|
+
def fetch_entry
|
88
|
+
begin
|
89
|
+
@result = @directory.fetch(@entries[0][:attributes][:entryuuid])
|
90
|
+
rescue Soar::Registry::Directory::Error::NoEntriesFound
|
91
|
+
@error = true
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def persisted?
|
96
|
+
result = @directory.fetch(@entries[0][:attributes][:entryuuid])
|
97
|
+
entry = @entries[0][:attributes]
|
98
|
+
entry.delete(:objectclass)
|
99
|
+
result == entry
|
100
|
+
end
|
101
|
+
|
102
|
+
def returned?
|
103
|
+
entry = @entries[0][:attributes]
|
104
|
+
entry.delete(:objectclass)
|
105
|
+
@result == [entry]
|
106
|
+
end
|
107
|
+
|
108
|
+
def index?
|
109
|
+
@result == @index
|
110
|
+
end
|
111
|
+
|
112
|
+
def single_entry?
|
113
|
+
entry = @entries[0][:attributes]
|
114
|
+
entry.delete(:objectclass)
|
115
|
+
@result == entry
|
116
|
+
end
|
117
|
+
|
118
|
+
def no_entries_found?
|
119
|
+
@error == true
|
120
|
+
end
|
121
|
+
|
122
|
+
def no_matching_entries?
|
123
|
+
@result == []
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
@@ -12,12 +12,11 @@ module Soar
|
|
12
12
|
"identifier" => SecureRandom.hex
|
13
13
|
}
|
14
14
|
|
15
|
-
@@index = ["
|
15
|
+
@@index = ["uuid", "identifier"]
|
16
16
|
|
17
17
|
def given_configured_directory
|
18
18
|
provider = Soar::Registry::Directory::Provider::Stub.new({
|
19
19
|
table: "identities",
|
20
|
-
primary_key: "uuid",
|
21
20
|
index: @@index
|
22
21
|
})
|
23
22
|
@directory = Soar::Registry::Directory.new(provider)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: soar-registry-directory
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Mulder
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
version: '2.6'
|
68
68
|
- - ">="
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
version: 2.6.
|
70
|
+
version: 2.6.38
|
71
71
|
type: :runtime
|
72
72
|
prerelease: false
|
73
73
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -77,7 +77,7 @@ dependencies:
|
|
77
77
|
version: '2.6'
|
78
78
|
- - ">="
|
79
79
|
- !ruby/object:Gem::Version
|
80
|
-
version: 2.6.
|
80
|
+
version: 2.6.38
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
82
|
name: hashie
|
83
83
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,6 +98,20 @@ dependencies:
|
|
98
98
|
- - ">="
|
99
99
|
- !ruby/object:Gem::Version
|
100
100
|
version: 3.4.6
|
101
|
+
- !ruby/object:Gem::Dependency
|
102
|
+
name: net-ldap
|
103
|
+
requirement: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - "~>"
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: 0.15.0
|
108
|
+
type: :runtime
|
109
|
+
prerelease: false
|
110
|
+
version_requirements: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - "~>"
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: 0.15.0
|
101
115
|
description: Directories for soar registries
|
102
116
|
email: charles.mulder@hetzner.co.za
|
103
117
|
executables: []
|
@@ -109,11 +123,14 @@ files:
|
|
109
123
|
- lib/soar/registry/directory/error.rb
|
110
124
|
- lib/soar/registry/directory/model.rb
|
111
125
|
- lib/soar/registry/directory/provider/dynamo_db.rb
|
126
|
+
- lib/soar/registry/directory/provider/ldap.rb
|
112
127
|
- lib/soar/registry/directory/provider/stub.rb
|
113
128
|
- lib/soar/registry/directory/test/fixtures/entries.json
|
129
|
+
- lib/soar/registry/directory/test/fixtures/entries.ldif
|
114
130
|
- lib/soar/registry/directory/test/fixtures/table_structure.json
|
115
131
|
- lib/soar/registry/directory/test/orchestrator.rb
|
116
132
|
- lib/soar/registry/directory/test/provider/dynamo_db.rb
|
133
|
+
- lib/soar/registry/directory/test/provider/ldap.rb
|
117
134
|
- lib/soar/registry/directory/test/provider/stub.rb
|
118
135
|
homepage: https://gitlab.host-h.net/registries/directory
|
119
136
|
licenses:
|