docker-remote 0.6.0 → 0.7.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: 67104ac59d9b809cfaafaac9c1711b4d68b4d514c4c0360a28cb42cea105a72b
4
- data.tar.gz: 59d0560b904d4fbf9bd4e7484caf179cf0355f3b716eaaf104c87a3700be00f6
3
+ metadata.gz: 7aafe47e42bed5d3cd16a135a0a3a6f771aaceb9c35b796bf0706ec09137814d
4
+ data.tar.gz: 1c5aa9f0e89a229cbe203f5d535154fcb85fe270df340862200f3a14df5e0789
5
5
  SHA512:
6
- metadata.gz: ee73da94c49c3c70779ad258d9b0e0147c2768998762bcaa5829756ba4203163245fcb00031bdd7d9abeaee5d680bc5077788fa5826deb03e7e99f9a7eb01591
7
- data.tar.gz: 1cd3bac68947f1bf7af75ca903de81b932ae2258842ae22a71eee444c621ea63975b243cbc63a1bd273a848d756a3427409548375454580372f6f7c6d00b0626
6
+ metadata.gz: d2a2c898b5150f0a69e6c42a8c097f5956044201749167a3648a89725f0ae62e2e5e03e9432133f68637325406842c3d529fa3aaed76ac07e19c51d67b569920
7
+ data.tar.gz: 1306ccd01efe9184963586f0b34bbe0d9b10ea262b9570538b8d234d4024c0e862dfc001cffa1c144b67699e9a231155940ea18fc36ebccf59ae444ad8777ab1
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.7.0
2
+ * Support Azure Container Registry (ACR)
3
+ - ACR does two things differently than other registries like DockerHub, GitHub, etc:
4
+ 1. OAuth tokens are returned under the `access_token` key instead of `token`.
5
+ 1. The repo:<name>:pull scope is not enough to read metadata like the list of tags. You need the repo:<name>:metadata_read scope instead. Fortunately the www-authenticate header contains the scope you need to perform the operation.
6
+
1
7
  ## 0.6.0
2
8
  * Raise `UnknownRepoError` if the registry returns the `NAME_UNKNOWN` error code, which indicates the repo has never been pushed to before.
3
9
 
@@ -0,0 +1,40 @@
1
+ module Docker
2
+ module Remote
3
+ class AuthInfo
4
+ class << self
5
+ def from_header(header, creds)
6
+ idx = header.index(' ')
7
+ auth_type = header[0..idx].strip.downcase
8
+
9
+ params = header[idx..-1].split(',').each_with_object({}) do |param, ret|
10
+ key, value = param.split('=')
11
+ ret[key.strip] = value.strip[1..-2] # remove quotes
12
+ end
13
+
14
+ new(auth_type, params, creds)
15
+ end
16
+ end
17
+
18
+
19
+ attr_reader :auth_type, :params, :creds
20
+
21
+ def initialize(auth_type, params, creds)
22
+ @auth_type = auth_type
23
+ @params = params
24
+ @creds = creds
25
+ end
26
+
27
+ def strategy
28
+ @strategy ||= case auth_type
29
+ when 'bearer'
30
+ BearerAuth.new(self, creds)
31
+ when 'basic'
32
+ BasicAuth.new(creds)
33
+ else
34
+ raise UnsupportedAuthTypeError,
35
+ "unsupported Docker auth type '#{auth_type}'"
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -3,16 +3,15 @@ require 'net/http'
3
3
  module Docker
4
4
  module Remote
5
5
  class BasicAuth
6
- attr_reader :username, :password
6
+ attr_reader :creds
7
7
 
8
- def initialize(username, password)
9
- @username = username
10
- @password = password
8
+ def initialize(creds)
9
+ @creds = creds
11
10
  end
12
11
 
13
12
  def make_get(path)
14
13
  Net::HTTP::Get.new(path).tap do |request|
15
- request.basic_auth(username, password)
14
+ request.basic_auth(creds.username, creds.password)
16
15
  end
17
16
  end
18
17
  end
@@ -7,13 +7,11 @@ module Docker
7
7
  class BearerAuth
8
8
  include Utils
9
9
 
10
- attr_reader :params, :repo, :username, :password
10
+ attr_reader :auth_info, :creds
11
11
 
