@@ -119,6 +119,10 @@ func (conn *IRODSConnection) SupportParallelUpload() bool {
119
119
return conn .serverVersion .HasHigherVersionThan (4 , 2 , 9 )
120
120
}
121
121
122
+ func (conn * IRODSConnection ) requirePAMPassword () bool {
123
+ return conn .serverVersion .HasHigherVersionThan (4 , 3 , 0 )
124
+ }
125
+
122
126
func (conn * IRODSConnection ) requiresCSNegotiation () bool {
123
127
return conn .account .ClientServerNegotiation
124
128
}
@@ -203,27 +207,13 @@ func (conn *IRODSConnection) setSocketOpt(socket net.Conn, bufferSize int) {
203
207
}
204
208
}
205
209
206
- // Connect connects to iRODS
207
- func (conn * IRODSConnection ) Connect () error {
210
+ func (conn * IRODSConnection ) connectTCP () error {
208
211
logger := log .WithFields (log.Fields {
209
212
"package" : "connection" ,
210
213
"struct" : "IRODSConnection" ,
211
- "function" : "Connect " ,
214
+ "function" : "connectTCP " ,
212
215
})
213
216
214
- conn .connected = false
215
-
216
- conn .account .FixAuthConfiguration ()
217
-
218
- err := conn .account .Validate ()
219
- if err != nil {
220
- return xerrors .Errorf ("invalid account (%q): %w" , err .Error (), types .NewConnectionConfigError (conn .account ))
221
- }
222
-
223
- // lock the connection
224
- conn .Lock ()
225
- defer conn .Unlock ()
226
-
227
217
server := fmt .Sprintf ("%s:%d" , conn .account .Host , conn .account .Port )
228
218
logger .Debugf ("Connecting to %s" , server )
229
219
@@ -250,16 +240,37 @@ func (conn *IRODSConnection) Connect() error {
250
240
}
251
241
252
242
conn .socket = socket
253
- var irodsVersion * types.IRODSVersion
243
+ return nil
244
+ }
254
245
255
- if conn .requiresCSNegotiation () {
256
- // client-server negotiation
257
- irodsVersion , err = conn .connectWithCSNegotiation ()
258
- } else {
259
- // No client-server negotiation
260
- irodsVersion , err = conn .connectWithoutCSNegotiation ()
246
+ // Connect connects to iRODS
247
+ func (conn * IRODSConnection ) Connect () error {
248
+ logger := log .WithFields (log.Fields {
249
+ "package" : "connection" ,
250
+ "struct" : "IRODSConnection" ,
251
+ "function" : "Connect" ,
252
+ })
253
+
254
+ conn .account .FixAuthConfiguration ()
255
+
256
+ err := conn .account .Validate ()
257
+ if err != nil {
258
+ return xerrors .Errorf ("invalid account (%q): %w" , err .Error (), types .NewConnectionConfigError (conn .account ))
259
+ }
260
+
261
+ conn .connected = false
262
+
263
+ // lock the connection
264
+ conn .Lock ()
265
+ defer conn .Unlock ()
266
+
267
+ // connect TCP
268
+ err = conn .connectTCP ()
269
+ if err != nil {
270
+ return err
261
271
}
262
272
273
+ irodsVersion , err := conn .startup ()
263
274
if err != nil {
264
275
connErr := xerrors .Errorf ("failed to startup an iRODS connection to server %q and port %d (%s): %w" , conn .account .Host , conn .account .Port , err .Error (), types .NewConnectionError ())
265
276
logger .Errorf ("%+v" , connErr )
@@ -277,11 +288,38 @@ func (conn *IRODSConnection) Connect() error {
277
288
err = conn .loginNative ()
278
289
case types .AuthSchemeGSI :
279
290
err = conn .loginGSI ()
280
- case types .AuthSchemePAM :
291
+ case types .AuthSchemePAM , types . AuthSchemePAMPassword :
281
292
if len (conn .account .PamToken ) > 0 {
282
293
err = conn .loginPAMWithToken ()
283
294
} else {
284
295
err = conn .loginPAMWithPassword ()
296
+ if err != nil {
297
+ connErr := xerrors .Errorf ("failed to login to irods using PAM authentication: %w" , err )
298
+ logger .Errorf ("%+v" , connErr )
299
+ return connErr
300
+ }
301
+
302
+ // reconnect when success
303
+ conn .disconnectNow ()
304
+
305
+ // connect TCP
306
+ err = conn .connectTCP ()
307
+ if err != nil {
308
+ return err
309
+ }
310
+
311
+ _ , err = conn .startup ()
312
+ if err != nil {
313
+ connErr := xerrors .Errorf ("failed to startup an iRODS connection to server %q and port %d (%s): %w" , conn .account .Host , conn .account .Port , err .Error (), types .NewConnectionError ())
314
+ logger .Errorf ("%+v" , connErr )
315
+ _ = conn .disconnectNow ()
316
+ if conn .metrics != nil {
317
+ conn .metrics .IncreaseCounterForConnectionFailures (1 )
318
+ }
319
+ return connErr
320
+ }
321
+
322
+ err = conn .loginPAMWithToken ()
285
323
}
286
324
default :
287
325
err = xerrors .Errorf ("unknown Authentication Scheme %q: %w" , conn .account .AuthenticationScheme , types .NewConnectionConfigError (conn .account ))
@@ -296,41 +334,54 @@ func (conn *IRODSConnection) Connect() error {
296
334
297
335
if conn .account .UseTicket () {
298
336
req := message .NewIRODSMessageTicketAdminRequest ("session" , conn .account .Ticket )
299
- err := conn .RequestAndCheck (req , & message.IRODSMessageAdminResponse {}, nil )
337
+ err := conn .RequestAndCheck (req , & message.IRODSMessageTicketAdminResponse {}, nil )
300
338
if err != nil {
301
339
return xerrors .Errorf ("received supply ticket error (%s): %w" , err .Error (), types .NewAuthError (conn .account ))
302
340
}
303
341
}
304
342
305
343
conn .connected = true
306
344
conn .lastSuccessfulAccess = time .Now ()
307
-
308
345
return nil
309
346
}
310
347
311
- func (conn * IRODSConnection ) connectWithCSNegotiation () (* types.IRODSVersion , error ) {
348
+ func (conn * IRODSConnection ) startup () (* types.IRODSVersion , error ) {
312
349
logger := log .WithFields (log.Fields {
313
350
"package" : "connection" ,
314
351
"struct" : "IRODSConnection" ,
315
- "function" : "connectWithCSNegotiation " ,
352
+ "function" : "startup " ,
316
353
})
317
354
318
- // Get client negotiation policy
319
355
clientPolicy := types .CSNegotiationRequireTCP
320
- if len (conn .account .CSNegotiationPolicy ) > 0 {
321
- clientPolicy = conn .account .CSNegotiationPolicy
356
+ if conn .requiresCSNegotiation () {
357
+ // Get client negotiation policy
358
+ if len (conn .account .CSNegotiationPolicy ) > 0 {
359
+ clientPolicy = conn .account .CSNegotiationPolicy
360
+ }
322
361
}
323
362
363
+ logger .Debug ("Start up an iRODS connection" )
364
+
324
365
// Send a startup message
325
- logger . Debug ( "Start up a connection with CS Negotiation" )
366
+ startup := message . NewIRODSMessageStartupPack ( conn . account , conn . applicationName , conn . requiresCSNegotiation () )
326
367
327
- startup := message .NewIRODSMessageStartupPack (conn .account , conn .applicationName , true )
328
- err := conn .RequestWithoutResponse (startup )
329
- if err != nil {
330
- return nil , xerrors .Errorf ("failed to send startup (%s): %w" , err .Error (), types .NewConnectionError ())
368
+ if conn .requiresCSNegotiation () {
369
+ err := conn .RequestWithoutResponse (startup )
370
+ if err != nil {
371
+ return nil , xerrors .Errorf ("failed to send startup (%s): %w" , err .Error (), types .NewConnectionError ())
372
+ }
373
+ } else {
374
+ // no cs negotiation
375
+ version := message.IRODSMessageVersion {}
376
+ err := conn .Request (startup , & version , nil )
377
+ if err != nil {
378
+ return nil , xerrors .Errorf ("failed to receive version message (%s): %w" , err .Error (), types .NewConnectionError ())
379
+ }
380
+
381
+ return version .GetVersion (), nil
331
382
}
332
383
333
- // Server responds with negotiation response
384
+ // cs negotiation response
334
385
negotiationMessage , err := conn .ReadMessage (nil )
335
386
if err != nil {
336
387
return nil , xerrors .Errorf ("failed to receive negotiation message (%s): %w" , err .Error (), types .NewConnectionError ())
@@ -394,27 +445,7 @@ func (conn *IRODSConnection) connectWithCSNegotiation() (*types.IRODSVersion, er
394
445
}
395
446
396
447
return nil , xerrors .Errorf ("unknown response message %q: %w" , negotiationMessage .Body .Type , types .NewConnectionError ())
397
- }
398
-
399
- func (conn * IRODSConnection ) connectWithoutCSNegotiation () (* types.IRODSVersion , error ) {
400
- logger := log .WithFields (log.Fields {
401
- "package" : "connection" ,
402
- "struct" : "IRODSConnection" ,
403
- "function" : "connectWithoutCSNegotiation" ,
404
- })
405
-
406
- // No client-server negotiation
407
- // Send a startup message
408
- logger .Debug ("Start up connection without CS Negotiation" )
409
-
410
- startup := message .NewIRODSMessageStartupPack (conn .account , conn .applicationName , false )
411
- version := message.IRODSMessageVersion {}
412
- err := conn .Request (startup , & version , nil )
413
- if err != nil {
414
- return nil , xerrors .Errorf ("failed to receive version message (%s): %w" , err .Error (), types .NewConnectionError ())
415
- }
416
448
417
- return version .GetVersion (), nil
418
449
}
419
450
420
451
func (conn * IRODSConnection ) sslStartup () error {
@@ -476,7 +507,7 @@ func (conn *IRODSConnection) sslStartup() error {
476
507
477
508
// Send a shared secret
478
509
sslSharedSecret := message .NewIRODSMessageSSLSharedSecret (encryptionKey )
479
- err = conn .RequestWithoutResponseNoXML (sslSharedSecret )
510
+ err = conn .RequestWithoutResponse (sslSharedSecret )
480
511
if err != nil {
481
512
return xerrors .Errorf ("failed to send ssl shared secret message (%s): %w" , err .Error (), types .NewConnectionError ())
482
513
}
@@ -490,7 +521,7 @@ func (conn *IRODSConnection) login(password string) error {
490
521
// authenticate
491
522
authRequest := message .NewIRODSMessageAuthRequest ()
492
523
authChallenge := message.IRODSMessageAuthChallengeResponse {}
493
- err := conn .Request (authRequest , & authChallenge , nil )
524
+ err := conn .RequestAndCheck (authRequest , & authChallenge , nil )
494
525
if err != nil {
495
526
return xerrors .Errorf ("failed to receive authentication challenge message body (%s): %w" , err .Error (), types .NewAuthError (conn .account ))
496
527
}
@@ -551,7 +582,7 @@ func (conn *IRODSConnection) loginPAMWithPassword() error {
551
582
552
583
ttl := conn .account .PamTTL
553
584
if ttl < 0 {
554
- ttl = 0 // decided by server
585
+ ttl = 0 // server decides
555
586
}
556
587
557
588
pamPassword := conn .getSafePAMPassword (conn .account .Password )
@@ -562,41 +593,43 @@ func (conn *IRODSConnection) loginPAMWithPassword() error {
562
593
563
594
authContext := strings .Join ([]string {userKV , passwordKV , ttlKV }, ";" )
564
595
565
- useDedicatedPAMApi := false
566
- if strings .ContainsAny (pamPassword , ";=" ) {
567
- useDedicatedPAMApi = true
568
- } else {
569
- // from python-irodsclient code
570
- if len (authContext ) >= 1024 + 64 {
571
- useDedicatedPAMApi = true
572
- }
596
+ useDedicatedPAMApi := true
597
+ if conn .requirePAMPassword () {
598
+ useDedicatedPAMApi = strings .ContainsAny (pamPassword , ";=" ) || len (authContext ) >= 1024 + 64
573
599
}
574
600
575
601
// authenticate
576
602
pamToken := ""
603
+
577
604
if useDedicatedPAMApi {
605
+ logger .Debugf ("use dedicated PAM api" )
606
+
578
607
pamAuthRequest := message .NewIRODSMessagePamAuthRequest (conn .account .ClientUser , pamPassword , ttl )
579
608
pamAuthResponse := message.IRODSMessagePamAuthResponse {}
580
- err := conn .Request (pamAuthRequest , & pamAuthResponse , nil )
609
+ err := conn .RequestAndCheck (pamAuthRequest , & pamAuthResponse , nil )
581
610
if err != nil {
582
- return xerrors .Errorf ("failed to receive an authentication challenge message (%s): %w" , err .Error (), types .NewAuthError (conn .account ))
611
+ return xerrors .Errorf ("failed to receive a PAM token (%s): %w" , err .Error (), types .NewAuthError (conn .account ))
583
612
}
584
613
585
614
pamToken = pamAuthResponse .GeneratedPassword
586
615
} else {
616
+ logger .Debugf ("use auth plugin api: scheme %q" , string (types .AuthSchemePAM ))
617
+
587
618
pamAuthRequest := message .NewIRODSMessageAuthPluginRequest (string (types .AuthSchemePAM ), authContext )
588
619
pamAuthResponse := message.IRODSMessageAuthPluginResponse {}
589
- err := conn .Request (pamAuthRequest , & pamAuthResponse , nil )
620
+ err := conn .RequestAndCheck (pamAuthRequest , & pamAuthResponse , nil )
590
621
if err != nil {
591
- return xerrors .Errorf ("failed to receive an authentication challenge message (%s): %w" , err .Error (), types .NewAuthError (conn .account ))
622
+ return xerrors .Errorf ("failed to receive a PAM token (%s): %w" , err .Error (), types .NewAuthError (conn .account ))
592
623
}
593
624
594
- pamToken = pamAuthResponse .Result
625
+ pamToken = string ( pamAuthResponse .GeneratedPassword )
595
626
}
596
627
597
628
// save irods generated password for possible future use
598
629
conn .account .PamToken = pamToken
599
630
631
+ // disconnect and connect
632
+
600
633
// retry native auth with generated password
601
634
return conn .login (conn .account .PamToken )
602
635
}
@@ -1053,6 +1086,7 @@ func (conn *IRODSConnection) poorMansEndTransaction(dummyCol string, commit bool
1053
1086
if commit {
1054
1087
request .AddKeyVal (common .COLLECTION_TYPE_KW , "NULL_SPECIAL_VALUE" )
1055
1088
}
1089
+
1056
1090
response := message.IRODSMessageModifyCollectionResponse {}
1057
1091
err := conn .Request (request , & response , nil )
1058
1092
if err != nil {
0 commit comments