train-rest 0.3.2 → 0.4.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: 45c7cbd2b28a41c2eba5d219545d4ff7e0bfbaf6305f239630352ce463bf8424
4
- data.tar.gz: 6e5de06f898f95a2a2c519ac45bae42c797e39840e2aec0c80bb6204d5e69591
3
+ metadata.gz: 1550899c2f8aad404793b83b1f7700ece96937efc8b78cb1eb7aebb8d6d2a2a2
4
+ data.tar.gz: b9251734100cc43233504afbe6e8d6fbd11bec1b07a16db7884720e907a164e2
5
5
  SHA512:
6
- metadata.gz: 48c46e55522807433595d89e5bf414a3d487c9167b7f8fd365a8a64645789fd533fc614a835b319f8d8e6590d907b01c1fbf864ea80fc735d333d2961c065ddf
7
- data.tar.gz: 9e24f8c14aa8000541aade240e46d0aaaac67a70a337672f821f9760336da98f482af80337e963ef64c218637f4ed36b059744c8dcc1a2d21cd08d73b5e5154d
6
+ metadata.gz: 1630381a0f378a7a4a275202fc19a60f71579b99f6b1ae50229c72b67cce2466e5d8b2f4a5b5c3c23f8c1c5c4ccc4817f768fc36cd65c3c8ac9c1b81609b1994
7
+ data.tar.gz: 02ed2d874ac736d016fc75f24a1c02e8b9209ec5f43cbb9281bf615106a04d53f4d49d26682e84cb7c2b7ab6a949dc2589823a769e9b87aa3c03aa428c50d919
data/README.md CHANGED
@@ -34,7 +34,18 @@ Identifier: `auth_type: :anonymous`
34
34
  No actions for authentication, logging in/out or session handing are made. This
35
35
  assumes a public API.
36
36
 
37
- ### Basic Authentication
37
+ ### Authtype Apikey
38
+
39
+ This will inject a HTTP header `Authorization: Apikey xxxx` with the passed
40
+ API key into requests.
41
+
42
+ Identifier: `auth_type: :authtype_apikey`
43
+
44
+ | Option | Explanation | Default |
45
+ | -------------------- | --------------------------------------- | ----------- |
46
+ | `apikey` | API Key for authentication | _required_ |
47
+
48
+ ### Basic (RFC 2617)
38
49
 
39
50
  Identifier: `auth_type: :basic`
40
51
 
@@ -46,6 +57,29 @@ Identifier: `auth_type: :basic`
46
57
  If you supply a `username` and a `password`, authentication will automatically
47
58
  switch to `basic`.
48
59
 
60
+ ### Bearer (RFC 7650)
61
+
62
+ This will inject a HTTP header `Authorization: Bearer xxxx` with the passed
63
+ token into requests.
64
+
65
+ Identifier: `auth_type: :bearer`
66
+
67
+ | Option | Explanation | Default |
68
+ | -------------------- | --------------------------------------- | ----------- |
69
+ | `token` | Tokenb to pass | _required_ |
70
+
71
+ ### Header-based
72
+
73
+ This will inject an additional HTTP header with the passed value. If no name
74
+ for the header is passed, it will default to `X-API-Key`.
75
+
76
+ Identifier: `auth_type: :header`
77
+
78
+ | Option | Explanation | Default |
79
+ | -------------------- | --------------------------------------- | ----------- |
80
+ | `apikey` | API Key for authentication | _required_ |
81
+ | `header` | Name of the HTTP header to include | `X-API-Key` |
82
+
49
83
  ### Redfish
50
84
 
51
85
  Identifier: `auth_type: :redfish`