12
- def initialize(params, repo, username, password)
13
- @params = params
14
- @repo = repo
15
- @username = username
16
- @password = password
12
+ def initialize(auth_info, creds)
13
+ @auth_info = auth_info
14
+ @creds = creds
17
15
  end
18
16
 
19
17
  def make_get(path)
@@ -25,11 +23,11 @@ module Docker
25
23
  private
26
24
 
27
25
  def realm
28
- @realm ||= URI.parse(params['realm'])
26
+ @realm ||= URI.parse(auth_info.params['realm'])
29
27
  end
30
28
 
31
29
  def service
32
- @serivce ||= params['service']
30
+ @serivce ||= auth_info.params['service']
33
31
  end
34
32
 
35
33
  def token
@@ -37,17 +35,24 @@ module Docker
37
35
  http = Net::HTTP.new(realm.host, realm.port)
38
36
  http.use_ssl = true if realm.scheme == 'https'
39
37
 
38
+ url_params = { service: service }
39
+
40
+ if scope = auth_info.params['scope']
41
+ url_params[:scope] = scope
42
+ end
43
+
40
44
  request = Net::HTTP::Get.new(
41
- "#{realm.request_uri}?service=#{service}&scope=repository:#{repo}:pull"
45
+ "#{realm.request_uri}?#{URI.encode_www_form(url_params)}"
42
46
  )
43
47
 
44
- if username && password
45
- request.basic_auth(username, password)
48
+ if creds.username && creds.password
49
+ request.basic_auth(creds.username, creds.password)
46
50
  end
47
51
 
48
52
  response = http.request(request)
49
53
  potentially_raise_error!(response)
50
- JSON.parse(response.body)['token']
54
+ body_json = JSON.parse(response.body)
55
+ body_json['token'] || body_json['access_token']
51
56
  end
52
57
  end
53
58
  end
@@ -12,7 +12,7 @@ module Docker
12
12
  class Client
13
13
  include Utils
14
14
 
15
- attr_reader :registry_url, :repo, :username, :password
15
+ attr_reader :registry_url, :repo, :creds
16
16
 
17
17
  PORTMAP = { 'ghcr.io' => 443 }.freeze
18
18
  DEFAULT_PORT = 443
@@ -21,8 +21,7 @@ module Docker
21
21
  def initialize(registry_url, repo, username = nil, password = nil)
22
22
  @registry_url = registry_url
23
23
  @repo = repo
24
- @username = username
25
- @password = password
24
+ @creds = Credentials.new(username, password)
26
25
  end
27
26
 
28
27
  def tags
@@ -47,14 +46,14 @@ module Docker
47
46
 
48
47
  def auth
49
48
  @auth ||= begin
50
- response = get('/v2/', use_auth: nil)
49
+ response = get('/v2/', use_auth: NoAuth.instance)
51
50
 
52
- case response.code
53
- when '200'
51
+ case response
52
+ when Net::HTTPSuccess
54
53
  NoAuth.instance
55
- when '401'
56
- www_auth(response)
57
- when '404'
54
+ when Net::HTTPUnauthorized
55
+ www_auth(response).strategy
56
+ when Net::HTTPNotFound
58
57
  raise UnsupportedVersionError,
59
58
  "the registry at #{registry_url} doesn't support v2 "\
60
59
  'of the Docker registry API'
@@ -67,25 +66,7 @@ module Docker
67
66
  end
68
67
 
69
68
  def www_auth(response)
70
- auth = response['www-authenticate']
71
-
72
- idx = auth.index(' ')
73
- auth_type = auth[0..idx].strip
74
-
75
- params = auth[idx..-1].split(',').each_with_object({}) do |param, ret|
76
- key, value = param.split('=')
77
- ret[key.strip] = value.strip[1..-2] # remove quotes
78
- end
79
-
80
- case auth_type.downcase
81
- when 'bearer'
82
- BearerAuth.new(params, repo, username, password)
83
- when 'basic'
84
- BasicAuth.new(username, password)
85
- else
86
- raise UnsupportedAuthTypeError,
87
- "unsupported Docker auth type '#{auth_type}'"
88
- end
69
+ AuthInfo.from_header(response['www-authenticate'], creds)
89
70
  end
