skull_island 1.1.1 → 1.1.2

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: 2599c9fbc76abcc4be21923b95477c784515165c3891aa5155d7a9d88c5c887b
4
- data.tar.gz: df6f3715f49a4a6cb09118bd446f1c7097fa7d0228dfce497e7396e63921e13c
3
+ metadata.gz: 0cadf0fd8b018522876070d358219f78a94ee7fe5ff94efe1045a961758783ba
4
+ data.tar.gz: 1fb907a4a66a77c9c22ff58ad5c1544001e124c49e8c34610dbcbadaf86da2df
5
5
  SHA512:
6
- metadata.gz: 70be200f4e3721d42c820176d16350e705c40c38254876322181a1509538b0e7612156fbb2ddb29b9a8bdfab522ec8452046b346a2fe059a3bd838f4f2c578bc
7
- data.tar.gz: 7c426dfbf53dbb080ed5211c14ce22b0d5ef78aa06a8e27c1fd1d91b1534065f77554ffc93edc56728fec870aa8bdd591ed10d1fcadf454c4372f897e16f03bf
6
+ metadata.gz: 8324088d97171e7c91205b09f219391827542b23e8635b06f77793b6cff7e86ec1dab1a0d431f25a8d39b03dff38344db961f4cf8944dac9be9d23a470a23c93
7
+ data.tar.gz: 876b5971f3955f88baa89dbb2f6395e52130a0b58625ad56f6d38c08402dba437760d7fa4e3dd4769b4bf0a43942717314065a717b13ecd7be8fd5fb52f7dfa6
data/.rubocop.yml CHANGED
@@ -8,10 +8,10 @@ Metrics/LineLength:
8
8
  Max: 100
9
9
 
10
10
  Metrics/ClassLength:
11
- Max: 170
11
+ Max: 175
12
12
 
13
13
  Metrics/ModuleLength:
14
- Max: 170
14
+ Max: 175
15
15
  Exclude:
16
16
  - 'lib/skull_island/helpers/resource.rb'
17
17
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- skull_island (1.1.1)
4
+ skull_island (1.1.2)
5
5
  deepsort (~> 0.4)
6
6
  erubi (~> 1.8)
7
7
  json (~> 2.1)
