arvados-login-sync 2.6.3 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/bin/arvados-login-sync +122 -91
  3. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 051af26b13fc808c8fc6da81ec2d42948c38c660e072c04b4a4945c462bc7e1f
4
- data.tar.gz: 8169f9968940af3d08186738592b88ea19fb67ed3b630c127c6ea91798878e56
3
+ metadata.gz: e91705a1939f5956d6e25e9faa476686231bf5288f61026e15fcfab13538d3b9
4
+ data.tar.gz: c493a0f547b305b9dec02a7630dad3577997c0b076a94f4ff89ab880823ec269
5
5
  SHA512:
6
- metadata.gz: 39951b7f294e5e4a926ac0286f23487804b47c8e1665eda866f0a04163d04e148eded1de600ad1c1af5528f221d1e7f601604fe2a173501b17ac2badf3919a74
7
- data.tar.gz: dc8fabfa2b5ba4134171eefc8c2c35cce94267911f2ce2015ded656eea9742a0a58fa3c735ae232834677f0c843559767dddb0a1d2d61e40852471edf5a94def
6
+ metadata.gz: 1082c1d9286f75180b2deda92c5f4d5ff949c91b99e5aa1f90d6b8e3d53e8b2e79da5fd1c355d28f6ae5257e6287175c6ca928b2654aec94c188be54c9cb4375
7
+ data.tar.gz: 36109d2c86044efb9c14d9b65e6f9c150d553beef169e3440595f0b3f7c5d01d2d3258dee3bcf809d37f37904bb67752232d5025f2b7047e1aa256873f7a532c
@@ -12,6 +12,18 @@ require 'yaml'
12
12
  require 'optparse'
13
13
  require 'open3'
14
14
 
15
+ def ensure_dir(path, mode, owner, group)
16
+ begin
17
+ Dir.mkdir(path, mode)
18
+ rescue Errno::EEXIST
19
+ # No change needed
20
+ false
21
+ else
22
+ FileUtils.chown(owner, group, path)
23
+ true
24
+ end
25
+ end
26
+
15
27
  req_envs = %w(ARVADOS_API_HOST ARVADOS_API_TOKEN ARVADOS_VIRTUAL_MACHINE_UUID)
16
28
  req_envs.each do |k|
17
29
  unless ENV[k]
@@ -34,6 +46,15 @@ exclusive_banner = "############################################################
34
46
  start_banner = "### BEGIN Arvados-managed keys -- changes between markers will be overwritten\n"
35
47
  end_banner = "### END Arvados-managed keys -- changes between markers will be overwritten\n"
36
48
 
49
+ actions = {
50
+ # These names correspond to the names in the cluster Users configuration.
51
+ # Managing everything was the original behavior.
52
+ SyncUserAccounts: true,
53
+ SyncUserGroups: true,
54
+ SyncUserSSHKeys: true,
55
+ SyncUserAPITokens: true,
56
+ }
57
+
37
58
  keys = ''
38
59
 
39
60
  begin
@@ -45,6 +66,17 @@ begin
45
66
  logincluster_host = ENV['ARVADOS_API_HOST']
46
67
  logincluster_name = arv.cluster_config['Login']['LoginCluster'] or ''
47
68
 
69
+ # Requiring the fuse group was previous hardcoded behavior
70
+ minimum_groups = arv.cluster_config['Users']['SyncRequiredGroups'] || ['fuse']
71
+ ignored_groups = arv.cluster_config['Users']['SyncIgnoredGroups'] || []
72
+ (minimum_groups & ignored_groups).each do |group_name|
73
+ STDERR.puts "WARNING: #{group_name} is listed in both SyncRequiredGroups and SyncIgnoredGroups. It will be ignored."
74
+ end
75
+
76
+ actions.each_pair do |key, default|
77
+ actions[key] = arv.cluster_config['Users'].fetch(key.to_s, default)
78
+ end
79
+
48
80
  if logincluster_name != '' and logincluster_name != arv.cluster_config['ClusterID']