@@ -0,0 +1,24 @@
1
+ require "base64" unless defined?(Base64)
2
+
3
+ require_relative "../auth_handler"
4
+
5
+ module TrainPlugins
6
+ module Rest
7
+ # Authentication via "Apikey" type in Authorization headers.
8
+ #
9
+ # Could not find a norm for this, just references in e.g. ElasticSearch & Cloud Conformity APIs.
10
+ class AuthtypeApikey < AuthHandler
11
+ def check_options
12
+ raise ArgumentError.new("Need :apikey for `Authorization: Apikey` authentication") unless options[:apikey]
13
+ end
14
+
15
+ def auth_parameters
16
+ {
17
+ headers: {
18
+ "Authorization" => format("Apikey %s", options[:apikey]),
19
+ },
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -4,11 +4,13 @@ require_relative "../auth_handler"
4
4
 
5
5
  module TrainPlugins
6
6
  module Rest
7
- # Authentication via HTTP Basic Authentication
7
+ # Authentication via Basic Authentication.
8
+ #
9
+ # @see https://www.rfc-editor.org/rfc/rfc2617#section-4.1
8
10
  class Basic < AuthHandler
9
11
  def check_options
10
- raise ArgumentError.new("Need username for Basic authentication") unless options[:username]
11
- raise ArgumentError.new("Need password for Basic authentication") unless options[:password]
12
+ raise ArgumentError.new("Need :username for Basic authentication") unless options[:username]
13
+ raise ArgumentError.new("Need :password for Basic authentication") unless options[:password]
12
14
  end
13
15
 
14
16
  def auth_parameters
@@ -0,0 +1,24 @@
1
+ require "base64" unless defined?(Base64)
2
+
3
+ require_relative "../auth_handler"
4
+
5
+ module TrainPlugins
6
+ module Rest
7
+ # Authentication via Bearer Authentication.
8
+ #
9
+ # @see https://datatracker.ietf.org/doc/html/rfc6750#section-2.1
10
+ class Bearer < AuthHandler
11
+ def check_options
12
+ raise ArgumentError.new("Need :token for Bearer authentication") unless options[:token]
13
+ end
14
+
15
+ def auth_parameters
16
+ {
17
+ headers: {
18
+ "Authorization" => format("Bearer %s", options[:token]),
19
+ },
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require_relative "../auth_handler"
2
+
3
+ module TrainPlugins
4
+ module Rest
5
+ # Authentication via additional Header.
6
+ #
7
+ # Header name defaults to "X-API-Key"
8
+ class Header < AuthHandler
9
+ def check_options
10
+ raise ArgumentError.new("Need :apikey for Header-based authentication") unless options[:apikey]
11
+
12
+ options[:header] = "X-API-Key" unless options[:header]
13
+ end
14
+
15
+ def auth_parameters
16
+ {
17
+ headers: {
18
+ options[:header] => options[:apikey],
19
+ },
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -13,7 +13,16 @@ module TrainPlugins
13
13
  #
14
14
  # @return [String]
15
15
  def self.name
16
- self.to_s.split("::").last.downcase
16
+ class_name = self.to_s.split("::").last
17
+
18
+ convert_to_snake_case(class_name)
19
+ end
20
+
21
+ # List authentication handlers
22
+ #
23
+ # @return [Array] Classes derived from `AuthHandler`
24
+ def self.descendants
25
+ ObjectSpace.each_object(Class).select { |klass| klass < self }
17
26
  end
18
27
 
19
28
  # Store authenticator options and trigger validation
@@ -29,10 +38,18 @@ module TrainPlugins
29
38
  # @raise [ArgumentError] if options are not as needed
30
39
  def check_options; end
31
40
 
32
- # Handle Login
41
+ # Handle login
33
42
  def login; end
34
43
 
35
- # Handle Logout
44
+ # Handle session renewal
45
+ def renew_session; end
46
+
47
+ # Return if session renewal needs to happen soon
48
+ #
49
+ # @return [Boolean]
50
+ def renewal_needed?; end
51
+
52
+ # Handle logout
36
53
  def logout; end
37
54
 
38
55
  # Headers added to the rest-client call
@@ -50,11 +67,21 @@ module TrainPlugins
50
67
  { headers: auth_headers }
51
68
  end
52
69
 
53
- # List authentication handlers
54
- #
55
- # @return [Array] Classes derived from `AuthHandler`
56
- def self.descendants
57
- ObjectSpace.each_object(Class).select { |klass| klass < self }
70
+ class << self
71
+ private
72
+
73
+ # Convert a class name to snake case.
74
+ #
75
+ # @param [String] Class name
76
+ # @return [String]
77
+ # @see https://github.com/chef/chef/blob/main/lib/chef/mixin/convert_to_class_name.rb
78
+ def convert_to_snake_case(str)
79
+ str = str.dup
80
+ str.gsub!(/[A-Z]/) { |s| "_" + s }
81
+ str.downcase!
82
+ str.sub!(/^\_/, "")
83
+ str
84
+ end
58
85
  end
59
86
  end
60
87
  end
@@ -86,6 +86,9 @@ module TrainPlugins
86
86
 
87
87
  # User-faced API
88
88
 
89
+ # Allow (programmatically) setting additional headers apart from global transport configuration
90
+ attr_accessor :override_headers
91
+
89
92
  %i{get post put patch delete head}.each do |method|
90
93
  define_method(method) do |path, **keywords|
91
94
  request(path, method, **keywords)
@@ -93,6 +96,8 @@ module TrainPlugins
93
96
  end
94
97
 
95
98
  def request(path, method = :get, request_parameters: {}, data: nil, headers: {}, json_processing: true)
99
+ auth_handler.renew_session if auth_handler.renewal_needed?
100
+
96
101
  parameters = global_parameters.merge(request_parameters)
97
102
 
98
103
  parameters[:method] = method
@@ -106,7 +111,9 @@ module TrainPlugins
106
111
  parameters[:payload] = data
107
112
  end
108
113
 
109
- parameters[:headers].merge! headers
114
+ # Merge override headers + request specific headers
115
+ parameters[:headers].merge!(override_headers || {})
116
+ parameters[:headers].merge!(headers)
110
117
  parameters.compact!
111
118
 
112
119
  logger.info format("[REST] => %s", parameters.to_s) if options[:debug_rest]
@@ -116,6 +123,27 @@ module TrainPlugins
116
123
  transform_response(response, json_processing)
117
124
  end
118
125
 
126
+ # Allow switching generic handlers for an API-specific one.
127
+ #
128
+ # New handler needs to be loaded prior and be derived from TrainPlugins::REST::AuthHandler.
129
+ def switch_auth_handler(new_handler)
130
+ return if active_auth_handler == new_handler
131
+
132
+ logout
133
+
134
+ options[:auth_type] = new_handler.to_sym
135
+ @auth_handler = nil
136
+
137
+ login
138
+ end
139
+
140
+ # Return active auth handler.
141
+ #
142
+ # @return [Symbol]
143
+ def active_auth_handler
144
+ options[:auth_type]
145
+ end
146
+
119
147
  # Auth Handlers-faced API
120
148
 
121
149
  def auth_parameters
@@ -1,5 +1,5 @@
1
1
  module TrainPlugins
2
2
  module Rest
3
- VERSION = "0.3.2".freeze
3
+ VERSION = "0.4.0".freeze
4
4
  end
5
5
  end
data/lib/train-rest.rb CHANGED
@@ -7,5 +7,8 @@ require "train-rest/transport"
7
7
  require "train-rest/connection"
8
8
 
9
9
  require "train-rest/auth_handler/anonymous"
10
+ require "train-rest/auth_handler/authtype-apikey"
11
+ require "train-rest/auth_handler/header"
10
12
  require "train-rest/auth_handler/basic"
13
+ require "train-rest/auth_handler/bearer"
11
14
  require "train-rest/auth_handler/redfish"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: train-rest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Heinen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-08 00:00:00.000000000 Z
11
+ date: 2021-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: train
@@ -120,7 +120,10 @@ files:
120
120
  - lib/train-rest.rb
121
121
  - lib/train-rest/auth_handler.rb
122
122
  - lib/train-rest/auth_handler/anonymous.rb
123
+ - lib/train-rest/auth_handler/authtype-apikey.rb
123
124
  - lib/train-rest/auth_handler/basic.rb
125
+ - lib/train-rest/auth_handler/bearer.rb
126
+ - lib/train-rest/auth_handler/header.rb
124
127
  - lib/train-rest/auth_handler/redfish.rb
125
128
  - lib/train-rest/connection.rb
126
129
  - lib/train-rest/transport.rb