Skip to content

Commit 8c63d48

Browse files
committed
Rework message request and response
1 parent 20d132c commit 8c63d48

File tree

105 files changed

+1097
-433
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+1097
-433
lines changed

fs/cache.go

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ type MetadataCacheTimeoutSetting struct {
1717
Inherit bool
1818
}
1919

20+
// CacheConfig defines cache config
2021
type CacheConfig struct {
2122
Timeout time.Duration // cache timeout
2223
CleanupTime time.Duration //
@@ -30,6 +31,7 @@ type CacheConfig struct {
3031
StartNewTransaction bool
3132
}
3233

34+
// NewDefaultCacheConfig creates a new default CacheConfig
3335
func NewDefaultCacheConfig() CacheConfig {
3436
return CacheConfig{
3537
Timeout: FileSystemTimeoutDefault,

icommands/environment.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ func (manager *ICommandsEnvironmentManager) Load(processID int) error {
198198
// continue
199199
} else {
200200
authScheme := types.GetAuthScheme(manager.Environment.AuthenticationScheme)
201-
if authScheme == types.AuthSchemePAM {
201+
if authScheme.IsPAM() {
202202
manager.Password = ""
203203
manager.PamToken = password
204204
} else {
@@ -247,7 +247,7 @@ func (manager *ICommandsEnvironmentManager) SaveEnvironment() error {
247247
authScheme := types.GetAuthScheme(manager.Environment.AuthenticationScheme)
248248

249249
password := manager.Password
250-
if authScheme == types.AuthSchemePAM {
250+
if authScheme.IsPAM() {
251251
password = manager.PamToken
252252
}
253253

irods/connection/connection.go

+107-73
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ func (conn *IRODSConnection) SupportParallelUpload() bool {
119119
return conn.serverVersion.HasHigherVersionThan(4, 2, 9)
120120
}
121121

122+
func (conn *IRODSConnection) requirePAMPassword() bool {
123+
return conn.serverVersion.HasHigherVersionThan(4, 3, 0)
124+
}
125+
122126
func (conn *IRODSConnection) requiresCSNegotiation() bool {
123127
return conn.account.ClientServerNegotiation
124128
}
@@ -203,27 +207,13 @@ func (conn *IRODSConnection) setSocketOpt(socket net.Conn, bufferSize int) {
203207
}
204208
}
205209

206-
// Connect connects to iRODS
207-
func (conn *IRODSConnection) Connect() error {
210+
func (conn *IRODSConnection) connectTCP() error {
208211
logger := log.WithFields(log.Fields{
209212
"package": "connection",
210213
"struct": "IRODSConnection",
211-
"function": "Connect",
214+
"function": "connectTCP",
212215
})
213216

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-
227217
server := fmt.Sprintf("%s:%d", conn.account.Host, conn.account.Port)
228218
logger.Debugf("Connecting to %s", server)
229219

@@ -250,16 +240,37 @@ func (conn *IRODSConnection) Connect() error {
250240
}
251241

252242
conn.socket = socket
253-
var irodsVersion *types.IRODSVersion
243+
return nil
244+
}
254245

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
261271
}
262272

273+
irodsVersion, err := conn.startup()
263274
if err != nil {
264275
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())
265276
logger.Errorf("%+v", connErr)
@@ -277,11 +288,38 @@ func (conn *IRODSConnection) Connect() error {
277288
err = conn.loginNative()
278289
case types.AuthSchemeGSI:
279290
err = conn.loginGSI()
280-
case types.AuthSchemePAM:
291+
case types.AuthSchemePAM, types.AuthSchemePAMPassword:
281292
if len(conn.account.PamToken) > 0 {
282293
err = conn.loginPAMWithToken()
283294
} else {
284295
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()
285323
}
286324
default:
287325
err = xerrors.Errorf("unknown Authentication Scheme %q: %w", conn.account.AuthenticationScheme, types.NewConnectionConfigError(conn.account))
@@ -296,41 +334,54 @@ func (conn *IRODSConnection) Connect() error {
296334

297335
if conn.account.UseTicket() {
298336
req := message.NewIRODSMessageTicketAdminRequest("session", conn.account.Ticket)
299-
err := conn.RequestAndCheck(req, &message.IRODSMessageAdminResponse{}, nil)
337+
err := conn.RequestAndCheck(req, &message.IRODSMessageTicketAdminResponse{}, nil)
300338
if err != nil {
301339
return xerrors.Errorf("received supply ticket error (%s): %w", err.Error(), types.NewAuthError(conn.account))
302340
}
303341
}
304342

305343
conn.connected = true
306344
conn.lastSuccessfulAccess = time.Now()
307-
308345
return nil
309346
}
310347

311-
func (conn *IRODSConnection) connectWithCSNegotiation() (*types.IRODSVersion, error) {
348+
func (conn *IRODSConnection) startup() (*types.IRODSVersion, error) {
312349
logger := log.WithFields(log.Fields{
313350
"package": "connection",
314351
"struct": "IRODSConnection",
315-
"function": "connectWithCSNegotiation",
352+
"function": "startup",
316353
})
317354

318-
// Get client negotiation policy
319355
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+
}
322361
}
323362

363+
logger.Debug("Start up an iRODS connection")
364+
324365
// Send a startup message
325-
logger.Debug("Start up a connection with CS Negotiation")
366+
startup := message.NewIRODSMessageStartupPack(conn.account, conn.applicationName, conn.requiresCSNegotiation())
326367

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
331382
}
332383

333-
// Server responds with negotiation response
384+
// cs negotiation response
334385
negotiationMessage, err := conn.ReadMessage(nil)
335386
if err != nil {
336387
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
394445
}
395446

396447
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-
}
416448

417-
return version.GetVersion(), nil
418449
}
419450

420451
func (conn *IRODSConnection) sslStartup() error {
@@ -476,7 +507,7 @@ func (conn *IRODSConnection) sslStartup() error {
476507

477508
// Send a shared secret
478509
sslSharedSecret := message.NewIRODSMessageSSLSharedSecret(encryptionKey)
479-
err = conn.RequestWithoutResponseNoXML(sslSharedSecret)
510+
err = conn.RequestWithoutResponse(sslSharedSecret)
480511
if err != nil {
481512
return xerrors.Errorf("failed to send ssl shared secret message (%s): %w", err.Error(), types.NewConnectionError())
482513
}
@@ -490,7 +521,7 @@ func (conn *IRODSConnection) login(password string) error {
490521
// authenticate
491522
authRequest := message.NewIRODSMessageAuthRequest()
492523
authChallenge := message.IRODSMessageAuthChallengeResponse{}
493-
err := conn.Request(authRequest, &authChallenge, nil)
524+
err := conn.RequestAndCheck(authRequest, &authChallenge, nil)
494525
if err != nil {
495526
return xerrors.Errorf("failed to receive authentication challenge message body (%s): %w", err.Error(), types.NewAuthError(conn.account))
496527
}
@@ -551,7 +582,7 @@ func (conn *IRODSConnection) loginPAMWithPassword() error {
551582

552583
ttl := conn.account.PamTTL
553584
if ttl < 0 {
554-
ttl = 0 // decided by server
585+
ttl = 0 // server decides
555586
}
556587

557588
pamPassword := conn.getSafePAMPassword(conn.account.Password)
@@ -562,41 +593,43 @@ func (conn *IRODSConnection) loginPAMWithPassword() error {
562593

563594
authContext := strings.Join([]string{userKV, passwordKV, ttlKV}, ";")
564595

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
573599
}
574600

575601
// authenticate
576602
pamToken := ""
603+
577604
if useDedicatedPAMApi {
605+
logger.Debugf("use dedicated PAM api")
606+
578607
pamAuthRequest := message.NewIRODSMessagePamAuthRequest(conn.account.ClientUser, pamPassword, ttl)
579608
pamAuthResponse := message.IRODSMessagePamAuthResponse{}
580-
err := conn.Request(pamAuthRequest, &pamAuthResponse, nil)
609+
err := conn.RequestAndCheck(pamAuthRequest, &pamAuthResponse, nil)
581610
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))
583612
}
584613

585614
pamToken = pamAuthResponse.GeneratedPassword
586615
} else {
616+
logger.Debugf("use auth plugin api: scheme %q", string(types.AuthSchemePAM))
617+
587618
pamAuthRequest := message.NewIRODSMessageAuthPluginRequest(string(types.AuthSchemePAM), authContext)
588619
pamAuthResponse := message.IRODSMessageAuthPluginResponse{}
589-
err := conn.Request(pamAuthRequest, &pamAuthResponse, nil)
620+
err := conn.RequestAndCheck(pamAuthRequest, &pamAuthResponse, nil)
590621
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))
592623
}
593624

594-
pamToken = pamAuthResponse.Result
625+
pamToken = string(pamAuthResponse.GeneratedPassword)
595626
}
596627

597628
// save irods generated password for possible future use
598629
conn.account.PamToken = pamToken
599630

631+
// disconnect and connect
632+
600633
// retry native auth with generated password
601634
return conn.login(conn.account.PamToken)
602635
}
@@ -1053,6 +1086,7 @@ func (conn *IRODSConnection) poorMansEndTransaction(dummyCol string, commit bool
10531086
if commit {
10541087
request.AddKeyVal(common.COLLECTION_TYPE_KW, "NULL_SPECIAL_VALUE")
10551088
}
1089+
10561090
response := message.IRODSMessageModifyCollectionResponse{}
10571091
err := conn.Request(request, &response, nil)
10581092
if err != nil {

0 commit comments

Comments
 (0)