49
81
  logincluster_host = arv.cluster_config['RemoteClusters'][logincluster_name]['Host']
50
82
  end
@@ -112,11 +144,12 @@ begin
112
144
 
113
145
  seen = Hash.new()
114
146
 
115
- current_user_groups = Hash.new
147
+ all_groups = []
148
+ current_user_groups = Hash.new { |hash, key| hash[key] = [] }
116
149
  while (ent = Etc.getgrent()) do
150
+ all_groups << ent.name
117
151
  ent.mem.each do |member|
118
- current_user_groups[member] ||= Array.new
119
- current_user_groups[member].push ent.name
152
+ current_user_groups[member] << ent.name
120
153
  end
121
154
  end
122
155
  Etc.endgrent()
@@ -128,6 +161,10 @@ begin
128
161
  username = l[:username]
129
162
 
130
163
  unless pwnam[l[:username]]
164
+ unless actions[:SyncUserAccounts]
165
+ STDERR.puts "User #{username} does not exist and SyncUserAccounts=false. Skipping."
166
+ next
167
+ end
131
168
  STDERR.puts "Creating account #{l[:username]}"
132
169
  # Create new user
133
170
  out, st = Open3.capture2e("useradd", "-m",
@@ -146,15 +183,21 @@ begin
146
183
  end
147
184
  end
148
185
 
149
- existing_groups = current_user_groups[username] || []
150
- groups = l[:groups] || []
151
- # Adding users to the FUSE group has long been hardcoded behavior.
152
- groups << "fuse"
153
- groups << username
154
- groups.select! { |g| Etc.getgrnam(g) rescue false }
186
+ user_gid = pwnam[username].gid
187
+ homedir = pwnam[l[:username]].dir
188
+ if !File.exist?(homedir)
189
+ STDERR.puts "Cannot set up user #{username} because their home directory #{homedir} does not exist. Skipping."
190
+ next
191
+ end
192
+
193
+ if actions[:SyncUserGroups]
194
+ have_groups = current_user_groups[username] - ignored_groups
195
+ want_groups = l[:groups] || []
196
+ want_groups |= minimum_groups
197
+ want_groups -= ignored_groups
198
+ want_groups &= all_groups
155
199
 
156
- groups.each do |addgroup|
157
- if existing_groups.index(addgroup).nil?
200
+ (want_groups - have_groups).each do |addgroup|
158
201
  # User should be in group, but isn't, so add them.
159
202
  STDERR.puts "Add user #{username} to #{addgroup} group"
160
203
  out, st = Open3.capture2e("usermod", "-aG", addgroup, username)
@@ -162,10 +205,8 @@ begin
162
205
  STDERR.puts "Failed to add #{username} to #{addgroup} group:\n#{out}"
163
206
  end
164
207
  end
165
- end
166
208
 
167
- existing_groups.each do |removegroup|
168
- if groups.index(removegroup).nil?
209
+ (have_groups - want_groups).each do |removegroup|
169
210
  # User is in a group, but shouldn't be, so remove them.
170
211
  STDERR.puts "Remove user #{username} from #{removegroup} group"
171
212
  out, st = Open3.capture2e("gpasswd", "-d", username, removegroup)
@@ -175,96 +216,86 @@ begin
175
216
  end
176
217
  end
177
218
 
178
- homedir = pwnam[l[:username]].dir
179
- userdotssh = File.join(homedir, ".ssh")
180
- Dir.mkdir(userdotssh) if !File.exist?(userdotssh)
219
+ if actions[:SyncUserSSHKeys]
220
+ userdotssh = File.join(homedir, ".ssh")
221
+ ensure_dir(userdotssh, 0700, username, user_gid)
181
222
 
182
- newkeys = "###\n###\n" + keys[l[:username]].join("\n") + "\n###\n###\n"
223
+ newkeys = "###\n###\n" + keys[l[:username]].join("\n") + "\n###\n###\n"
183
224
 
184
- keysfile = File.join(userdotssh, "authorized_keys")
225
+ keysfile = File.join(userdotssh, "authorized_keys")
226
+ begin
227
+ oldkeys = File.read(keysfile)
228
+ rescue Errno::ENOENT
229
+ oldkeys = ""
230
+ end
185
231
 
186
- if File.exist?(keysfile)
187
- oldkeys = IO::read(keysfile)
188
- else
189
- oldkeys = ""
190
- end
232
+ if options[:exclusive]
233
+ newkeys = exclusive_banner + newkeys
234
+ elsif oldkeys.start_with?(exclusive_banner)
235
+ newkeys = start_banner + newkeys + end_banner
236
+ elsif (m = /^(.*?\n|)#{start_banner}(.*?\n|)#{end_banner}(.*)/m.match(oldkeys))
237
+ newkeys = m[1] + start_banner + newkeys + end_banner + m[3]
238
+ else
239
+ newkeys = start_banner + newkeys + end_banner + oldkeys
240
+ end
191
241
 
192
- if options[:exclusive]
193
- newkeys = exclusive_banner + newkeys
194
- elsif oldkeys.start_with?(exclusive_banner)
195
- newkeys = start_banner + newkeys + end_banner
196
- elsif (m = /^(.*?\n|)#{start_banner}(.*?\n|)#{end_banner}(.*)/m.match(oldkeys))
197
- newkeys = m[1] + start_banner + newkeys + end_banner + m[3]
198
- else
199
- newkeys = start_banner + newkeys + end_banner + oldkeys
242
+ if oldkeys != newkeys then
243
+ File.open(keysfile, 'w', 0600) do |f|
244
+ f.write(newkeys)
245
+ end
246
+ FileUtils.chown(username, user_gid, keysfile)
247
+ end
200
248
  end
201
249
 
202
- if oldkeys != newkeys then
203
- f = File.new(keysfile, 'w')
204
- f.write(newkeys)
205
- f.close()
206
- end
250
+ if actions[:SyncUserAPITokens]
251
+ userdotconfig = File.join(homedir, ".config")
252
+ ensure_dir(userdotconfig, 0755, username, user_gid)
253
+ configarvados = File.join(userdotconfig, "arvados")
254
+ ensure_dir(configarvados, 0700, username, user_gid)
207
255
 
208
- userdotconfig = File.join(homedir, ".config")
209
- if !File.exist?(userdotconfig)
210
- Dir.mkdir(userdotconfig)
211
- end
256
+ tokenfile = File.join(configarvados, "settings.conf")
212
257
 
213
- configarvados = File.join(userdotconfig, "arvados")
214
- Dir.mkdir(configarvados) if !File.exist?(configarvados)
215
-
216
- tokenfile = File.join(configarvados, "settings.conf")
217
-
218
- begin
219
- STDERR.puts "Processing #{tokenfile} ..." if debug
220
- newToken = false
221
- if File.exist?(tokenfile)
222
- # check if the token is still valid
223
- myToken = ENV["ARVADOS_API_TOKEN"]
224
- userEnv = IO::read(tokenfile)
225
- if (m = /^ARVADOS_API_TOKEN=(.*?\n)/m.match(userEnv))
226
- begin
227
- tmp_arv = Arvados.new({ :api_host => logincluster_host,
228
- :api_token => (m[1]),
229
- :suppress_ssl_warnings => false })
230
- tmp_arv.user.current
231
- rescue Arvados::TransactionFailedError => e
232
- if e.to_s =~ /401 Unauthorized/
233
- STDERR.puts "Account #{l[:username]} token not valid, creating new token."
234
- newToken = true
235
- else
236
- raise
258
+ begin
259
+ STDERR.puts "Processing #{tokenfile} ..." if debug
260
+ newToken = false
261
+ if File.exist?(tokenfile)
262
+ # check if the token is still valid
263
+ myToken = ENV["ARVADOS_API_TOKEN"]
264
+ userEnv = File.read(tokenfile)
265
+ if (m = /^ARVADOS_API_TOKEN=(.*?\n)/m.match(userEnv))
266
+ begin
267
+ tmp_arv = Arvados.new({ :api_host => logincluster_host,
268
+ :api_token => (m[1]),
269
+ :suppress_ssl_warnings => false })
270
+ tmp_arv.user.current
271
+ rescue Arvados::TransactionFailedError => e
272
+ if e.to_s =~ /401 Unauthorized/
273
+ STDERR.puts "Account #{l[:username]} token not valid, creating new token."
274
+ newToken = true
275
+ else
276
+ raise
277
+ end
237
278
  end
238
279
  end
280
+ elsif !File.exist?(tokenfile) || options[:"rotate-tokens"]
281
+ STDERR.puts "Account #{l[:username]} token file not found, creating new token."
282
+ newToken = true
239
283
  end
240
- elsif !File.exist?(tokenfile) || options[:"rotate-tokens"]
241
- STDERR.puts "Account #{l[:username]} token file not found, creating new token."
242
- newToken = true
243
- end
244
- if newToken
245
- aca_params = {owner_uuid: l[:user_uuid], api_client_id: 0}
246
- if options[:"token-lifetime"] && options[:"token-lifetime"] > 0
247
- aca_params.merge!(expires_at: (Time.now + options[:"token-lifetime"]))
284
+ if newToken
285
+ aca_params = {owner_uuid: l[:user_uuid], api_client_id: 0}
286
+ if options[:"token-lifetime"] && options[:"token-lifetime"] > 0
287
+ aca_params.merge!(expires_at: (Time.now + options[:"token-lifetime"]))
288
+ end
289
+ user_token = logincluster_arv.api_client_authorization.create(api_client_authorization: aca_params)
290
+ File.open(tokenfile, 'w', 0600) do |f|
291
+ f.write("ARVADOS_API_HOST=#{ENV['ARVADOS_API_HOST']}\n")
292
+ f.write("ARVADOS_API_TOKEN=v2/#{user_token[:uuid]}/#{user_token[:api_token]}\n")
293
+ end
294
+ FileUtils.chown(username, user_gid, tokenfile)
248
295
  end
249
- user_token = logincluster_arv.api_client_authorization.create(api_client_authorization: aca_params)
250
- f = File.new(tokenfile, 'w')
251
- f.write("ARVADOS_API_HOST=#{ENV['ARVADOS_API_HOST']}\n")
252
- f.write("ARVADOS_API_TOKEN=v2/#{user_token[:uuid]}/#{user_token[:api_token]}\n")
253
- f.close()
296
+ rescue => e
297
+ STDERR.puts "Error setting token for #{l[:username]}: #{e}"
254
298
  end
255
- rescue => e
256
- STDERR.puts "Error setting token for #{l[:username]}: #{e}"
257
- end
258
-
259
- FileUtils.chown_R(l[:username], nil, userdotssh)
260
- FileUtils.chown_R(l[:username], nil, userdotconfig)
261
- File.chmod(0700, userdotssh)
262
- File.chmod(0700, userdotconfig)
263
- File.chmod(0700, configarvados)
264
- File.chmod(0750, homedir)
265
- File.chmod(0600, keysfile)
266
- if File.exist?(tokenfile)
267
- File.chmod(0600, tokenfile)
268
299
  end
269
300
  end
270
301
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arvados-login-sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.3
4
+ version: 2.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arvados Authors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-13 00:00:00.000000000 Z
11
+ date: 2023-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: arvados
@@ -79,7 +79,7 @@ dependencies:
79
79
  - !ruby/object:Gem::Version
80
80
  version: '0.12'
81
81
  description: Creates and updates local login accounts for Arvados users. Built from
82
- git commit 83974ae9df4060f7aaa6bba61997404a2a7405b2
82
+ git commit b5dad64d1faa5063482db0d33d22805912abdda6
83
83
  email: packaging@arvados.org
84
84
  executables:
85
85
  - arvados-login-sync