90
71
 
91
72
  def get(path, http: registry_http, use_auth: auth, limit: 5)
@@ -93,24 +74,31 @@ module Docker
93
74
  raise DockerRemoteError, 'too many redirects'
94
75
  end
95
76
 
96
- request = if use_auth
97
- use_auth.make_get(path)
98
- else
99
- Net::HTTP::Get.new(path)
100
- end
101
-
77
+ request = use_auth.make_get(path)
102
78
  response = http.request(request)
103
79
 
104
80
  case response
81
+ when Net::HTTPUnauthorized
82
+ auth_info = www_auth(response)
83
+
84
+ if auth_info.params['error'] == 'insufficient_scope'
85
+ if auth_info.params.include?('scope')
86
+ return get(
87
+ path,
88
+ http: http,
89
+ use_auth: auth_info.strategy,
90
+ limit: limit - 1
91
+ )
92
+ end
93
+ end
105
94
  when Net::HTTPRedirection
106
95
  redirect_uri = URI.parse(response['location'])
107
96
  redirect_http = make_http(redirect_uri)
108
97
  return get(
109
- redirect_uri.path, {
110
- http: redirect_http,
111
- use_auth: use_auth,
112
- limit: limit - 1
113
- }
98
+ redirect_uri.path,
99
+ http: redirect_http,
100
+ use_auth: use_auth,
101
+ limit: limit - 1
114
102
  )
115
103
  end
116
104
 
@@ -0,0 +1,12 @@
1
+ module Docker
2
+ module Remote
3
+ class Credentials
4
+ attr_reader :username, :password
5
+
6
+ def initialize(username, password)
7
+ @username = username
8
+ @password = password
9
+ end
10
+ end
11
+ end
12
+ end
@@ -1,5 +1,5 @@
1
1
  module Docker
2
2
  module Remote
3
- VERSION = '0.6.0'
3
+ VERSION = '0.7.0'
4
4
  end
5
5
  end
data/lib/docker/remote.rb CHANGED
@@ -8,10 +8,12 @@ module Docker
8
8
 
9
9
  class UnsupportedAuthTypeError < StandardError; end
10
10
 
11
- autoload :BasicAuth, 'docker/remote/basic_auth'
12
- autoload :BearerAuth, 'docker/remote/bearer_auth'
13
- autoload :Client, 'docker/remote/client'
14
- autoload :NoAuth, 'docker/remote/no_auth'
15
- autoload :Utils, 'docker/remote/utils'
11
+ autoload :AuthInfo, 'docker/remote/auth_info'
12
+ autoload :BasicAuth, 'docker/remote/basic_auth'
13
+ autoload :BearerAuth, 'docker/remote/bearer_auth'
14
+ autoload :Client, 'docker/remote/client'
15
+ autoload :Credentials, 'docker/remote/credentials'
16
+ autoload :NoAuth, 'docker/remote/no_auth'
17
+ autoload :Utils, 'docker/remote/utils'
16
18
  end
17
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docker-remote
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cameron Dutro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-06 00:00:00.000000000 Z
11
+ date: 2022-02-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A Ruby client for communicating with the Docker registry API v2.
14
14
  email:
@@ -23,9 +23,11 @@ files:
23
23
  - Rakefile
24
24
  - docker-remote.gemspec
25
25
  - lib/docker/remote.rb
26
+ - lib/docker/remote/auth_info.rb
26
27
  - lib/docker/remote/basic_auth.rb
27
28
  - lib/docker/remote/bearer_auth.rb
28
29
  - lib/docker/remote/client.rb
30
+ - lib/docker/remote/credentials.rb
29
31
  - lib/docker/remote/no_auth.rb
30
32
  - lib/docker/remote/utils.rb
31
33
  - lib/docker/remote/version.rb
@@ -47,7 +49,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
47
49
  - !ruby/object:Gem::Version
48
50
  version: '0'
49
51
  requirements: []
50
- rubygems_version: 3.1.4
52
+ rubygems_version: 3.2.22
51
53
  signing_key:
52
54
  specification_version: 4
53
55
  summary: A Ruby client for communicating with the Docker registry API v2.