...

Source file src/go.mongodb.org/mongo-driver/x/mongo/driver/auth/speculative_x509_test.go

Documentation: go.mongodb.org/mongo-driver/x/mongo/driver/auth

     1  // Copyright (C) MongoDB, Inc. 2017-present.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"); you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
     6  
     7  package auth
     8  
     9  import (
    10  	"bytes"
    11  	"context"
    12  	"testing"
    13  
    14  	"go.mongodb.org/mongo-driver/bson"
    15  	"go.mongodb.org/mongo-driver/internal/assert"
    16  	"go.mongodb.org/mongo-driver/internal/handshake"
    17  	"go.mongodb.org/mongo-driver/mongo/address"
    18  	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
    19  	"go.mongodb.org/mongo-driver/x/mongo/driver/drivertest"
    20  )
    21  
    22  var (
    23  	x509Response bsoncore.Document = bsoncore.BuildDocumentFromElements(nil,
    24  		bsoncore.AppendStringElement(nil, "dbname", "$external"),
    25  		bsoncore.AppendStringElement(nil, "user", "username"),
    26  		bsoncore.AppendInt32Element(nil, "ok", 1),
    27  	)
    28  )
    29  
    30  func TestSpeculativeX509(t *testing.T) {
    31  	t.Run("speculative response included", func(t *testing.T) {
    32  		// Tests for X509 when the hello response contains a reply to the speculative authentication attempt. The
    33  		// driver should not send any more commands after the hello.
    34  
    35  		authenticator, err := CreateAuthenticator("MONGODB-X509", &Cred{})
    36  		assert.Nil(t, err, "CreateAuthenticator error: %v", err)
    37  		handshaker := Handshaker(nil, &HandshakeOptions{
    38  			Authenticator: authenticator,
    39  		})
    40  
    41  		numResponses := 1
    42  		responses := make(chan []byte, numResponses)
    43  		writeReplies(responses, createSpeculativeX509Handshake()...)
    44  
    45  		conn := &drivertest.ChannelConn{
    46  			Written:  make(chan []byte, numResponses),
    47  			ReadResp: responses,
    48  		}
    49  
    50  		info, err := handshaker.GetHandshakeInformation(context.Background(), address.Address("localhost:27017"), conn)
    51  		assert.Nil(t, err, "GetDescription error: %v", err)
    52  		assert.NotNil(t, info.SpeculativeAuthenticate, "desc.SpeculativeAuthenticate not set")
    53  		conn.Desc = info.Description
    54  
    55  		err = handshaker.FinishHandshake(context.Background(), conn)
    56  		assert.Nil(t, err, "FinishHandshake error: %v", err)
    57  		assert.Equal(t, 0, len(conn.ReadResp), "%d messages left unread", len(conn.ReadResp))
    58  
    59  		assert.Equal(t, numResponses, len(conn.Written), "expected %d wire messages to be sent, got %d",
    60  			numResponses, len(conn.Written))
    61  		hello, err := drivertest.GetCommandFromQueryWireMessage(<-conn.Written)
    62  		assert.Nil(t, err, "error parsing hello command: %v", err)
    63  		assertCommandName(t, hello, handshake.LegacyHello)
    64  
    65  		authDocVal, err := hello.LookupErr("speculativeAuthenticate")
    66  		assert.Nil(t, err, "expected command %s to contain 'speculativeAuthenticate'", bson.Raw(hello))
    67  		authDoc := authDocVal.Document()
    68  		expectedAuthDoc := bsoncore.BuildDocumentFromElements(nil,
    69  			bsoncore.AppendInt32Element(nil, "authenticate", 1),
    70  			bsoncore.AppendStringElement(nil, "mechanism", "MONGODB-X509"),
    71  		)
    72  		assert.True(t, bytes.Equal(expectedAuthDoc, authDoc), "expected speculative auth document %s, got %s",
    73  			expectedAuthDoc, authDoc)
    74  	})
    75  	t.Run("speculative response not included", func(t *testing.T) {
    76  		// Tests for X509 when the hello response does not contain a reply to the speculative authentication attempt.
    77  		// The driver should send an authenticate command after the hello.
    78  
    79  		authenticator, err := CreateAuthenticator("MONGODB-X509", &Cred{})
    80  		assert.Nil(t, err, "CreateAuthenticator error: %v", err)
    81  		handshaker := Handshaker(nil, &HandshakeOptions{
    82  			Authenticator: authenticator,
    83  		})
    84  
    85  		numResponses := 2
    86  		responses := make(chan []byte, numResponses)
    87  		writeReplies(responses, createRegularX509Handshake()...)
    88  
    89  		conn := &drivertest.ChannelConn{
    90  			Written:  make(chan []byte, numResponses),
    91  			ReadResp: responses,
    92  		}
    93  
    94  		info, err := handshaker.GetHandshakeInformation(context.Background(), address.Address("localhost:27017"), conn)
    95  		assert.Nil(t, err, "GetDescription error: %v", err)
    96  		assert.Nil(t, info.SpeculativeAuthenticate, "expected desc.SpeculativeAuthenticate to be unset, got %s",
    97  			bson.Raw(info.SpeculativeAuthenticate))
    98  		conn.Desc = info.Description
    99  
   100  		err = handshaker.FinishHandshake(context.Background(), conn)
   101  		assert.Nil(t, err, "FinishHandshake error: %v", err)
   102  		assert.Equal(t, 0, len(conn.ReadResp), "%d messages left unread", len(conn.ReadResp))
   103  
   104  		assert.Equal(t, numResponses, len(conn.Written), "expected %d wire messages to be sent, got %d",
   105  			numResponses, len(conn.Written))
   106  		hello, err := drivertest.GetCommandFromQueryWireMessage(<-conn.Written)
   107  		assert.Nil(t, err, "error parsing hello command: %v", err)
   108  		assertCommandName(t, hello, handshake.LegacyHello)
   109  		_, err = hello.LookupErr("speculativeAuthenticate")
   110  		assert.Nil(t, err, "expected command %s to contain 'speculativeAuthenticate'", bson.Raw(hello))
   111  
   112  		authenticate, err := drivertest.GetCommandFromMsgWireMessage(<-conn.Written)
   113  		assert.Nil(t, err, "error parsing authenticate command: %v", err)
   114  		assertCommandName(t, authenticate, "authenticate")
   115  	})
   116  }
   117  
   118  // createSpeculativeX509Handshake creates the server replies for a successful speculative X509 authentication attempt.
   119  // There is only one reply:
   120  //
   121  // 1. hello reply containing a "speculativeAuthenticate" document.
   122  func createSpeculativeX509Handshake() []bsoncore.Document {
   123  	firstAuthElem := bsoncore.AppendDocumentElement(nil, "speculativeAuthenticate", x509Response)
   124  	hello := bsoncore.BuildDocumentFromElements(nil, append(handshakeHelloElements, firstAuthElem)...)
   125  	return []bsoncore.Document{hello}
   126  }
   127  
   128  // createSpeculativeX509Handshake creates the server replies for a handshake + X509 authentication attempt.
   129  // There are two replies:
   130  //
   131  // 1. hello reply
   132  // 2. authenticate reply
   133  func createRegularX509Handshake() []bsoncore.Document {
   134  	hello := bsoncore.BuildDocumentFromElements(nil, handshakeHelloElements...)
   135  	return []bsoncore.Document{hello, x509Response}
   136  }
   137  

View as plain text