data/README.md CHANGED
@@ -318,10 +318,10 @@ From here, the SDK mostly wraps the attributes described in the [Kong API Docs](
318
318
  resource = Resources::Certificate.new
319
319
 
320
320
  # These attributes can be set and read
321
- resource.cert = '-----BEGIN CERTIFICATE-----...' # PEM-encoded public key
321
+ resource.cert = '-----BEGIN CERTIFICATE-----...' # PEM-encoded public key
322
322
  resource.key = '-----BEGIN RSA PRIVATE KEY-----...' # PEM-encoded private key
323
- resource.snis = ['example.com', 'example.org'] # Array of names for which this cert is valid
324
-
323
+ resource.snis = ['example.com', 'example.org'] # Array of names for which this cert is valid
324
+ resource.tags = ['production', 'example'] # Array of tags
325
325
  resource.save
326
326
 
327
327
  # These attributes are read-only
@@ -333,14 +333,15 @@ resource.created_at
333
333
 
334
334
  #### Consumers (and their Credentials)
335
335
 
336
- Note that for Consumer credentials, only [`key-auth`](https://docs.konghq.com/hub/kong-inc/key-auth/) and [`basic-auth`](https://docs.konghq.com/hub/kong-inc/basic-auth/) are currently supported.
336
+ Note that for Consumer credentials, only [`key-auth`](https://docs.konghq.com/hub/kong-inc/key-auth/), [`jwt`](https://docs.konghq.com/hub/kong-inc/jwt/), and [`basic-auth`](https://docs.konghq.com/hub/kong-inc/basic-auth/) are currently supported.
337
337
 
338
338
  ```ruby
339
339
  resource = Resources::Consumer.new
340
340
 
341
341
  # These attributes can be set and read
342
- resource.custom_id = 'user1' # A string
343
- resource.username = 'user1' # A string
342
+ resource.custom_id = 'user1' # A string
343
+ resource.username = 'user1' # A string
344
+ resource.tags = ['production', 'example'] # Array of tags
344
345
 
345
346
  resource.save
346
347
 
@@ -375,9 +376,10 @@ Note that this doesn't _install_ plugins; it only allows using them.
375
376
  resource = Resources::Plugin.new
376
377
 
377
378
  # These attributes can be set and read
378
- resource.name = 'rate-limiting' # The name of the plugin
379
- resource.enabled = true # A Boolean
379
+ resource.name = 'rate-limiting' # The name of the plugin
380
+ resource.enabled = true # A Boolean
380
381
  resource.config = { 'minute' => 50, 'hour' => 1000 } # A Hash of config keys and values
382
+ resource.tags = ['production', 'example'] # Array of tags
381
383
 
382
384
  # Either reference related resources by ID
383
385
  resource.service = { 'id' => '5fd1z584-1adb-40a5-c042-63b19db49x21' }
@@ -418,6 +420,7 @@ Resources::Plugin.schema('acl')
418
420
  resource = Resources::Route.new
419
421
 
420
422
  # These attributes can be set and read
423
+ resource.name = 'example_route'
421
424
  resource.hosts = ['example.com', 'example.org']
422
425
  resource.protocols = ['https']
423
426
  resource.methods = ['GET', 'POST']
@@ -425,6 +428,19 @@ resource.paths = ['/some/path']
425
428
  resource.regex_priority = 10
426
429
  resource.strip_path = false
427
430
  resource.preserve_host = true
431
+ resource.tags = ['production', 'example']
432
+
433
+ # Or, for TCP/TLS routes
434
+ resource.protocols = ['tcp', 'tls']
435
+ resource.sources = [
436
+ { "ip" => "10.1.0.0/16", "port" => 1234 }
437
+ ]
438
+ resource.destinations = [
439
+ { "ip" => "10.1.0.0/16", "port" => 1234 },
440
+ { "ip" => "10.2.2.2" },
441
+ { "port" => 9123 }
442
+ ]
443
+ resource.snis = ['example.com', 'example.org']
428
444
 
429
445
  # Either reference related resources by ID
430
446
  resource.service = { 'id' => '4e13f54a-bbf1-47a8-8777-255fed7116f2' }
@@ -461,6 +477,7 @@ resource.name = 'example-service'
461
477
  resource.retries = 10
462
478
  resource.read_timeout = 60000
463
479
  resource.write_timeout = 60000
480
+ resource.tags = ['production', 'example']
464
481
 
465
482
  resource.save
466
483
 
@@ -513,6 +530,7 @@ resource.healthchecks = {
513
530
  }
514
531
  }
515
532
  }
533
+ resource.tags = ['production', 'example']
516
534
 
517
535
  resource.save
518
536
 
@@ -5,7 +5,7 @@ module SkullIsland
5
5
  # TODO: Thread safety
6
6
  class Resource
7
7
  attr_accessor :api_client
8
- attr_reader :errors
8
+ attr_reader :errors, :entity
9
9
 
10
10
  include Comparable
11
11
  include Validations::Resource
@@ -30,6 +30,14 @@ module SkullIsland
30
30
  test: test
31
31
  )
32
32
 
33
+ JWTCredential.batch_import(
34
+ (
35
+ resource_data.dig('credentials', 'jwt') || []
36
+ ).map { |t| t.merge('consumer' => { 'id' => resource.id }) },
37
+ verbose: verbose,
38
+ test: test
39
+ )
40
+
33
41
  KeyauthCredential.batch_import(
34
42
  (
35
43
  resource_data.dig('credentials', 'key-auth') || []
@@ -41,9 +49,19 @@ module SkullIsland
41
49
  end
42
50
 
43
51
  # Convenience method to add upstream targets
52
+ # rubocop:disable Metrics/AbcSize
53
+ # rubocop:disable Metrics/CyclomaticComplexity
54
+ # rubocop:disable Metrics/PerceivedComplexity
44
55
  def add_credential!(details)
45
- r = if [BasicauthCredential, KeyauthCredential].include? details.class
56
+ r = if [BasicauthCredential, JWTCredential, KeyauthCredential].include? details.class
46
57
  details
58
+ elsif details.is_a?(Hash) && details.key?(:algorithm)
59
+ cred = JWTCredential.new(api_client: api_client)
60
+ cred.algorithm = details[:algorithm]
61
+ cred.key = details[:key] if details[:key]
62
+ cred.secret = details[:secret] if details[:secret]
63
+ cred.rsa_public_key = details[:rsa_public_key] if details[:rsa_public_key]
64
+ cred
47
65
  elsif details.is_a?(Hash) && details.key?(:key)
48
66
  cred = KeyauthCredential.new(api_client: api_client)
49
67
  cred.key = details[:key]
@@ -58,6 +76,9 @@ module SkullIsland
58
76
  r.consumer = self
59
77
  r.save
60
78
  end
79
+ # rubocop:enable Metrics/AbcSize
80
+ # rubocop:enable Metrics/CyclomaticComplexity
81
+ # rubocop:enable Metrics/PerceivedComplexity
61
82
 
62
83
  def credentials
63
84
  creds = {}
@@ -65,6 +86,8 @@ module SkullIsland
65
86
  creds['key-auth'] = keyauth_creds if keyauth_creds
66
87
  basicauth_creds = BasicauthCredential.where(:consumer, self, api_client: api_client)
67
88
  creds['basic-auth'] = basicauth_creds if basicauth_creds
89
+ jwt_creds = JWTCredential.where(:consumer, self, api_client: api_client)
90
+ creds['jwt'] = jwt_creds if jwt_creds
68
91
  creds
69
92
  end
70
93
 
@@ -112,6 +135,11 @@ module SkullIsland
112
135
  cred.export(exclude: 'consumer')
113
136
  end
114
137
  end
138
+ unless credentials['jwt'].empty?
139
+ creds['jwt'] = credentials['jwt'].collect do |cred|
140
+ cred.export(exclude: 'consumer')
141
+ end
142
+ end
115
143
  unless credentials['basic-auth'].empty?
116
144
  creds['basic-auth'] = credentials['basic-auth'].collect do |cred|
117
145
  cred.export(exclude: 'consumer')
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SkullIsland
4
+ # Resource classes go here...
5
+ module Resources
6
+ # The JWTCredential resource class
7
+ #
8
+ # @see https://docs.konghq.com/hub/kong-inc/jwt/ JWT Authentication details
9
+ class JWTCredential < Resource
10
+ property :algorithm, required: true, validate: true
11
+ property :key, validate: true
12
+ property :secret, validated: true
13
+ property :rsa_public_key, validated: true
14
+ property(
15
+ :consumer,
16
+ required: true, validate: true, preprocess: true, postprocess: true
17
+ )
18
+ property :created_at, read_only: true, postprocess: true
19
+
20
+ def self.batch_import(data, verbose: false, test: false)
21
+ raise(Exceptions::InvalidArguments) unless data.is_a?(Array)
22
+
23
+ data.each_with_index do |resource_data, index|
24
+ resource = new
25
+ resource.algorithm = resource_data['algorithm']
26
+ resource.key = resource_data['key'] if resource_data['key']
27
+ resource.secret = resource_data['secret'] if resource_data['secret']
28
+ if resource_data['rsa_public_key']
29
+ resource.rsa_public_key = resource_data['rsa_public_key']
30
+ end
31
+ resource.delayed_set(:consumer, resource_data, 'consumer')
32
+ resource.import_update_or_skip(index: index, verbose: verbose, test: test)
33
+ end
34
+ end
35
+
36
+ def self.relative_uri
37
+ 'jwts'
38
+ end
39
+
40
+ def relative_uri
41
+ consumer ? "#{consumer.relative_uri}/jwt/#{id}" : nil
42
+ end
43
+
44
+ def save_uri
45
+ consumer ? "#{consumer.relative_uri}/jwt" : nil
46
+ end
47
+
48
+ def export(options = {})
49
+ hash = { 'algorithm' => algorithm }
50
+ hash['key'] = key if key
51
+ hash['secret'] = secret if secret
52
+ hash['rsa_public_key'] = rsa_public_key if rsa_public_key
53
+ hash['consumer'] = "<%= lookup :consumer, '#{consumer.username}' %>" if consumer
54
+ [*options[:exclude]].each do |exclude|
55
+ hash.delete(exclude.to_s)
56
+ end
57
+ [*options[:include]].each do |inc|
58
+ hash[inc.to_s] = send(inc.to_sym)
59
+ end
60
+ hash.reject { |_, value| value.nil? }
61
+ end
62
+
63
+ # Keys can't be updated, only created or deleted
64
+ def modified_existing?
65
+ false
66
+ end
67
+
68
+ private
69
+
70
+ def postprocess_consumer(value)
71
+ if value.is_a?(Hash)
72
+ Consumer.new(
73
+ entity: value,
74
+ lazy: true,
75
+ tainted: false
76
+ )
77
+ else
78
+ value
79
+ end
80
+ end
81
+
82
+ def preprocess_consumer(input)
83
+ if input.is_a?(Hash)
84
+ input
85
+ else
86
+ { 'id' => input.id }
87
+ end
88
+ end
89
+
90
+ # Used to validate {#consumer} on set
91
+ def validate_consumer(value)
92
+ # allow either a Consumer object or a Hash
93
+ value.is_a?(Consumer) || value.is_a?(Hash)
94
+ end
95
+
96
+ # Used to validate {#algorithm} on set
97
+ def validate_algorithm(value)
98
+ # allow a String
99
+ %w[HS256 HS384 HS512 RS256 ES256].include? value
100
+ end
101
+
102
+ # Used to validate {#key} on set
103
+ def validate_key(value)
104
+ # allow a String
105
+ value.is_a?(String)
106
+ end
107
+
108
+ # Used to validate {#secret} on set
109
+ def validate_secret(value)
110
+ # allow a String
111
+ value.is_a?(String)
112
+ end
113
+
114
+ # Used to validate {#rsa_public_key} on set
115
+ def validate_rsa_public_key(value)
116
+ # allow a String
117
+ value.is_a?(String)
118
+ end
119
+ end
120
+ end
121
+ end
@@ -42,6 +42,10 @@ module SkullIsland
42
42
  api_client.get("#{relative_uri}/schema/#{name}")
43
43
  end
44
44
 
45
+ def digest_properties
46
+ super.reject { |k| %i[run_on].include? k }
47
+ end
48
+
45
49
  def export(options = {})
46
50
  hash = {
47
51
  'name' => name,
@@ -30,8 +30,8 @@ module SkullIsland
30
30
  resource.name = rdata['name']
31
31
  resource.slots = rdata['slots'] if rdata['slots']
32
32
  resource.hash_on = rdata['hash_on']
33
- resource.hash_fallback = rdata['hash_fallback']
34
- resource.hash_on_header = rdata['hash_on_header']
33
+ resource.hash_fallback = rdata['hash_fallback'] if rdata['hash_fallback']
34
+ resource.hash_on_header = rdata['hash_on_header'] if rdata['hash_on_header']
35
35
  if rdata['hash_fallback_header']
36
36
  resource.hash_fallback_header = rdata['hash_fallback_header']
37
37
  end
@@ -78,12 +78,7 @@ module SkullIsland
78
78
  end
79
79
 
80
80
  def target(target_id)
81
- UpstreamTarget.new(
82
- entity: { 'id' => target_id, 'upstream' => { 'id' => id } },
83
- lazy: true,
84
- tainted: false,
85
- api_client: api_client
86
- )
81
+ targets.where(id: target_id).first
87
82
  end
88
83
 
89
84
  def targets
@@ -176,10 +171,10 @@ module SkullIsland
176
171
  value.is_a?(String) && [hash_on, hash_fallback].include?('cookie')
177
172
  end
178
173
 
179
- # Used to validate {#hash_cookie_path} on set
180
- def validate_hash_cookie_path(value)
181
- # only String is allowed and only when {#hash_on} or {#hash_fallback} is set to 'cookie'
182
- value.is_a?(String) && [hash_on, hash_fallback].include?('cookie')
174
+ # Used to validate {#hash_on_cookie_path} on set
175
+ def validate_hash_on_cookie_path(value)
176
+ # only String is allowed
177
+ value.is_a?(String)
183
178
  end
184
179
 
185
180
  # Used to validate {#name} on set
@@ -29,6 +29,12 @@ module SkullIsland
29
29
  end
30
30
  end
31
31
 
32
+ def self.all(options = {})
33
+ api_client = options[:api_client] || APIClient.instance
34
+
35
+ Upstream.all(api_client: api_client).map(&:targets).reduce(&:merge)
36
+ end
37
+
32
38
  def self.get(id, options = {})
33
39
  if options[:upstream]&.is_a?(Upstream)
34
40
  options[:upstream].target(id)
@@ -38,6 +44,19 @@ module SkullIsland
38
44
  end
39
45
  end
40
46
 
47
+ # Tests for an existing version of this resource based on its properties rather than its `id`
48
+ def find_by_digest
49
+ result = self.class.where(:digest, digest) # matching digest means the equivalent resource
50
+ if result.size == 1
51
+ @entity = result.first.entity
52
+ @lazy = false
53
+ @tainted = false
54
+ true
55
+ else
56
+ false
57
+ end
58
+ end
59
+
41
60
  def relative_uri
42
61
  upstream ? "#{upstream.relative_uri}/targets/#{id}" : nil
43
62
  end
@@ -111,7 +130,7 @@ module SkullIsland
111
130
  def validate_target(value)
112
131
  # only URIs or specific strings
113
132
  value.is_a?(URI) || (
114
- value.is_a?(String) && value.match?(/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{1,5}/)
133
+ value.is_a?(String) && value.match?(/[\w\d.-]+:\d{1,5}/)
115
134
  )
116
135
  end
117
136
 
@@ -4,6 +4,6 @@ module SkullIsland
4
4
  VERSION = [
5
5
  1, # Major
6
6
  1, # Minor
7
- 1 # Patch
7
+ 2 # Patch
8
8
  ].join('.')
9
9
  end
data/lib/skull_island.rb CHANGED
@@ -46,6 +46,7 @@ require 'skull_island/validations/resource'
46
46
  require 'skull_island/resource'
47
47
  require 'skull_island/resources/certificate'
48
48
  require 'skull_island/resources/basicauth_credential'
49
+ require 'skull_island/resources/jwt_credential'
49
50
  require 'skull_island/resources/keyauth_credential'
50
51
  require 'skull_island/resources/consumer'
51
52
  require 'skull_island/resources/plugin'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skull_island
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Gnagy
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-05-13 00:00:00.000000000 Z
11
+ date: 2019-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deepsort
@@ -251,6 +251,7 @@ files:
251
251
  - lib/skull_island/resources/basicauth_credential.rb
252
252
  - lib/skull_island/resources/certificate.rb
253
253
  - lib/skull_island/resources/consumer.rb
254
+ - lib/skull_island/resources/jwt_credential.rb
254
255
  - lib/skull_island/resources/keyauth_credential.rb
255
256
  - lib/skull_island/resources/plugin.rb
256
257
  - lib/skull_island/resources/route.rb
@@ -283,7 +284,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
283
284
  - !ruby/object:Gem::Version
284
285
  version: '0'
285
286
  requirements: []
286
- rubygems_version: 3.0.3
287
+ rubygems_version: 3.0.4
287
288
  signing_key:
288
289
  specification_version: 4
289
290
  summary: Ruby SDK for Kong