smart_proxy_container_gateway 1.0.0 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/smart_proxy_container_gateway/container_gateway.rb +15 -4
- data/lib/smart_proxy_container_gateway/container_gateway_api.rb +89 -32
- data/lib/smart_proxy_container_gateway/container_gateway_main.rb +102 -25
- data/lib/smart_proxy_container_gateway/foreman_api.rb +13 -5
- data/lib/smart_proxy_container_gateway/sequel_migrations/003_authorization_reorg.rb +65 -0
- data/lib/smart_proxy_container_gateway/version.rb +1 -1
- data/settings.d/container_gateway.yml.example +2 -0
- metadata +17 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f7f64eda929055e1dbf8e33f6f25797f5f01eaec99fc44c68b48cdbb54e3ac24
|
4
|
+
data.tar.gz: 3b82489df2523cc112474f8f88925959123db0ea34848462dcaa3a15aa2f01f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7275b37d4d4e2de7be47377f45790277df201752f429a3d1bea719a7f644b9a59e7b39a312f75d4b6c75d66c2ada8a21970cab2b6ee665ee11c45dfd739d2905
|
7
|
+
data.tar.gz: 0f12062658a3840ddccb627e1e2ef2602e3e53b03b218684ff2f6a733504107a49329237d56f6a0b5ed6669509b422622459f84dc2c66484ddb99f5ec10bfa71
|
@@ -9,10 +9,21 @@ module Proxy
|
|
9
9
|
:katello_registry_path => '/v2/',
|
10
10
|
:sqlite_db_path => '/var/lib/foreman-proxy/smart_proxy_container_gateway.db'
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
# Load defaults that copy values from SETTINGS. This is done as
|
13
|
+
# programmable settings since SETTINGS isn't initialized during plugin
|
14
|
+
# loading.
|
15
|
+
load_programmable_settings do |settings|
|
16
|
+
settings[:pulp_client_ssl_ca] ||= SETTINGS.foreman_ssl_ca
|
17
|
+
settings[:pulp_client_ssl_cert] ||= SETTINGS.foreman_ssl_cert
|
18
|
+
settings[:pulp_client_ssl_key] ||= SETTINGS.foreman_ssl_key
|
19
|
+
end
|
20
|
+
|
21
|
+
# TODO: sqlite_db_path should able be readable or creatable. There's no
|
22
|
+
# test for creatable
|
23
|
+
validate_readable :pulp_client_ssl_ca, :pulp_client_ssl_cert, :pulp_client_ssl_key
|
24
|
+
validate :pulp_endpoint, url: true
|
25
|
+
|
26
|
+
rackup_path File.join(__dir__, 'container_gateway_http_config.ru')
|
16
27
|
end
|
17
28
|
end
|
18
29
|
end
|
@@ -2,7 +2,6 @@ require 'sinatra'
|
|
2
2
|
require 'smart_proxy_container_gateway/container_gateway'
|
3
3
|
require 'smart_proxy_container_gateway/container_gateway_main'
|
4
4
|
require 'smart_proxy_container_gateway/foreman_api'
|
5
|
-
require 'sequel'
|
6
5
|
require 'sqlite3'
|
7
6
|
|
8
7
|
module Proxy
|
@@ -10,7 +9,7 @@ module Proxy
|
|
10
9
|
class Api < ::Sinatra::Base
|
11
10
|
include ::Proxy::Log
|
12
11
|
helpers ::Proxy::Helpers
|
13
|
-
|
12
|
+
helpers ::Sinatra::Authorization::Helpers
|
14
13
|
|
15
14
|
get '/v1/_ping/?' do
|
16
15
|
Proxy::ContainerGateway.ping
|
@@ -18,6 +17,7 @@ module Proxy
|
|
18
17
|
|
19
18
|
get '/v2/?' do
|
20
19
|
if auth_header.present? && (auth_header.unauthorized_token? || auth_header.valid_user_token?)
|
20
|
+
response.headers['Docker-Distribution-API-Version'] = 'registry/2.0'
|
21
21
|
Proxy::ContainerGateway.ping
|
22
22
|
else
|
23
23
|
redirect_authorization_headers
|
@@ -26,31 +26,32 @@ module Proxy
|
|
26
26
|
end
|
27
27
|
|
28
28
|
get '/v2/:repository/manifests/:tag/?' do
|
29
|
-
|
30
|
-
redirect_authorization_headers
|
31
|
-
halt 401, "unauthorized"
|
32
|
-
end
|
29
|
+
handle_repo_auth(params, auth_header, request)
|
33
30
|
redirection_location = Proxy::ContainerGateway.manifests(params[:repository], params[:tag])
|
34
31
|
redirect to(redirection_location)
|
35
32
|
end
|
36
33
|
|
37
34
|
get '/v2/:repository/blobs/:digest/?' do
|
38
|
-
|
39
|
-
redirect_authorization_headers
|
40
|
-
halt 401, "unauthorized"
|
41
|
-
end
|
35
|
+
handle_repo_auth(params, auth_header, request)
|
42
36
|
redirection_location = Proxy::ContainerGateway.blobs(params[:repository], params[:digest])
|
43
37
|
redirect to(redirection_location)
|
44
38
|
end
|
45
39
|
|
46
40
|
get '/v1/search/?' do
|
47
41
|
# Checks for podman client and issues a 404 in that case. Podman
|
48
|
-
# examines the response from a /
|
42
|
+
# examines the response from a /v1/search request. If the result
|
49
43
|
# is a 4XX, it will then proceed with a request to /_catalog
|
50
44
|
if !request.env['HTTP_USER_AGENT'].nil? && request.env['HTTP_USER_AGENT'].downcase.include?('libpod')
|
51
45
|
halt 404, "not found"
|
52
46
|
end
|
53
47
|
|
48
|
+
if auth_header.present? && !auth_header.blank?
|
49
|
+
username = auth_header.v1_foreman_authorized_username
|
50
|
+
if username.nil?
|
51
|
+
halt 401, "unauthorized"
|
52
|
+
end
|
53
|
+
params[:user] = username
|
54
|
+
end
|
54
55
|
repositories = Proxy::ContainerGateway.v1_search(params)
|
55
56
|
|
56
57
|
content_type :json
|
@@ -58,13 +59,23 @@ module Proxy
|
|
58
59
|
end
|
59
60
|
|
60
61
|
get '/v2/_catalog/?' do
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
catalog = []
|
63
|
+
if auth_header.present?
|
64
|
+
if auth_header.unauthorized_token?
|
65
|
+
catalog = Proxy::ContainerGateway.catalog
|
66
|
+
elsif auth_header.valid_user_token?
|
67
|
+
catalog = Proxy::ContainerGateway.catalog(auth_header.user)
|
68
|
+
else
|
69
|
+
redirect_authorization_headers
|
70
|
+
halt 401, "unauthorized"
|
71
|
+
end
|
72
|
+
else
|
73
|
+
redirect_authorization_headers
|
74
|
+
halt 401, "unauthorized"
|
75
|
+
end
|
64
76
|
|
65
|
-
get '/v2/unauthenticated_repository_list/?' do
|
66
77
|
content_type :json
|
67
|
-
{ repositories:
|
78
|
+
{ repositories: catalog }.to_json
|
68
79
|
end
|
69
80
|
|
70
81
|
get '/v2/token' do
|
@@ -72,8 +83,8 @@ module Proxy
|
|
72
83
|
|
73
84
|
unless auth_header.present? && auth_header.basic_auth?
|
74
85
|
one_year = (60 * 60 * 24 * 365)
|
75
|
-
return { token: AuthorizationHeader::UNAUTHORIZED_TOKEN, issued_at: Time.now,
|
76
|
-
expires_at: Time.now + one_year }.to_json
|
86
|
+
return { token: AuthorizationHeader::UNAUTHORIZED_TOKEN, issued_at: Time.now.iso8601,
|
87
|
+
expires_at: (Time.now + one_year).iso8601 }.to_json
|
77
88
|
end
|
78
89
|
|
79
90
|
token_response = ForemanApi.new.fetch_token(auth_header.raw_header, request.params)
|
@@ -83,28 +94,57 @@ expires_at: Time.now + one_year }.to_json
|
|
83
94
|
token_response_body = JSON.parse(token_response.body)
|
84
95
|
ContainerGateway.insert_token(request.params['account'], token_response_body['token'],
|
85
96
|
token_response_body['expires_at'])
|
97
|
+
|
98
|
+
repo_response = ForemanApi.new.fetch_user_repositories(auth_header.raw_header, request.params)
|
99
|
+
if repo_response.code.to_i != 200
|
100
|
+
halt repo_response.code.to_i, repo_response.body
|
101
|
+
else
|
102
|
+
ContainerGateway.update_user_repositories(request.params['account'],
|
103
|
+
JSON.parse(repo_response.body)['repositories'])
|
104
|
+
end
|
86
105
|
return token_response_body.to_json
|
87
106
|
end
|
88
107
|
end
|
89
108
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
109
|
+
get '/users/?' do
|
110
|
+
do_authorize_any
|
111
|
+
|
112
|
+
content_type :json
|
113
|
+
{ users: User.map(:name) }.to_json
|
114
|
+
end
|
115
|
+
|
116
|
+
put '/user_repository_mapping/?' do
|
117
|
+
do_authorize_any
|
118
|
+
|
119
|
+
ContainerGateway.update_user_repo_mapping(params)
|
120
|
+
{}
|
121
|
+
end
|
122
|
+
|
123
|
+
put '/repository_list/?' do
|
124
|
+
do_authorize_any
|
125
|
+
|
126
|
+
repositories = params['repositories'].nil? ? [] : params['repositories']
|
127
|
+
ContainerGateway.update_repository_list(repositories)
|
128
|
+
{}
|
104
129
|
end
|
105
130
|
|
106
131
|
private
|
107
132
|
|
133
|
+
def handle_repo_auth(params, auth_header, request)
|
134
|
+
user_token_is_valid = false
|
135
|
+
# FIXME: Getting unauthenticated token here...
|
136
|
+
if auth_header.present? && auth_header.valid_user_token?
|
137
|
+
user_token_is_valid = true
|
138
|
+
username = auth_header.user.name
|
139
|
+
end
|
140
|
+
username = request.params['account'] if username.nil?
|
141
|
+
|
142
|
+
return if Proxy::ContainerGateway.authorized_for_repo?(params[:repository], user_token_is_valid, username)
|
143
|
+
|
144
|
+
redirect_authorization_headers
|
145
|
+
halt 401, "unauthorized"
|
146
|
+
end
|
147
|
+
|
108
148
|
def redirect_authorization_headers
|
109
149
|
response.headers['Docker-Distribution-API-Version'] = 'registry/2.0'
|
110
150
|
response.headers['Www-Authenticate'] = "Bearer realm=\"https://#{request.host}/v2/token\"," \
|
@@ -123,6 +163,10 @@ expires_at: Time.now + one_year }.to_json
|
|
123
163
|
@value = value || ''
|
124
164
|
end
|
125
165
|
|
166
|
+
def user
|
167
|
+
ContainerGateway.token_user(@value.split(' ')[1])
|
168
|
+
end
|
169
|
+
|
126
170
|
def valid_user_token?
|
127
171
|
token_auth? && ContainerGateway.valid_token?(@value.split(' ')[1])
|
128
172
|
end
|
@@ -146,6 +190,19 @@ expires_at: Time.now + one_year }.to_json
|
|
146
190
|
def basic_auth?
|
147
191
|
@value.split(' ')[0] == 'Basic'
|
148
192
|
end
|
193
|
+
|
194
|
+
def blank?
|
195
|
+
Base64.decode64(@value.split(' ')[1]) == ':'
|
196
|
+
end
|
197
|
+
|
198
|
+
# A special case for the V1 API. Defer authentication to Foreman and return the username. `nil` if not authorized.
|
199
|
+
def v1_foreman_authorized_username
|
200
|
+
username = Base64.decode64(@value.split(' ')[1]).split(':')[0]
|
201
|
+
auth_response = ForemanApi.new.fetch_token(raw_header, { 'account' => username })
|
202
|
+
return username if auth_response.code.to_i == 200 && (JSON.parse(auth_response.body)['token'] != 'unauthenticated')
|
203
|
+
|
204
|
+
nil
|
205
|
+
end
|
149
206
|
end
|
150
207
|
end
|
151
208
|
end
|
@@ -1,15 +1,17 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
require 'uri'
|
3
3
|
require 'digest'
|
4
|
-
|
4
|
+
require 'sequel'
|
5
5
|
module Proxy
|
6
6
|
module ContainerGateway
|
7
7
|
extend ::Proxy::Util
|
8
8
|
extend ::Proxy::Log
|
9
9
|
|
10
10
|
class << self
|
11
|
+
Sequel.extension :migration, :core_extensions
|
11
12
|
def pulp_registry_request(uri)
|
12
13
|
http_client = Net::HTTP.new(uri.host, uri.port)
|
14
|
+
http_client.ca_file = pulp_ca
|
13
15
|
http_client.cert = pulp_cert
|
14
16
|
http_client.key = pulp_key
|
15
17
|
http_client.use_ssl = true
|
@@ -48,7 +50,8 @@ module Proxy
|
|
48
50
|
|
49
51
|
repo_count = 0
|
50
52
|
repositories = []
|
51
|
-
|
53
|
+
user = params[:user].nil? ? nil : User.find(name: params[:user])
|
54
|
+
Proxy::ContainerGateway.catalog(user).each do |repo_name|
|
52
55
|
break if repo_count >= params[:n]
|
53
56
|
|
54
57
|
if params[:q].nil? || params[:q] == "" || repo_name.include?(params[:q])
|
@@ -59,48 +62,103 @@ module Proxy
|
|
59
62
|
repositories
|
60
63
|
end
|
61
64
|
|
62
|
-
def catalog
|
63
|
-
|
65
|
+
def catalog(user = nil)
|
66
|
+
if user.nil?
|
67
|
+
unauthenticated_repos
|
68
|
+
else
|
69
|
+
(unauthenticated_repos + user.repositories_dataset.map(:name)).sort
|
70
|
+
end
|
64
71
|
end
|
65
72
|
|
66
73
|
def unauthenticated_repos
|
67
|
-
|
68
|
-
conn[:unauthenticated_repositories].order(:name).map(:name)
|
74
|
+
Repository.where(auth_required: false).order(:name).map(:name)
|
69
75
|
end
|
70
76
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
+
# Replaces the entire list of repositories
|
78
|
+
def update_repository_list(repo_list)
|
79
|
+
RepositoryUser.dataset.delete
|
80
|
+
Repository.dataset.delete
|
81
|
+
repo_list.each do |repo|
|
82
|
+
Repository.find_or_create(name: repo['repository'],
|
83
|
+
auth_required: repo['auth_required'].to_s.downcase == "true")
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Replaces the entire user-repo mapping for all logged-in users
|
88
|
+
def update_user_repo_mapping(user_repo_maps)
|
89
|
+
# Get hash map of all users and their repositories
|
90
|
+
# Ex: {"users"=> [{"admin"=>[{"repository"=>"repo", "auth_required"=>"true"}]}]}
|
91
|
+
# Go through list of repositories and add them to the DB
|
92
|
+
RepositoryUser.dataset.delete
|
93
|
+
user_repo_maps['users'].each do |user_repo_map|
|
94
|
+
user_repo_map.each do |user, repos|
|
95
|
+
repos.each do |repo|
|
96
|
+
found_repo = Repository.find(name: repo['repository'],
|
97
|
+
auth_required: repo['auth_required'].to_s.downcase == "true")
|
98
|
+
if found_repo.nil?
|
99
|
+
logger.warn("#{repo['repository']} does not exist in this smart proxy's environments")
|
100
|
+
elsif found_repo.auth_required
|
101
|
+
found_repo.add_user(User.find(name: user))
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
77
105
|
end
|
78
106
|
end
|
79
107
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
108
|
+
# Replaces the user-repo mapping for a single user
|
109
|
+
def update_user_repositories(username, repositories)
|
110
|
+
user = User.where(name: username).first
|
111
|
+
user.remove_all_repositories
|
112
|
+
repositories.each do |repo_name|
|
113
|
+
found_repo = Repository.find(name: repo_name)
|
114
|
+
if found_repo.nil?
|
115
|
+
logger.warn("#{repo_name} does not exist in this smart proxy's environments")
|
116
|
+
elsif user.repositories_dataset.where(name: repo_name).first.nil? && found_repo.auth_required
|
117
|
+
user.add_repository(found_repo)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def authorized_for_repo?(repo_name, user_token_is_valid, username = nil)
|
123
|
+
repository = Repository.where(name: repo_name).first
|
124
|
+
|
125
|
+
# Repository doesn't exist
|
126
|
+
return false if repository.nil?
|
127
|
+
|
128
|
+
# Repository doesn't require auth
|
129
|
+
return true unless repository.auth_required
|
130
|
+
|
131
|
+
if username && user_token_is_valid && repository.auth_required
|
132
|
+
# User is logged in and has access to the repository
|
133
|
+
user = User.find(name: username)
|
134
|
+
return !user.repositories_dataset.where(name: repo_name).first.nil?
|
135
|
+
end
|
136
|
+
|
137
|
+
false
|
138
|
+
end
|
139
|
+
|
140
|
+
def token_user(token)
|
141
|
+
User[AuthenticationToken.find(token_checksum: Digest::SHA256.hexdigest(token)).user_id]
|
84
142
|
end
|
85
143
|
|
86
144
|
def valid_token?(token)
|
87
|
-
|
88
|
-
tokens.where(token_checksum: Digest::SHA256.hexdigest(token)).where do
|
145
|
+
AuthenticationToken.where(token_checksum: Digest::SHA256.hexdigest(token)).where do
|
89
146
|
expire_at > Sequel::CURRENT_TIMESTAMP
|
90
147
|
end.count.positive?
|
91
148
|
end
|
92
149
|
|
93
150
|
def insert_token(username, token, expire_at_string, clear_expired_tokens: true)
|
94
|
-
tokens = initialize_db[:authentication_tokens]
|
95
151
|
checksum = Digest::SHA256.hexdigest(token)
|
152
|
+
user = User.find_or_create(name: username)
|
96
153
|
|
97
|
-
|
98
|
-
|
99
|
-
|
154
|
+
AuthenticationToken.where(:token_checksum => checksum).delete
|
155
|
+
AuthenticationToken.create(token_checksum: checksum, expire_at: expire_at_string.to_s, user_id: user.id)
|
156
|
+
AuthenticationToken.where { expire_at < Sequel::CURRENT_TIMESTAMP }.delete if clear_expired_tokens
|
100
157
|
end
|
101
158
|
|
102
159
|
def initialize_db
|
103
|
-
|
160
|
+
file_path = Proxy::ContainerGateway::Plugin.settings.sqlite_db_path
|
161
|
+
conn = Sequel.connect("sqlite://#{file_path}")
|
104
162
|
container_gateway_path = $LOAD_PATH.detect { |path| path.include? 'smart_proxy_container_gateway' }
|
105
163
|
begin
|
106
164
|
Sequel::Migrator.check_current(conn, "#{container_gateway_path}/smart_proxy_container_gateway/sequel_migrations")
|
@@ -116,15 +174,34 @@ module Proxy
|
|
116
174
|
Sequel::Migrator.run(db_connection, "#{container_gateway_path}/smart_proxy_container_gateway/sequel_migrations")
|
117
175
|
end
|
118
176
|
|
177
|
+
def pulp_ca
|
178
|
+
Proxy::ContainerGateway::Plugin.settings.pulp_client_ssl_ca
|
179
|
+
end
|
180
|
+
|
119
181
|
def pulp_cert
|
120
|
-
OpenSSL::X509::Certificate.new(File.
|
182
|
+
OpenSSL::X509::Certificate.new(File.read(Proxy::ContainerGateway::Plugin.settings.pulp_client_ssl_cert))
|
121
183
|
end
|
122
184
|
|
123
185
|
def pulp_key
|
124
186
|
OpenSSL::PKey::RSA.new(
|
125
|
-
File.
|
187
|
+
File.read(Proxy::ContainerGateway::Plugin.settings.pulp_client_ssl_key)
|
126
188
|
)
|
127
189
|
end
|
128
190
|
end
|
191
|
+
|
192
|
+
class Repository < ::Sequel::Model(Proxy::ContainerGateway.initialize_db[:repositories])
|
193
|
+
many_to_many :users
|
194
|
+
end
|
195
|
+
|
196
|
+
class User < ::Sequel::Model(Proxy::ContainerGateway.initialize_db[:users])
|
197
|
+
many_to_many :repositories
|
198
|
+
one_to_many :authentication_tokens
|
199
|
+
end
|
200
|
+
|
201
|
+
class RepositoryUser < ::Sequel::Model(Proxy::ContainerGateway.initialize_db[:repositories_users]); end
|
202
|
+
|
203
|
+
class AuthenticationToken < ::Sequel::Model(Proxy::ContainerGateway.initialize_db[:authentication_tokens])
|
204
|
+
many_to_one :users
|
205
|
+
end
|
129
206
|
end
|
130
207
|
end
|
@@ -3,15 +3,15 @@ require 'uri'
|
|
3
3
|
module Proxy
|
4
4
|
module ContainerGateway
|
5
5
|
class ForemanApi
|
6
|
-
def
|
7
|
-
|
8
|
-
|
6
|
+
def registry_request(auth_header, params, suffix)
|
7
|
+
uri = URI.join(Proxy::SETTINGS.foreman_url, Proxy::ContainerGateway::Plugin.settings.katello_registry_path, suffix)
|
8
|
+
uri.query = process_params(params)
|
9
9
|
|
10
|
-
req = Net::HTTP::Get.new(
|
10
|
+
req = Net::HTTP::Get.new(uri)
|
11
11
|
req.add_field('Authorization', auth_header)
|
12
12
|
req.add_field('Accept', 'application/json')
|
13
13
|
req.content_type = 'application/json'
|
14
|
-
http = Net::HTTP.new(
|
14
|
+
http = Net::HTTP.new(uri.hostname, uri.port)
|
15
15
|
http.use_ssl = true
|
16
16
|
|
17
17
|
http.request(req)
|
@@ -21,6 +21,14 @@ module Proxy
|
|
21
21
|
params = params_in.slice('scope', 'account').compact
|
22
22
|
URI.encode_www_form(params)
|
23
23
|
end
|
24
|
+
|
25
|
+
def fetch_token(auth_header, params)
|
26
|
+
registry_request(auth_header, params, 'token')
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch_user_repositories(auth_header, params)
|
30
|
+
registry_request(auth_header, params, '_catalog')
|
31
|
+
end
|
24
32
|
end
|
25
33
|
end
|
26
34
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
Sequel.migration do
|
2
|
+
up do
|
3
|
+
# TODO: Should I be migrating the existing data?
|
4
|
+
|
5
|
+
create_table(:repositories) do
|
6
|
+
primary_key :id
|
7
|
+
String :name, null: false
|
8
|
+
Boolean :auth_required, null: false
|
9
|
+
end
|
10
|
+
|
11
|
+
create_table(:users) do
|
12
|
+
primary_key :id
|
13
|
+
String :name, null: false
|
14
|
+
end
|
15
|
+
|
16
|
+
# Migrate unauthenticated_repositories to the new repositories table (TODO: can I select `false` like that?)
|
17
|
+
from(:repositories).insert(%i[name auth_required],
|
18
|
+
from(:unauthenticated_repositories).select(:name, false))
|
19
|
+
|
20
|
+
# Migrate names from authentication_tokens to the new users table
|
21
|
+
from(:users).insert([:name], from(:authentication_tokens).select(:username))
|
22
|
+
|
23
|
+
alter_table(:authentication_tokens) do
|
24
|
+
add_foreign_key :user_id, :users
|
25
|
+
end
|
26
|
+
|
27
|
+
# Populate the new user_id foreign key for all authentication_tokens
|
28
|
+
from(:authentication_tokens).insert([:user_id],
|
29
|
+
from(:users).select(:id).where(name: self[:authentication_tokens][:username]))
|
30
|
+
|
31
|
+
alter_table(:authentication_tokens) do
|
32
|
+
drop_column :username
|
33
|
+
end
|
34
|
+
|
35
|
+
create_join_table(repository_id: :repositories, user_id: :users)
|
36
|
+
drop_table :unauthenticated_repositories
|
37
|
+
end
|
38
|
+
|
39
|
+
down do
|
40
|
+
alter_table(:authentication_tokens) do
|
41
|
+
add_column :username, String
|
42
|
+
end
|
43
|
+
|
44
|
+
# Repopulate the name column with usernames
|
45
|
+
from(:authentication_tokens).update(username:
|
46
|
+
from(:users).select(:name).where(id: self[:authentication_tokens][:user_id]))
|
47
|
+
|
48
|
+
alter_table(:authentication_tokens) do
|
49
|
+
drop_foreign_key :user_id
|
50
|
+
end
|
51
|
+
|
52
|
+
create_table(:unauthenticated_repositories) do
|
53
|
+
primary_key :id
|
54
|
+
String :name, null: false
|
55
|
+
end
|
56
|
+
|
57
|
+
# Repopulate the unauthenticated_repositories table
|
58
|
+
from(:unauthenticated_repositories).insert([:username],
|
59
|
+
from(:repositories).select(:name).where(auth_required: true))
|
60
|
+
|
61
|
+
drop_table :users
|
62
|
+
drop_table :repositories
|
63
|
+
drop_join_table(repository_id: :repositories, user_id: :users)
|
64
|
+
end
|
65
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
---
|
2
2
|
:enabled: true
|
3
3
|
:pulp_endpoint: 'https://your_pulp_3_server_here.com'
|
4
|
+
:pulp_client_ssl_ca: 'CA Cert for authenticating with Pulp'
|
4
5
|
:pulp_client_ssl_cert: 'X509 certificate for authenticating with Pulp'
|
5
6
|
:pulp_client_ssl_key: 'RSA private key for the Pulp certificate'
|
7
|
+
:katello_registry_path: 'Katello container registry suffix, e.g., /v2/'
|
6
8
|
:sqlite_db_path: '/var/lib/foreman-proxy/smart_proxy_container_gateway.db'
|
metadata
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_proxy_container_gateway
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ian Ballou
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sequel
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: sqlite3
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
description: Pulp 3 container registry support for Foreman/Katello Smart-Proxy
|
@@ -46,19 +46,20 @@ extra_rdoc_files:
|
|
46
46
|
- README.md
|
47
47
|
- LICENSE
|
48
48
|
files:
|
49
|
+
- LICENSE
|
50
|
+
- README.md
|
51
|
+
- bundler.d/container_gateway.rb
|
49
52
|
- lib/smart_proxy_container_gateway.rb
|
53
|
+
- lib/smart_proxy_container_gateway/container_gateway.rb
|
54
|
+
- lib/smart_proxy_container_gateway/container_gateway_api.rb
|
55
|
+
- lib/smart_proxy_container_gateway/container_gateway_http_config.ru
|
56
|
+
- lib/smart_proxy_container_gateway/container_gateway_main.rb
|
50
57
|
- lib/smart_proxy_container_gateway/foreman_api.rb
|
51
58
|
- lib/smart_proxy_container_gateway/sequel_migrations/001_initial.rb
|
52
59
|
- lib/smart_proxy_container_gateway/sequel_migrations/002_auth_tokens.rb
|
53
|
-
- lib/smart_proxy_container_gateway/
|
60
|
+
- lib/smart_proxy_container_gateway/sequel_migrations/003_authorization_reorg.rb
|
54
61
|
- lib/smart_proxy_container_gateway/version.rb
|
55
|
-
- lib/smart_proxy_container_gateway/container_gateway.rb
|
56
|
-
- lib/smart_proxy_container_gateway/container_gateway_api.rb
|
57
|
-
- lib/smart_proxy_container_gateway/container_gateway_main.rb
|
58
62
|
- settings.d/container_gateway.yml.example
|
59
|
-
- bundler.d/container_gateway.rb
|
60
|
-
- README.md
|
61
|
-
- LICENSE
|
62
63
|
homepage: http://github.com/ianballou/smart_proxy_container_gateway
|
63
64
|
licenses:
|
64
65
|
- GPLv3
|
@@ -69,17 +70,16 @@ require_paths:
|
|
69
70
|
- lib
|
70
71
|
required_ruby_version: !ruby/object:Gem::Requirement
|
71
72
|
requirements:
|
72
|
-
- - ~>
|
73
|
+
- - "~>"
|
73
74
|
- !ruby/object:Gem::Version
|
74
75
|
version: '2.5'
|
75
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
77
|
requirements:
|
77
|
-
- -
|
78
|
+
- - ">="
|
78
79
|
- !ruby/object:Gem::Version
|
79
80
|
version: '0'
|
80
81
|
requirements: []
|
81
|
-
|
82
|
-
rubygems_version: 2.0.14.1
|
82
|
+
rubygems_version: 3.0.3
|
83
83
|
signing_key:
|
84
84
|
specification_version: 4
|
85
85
|
summary: Pulp 3 container registry support for Foreman/Katello Smart-Proxy
|