Skip to content

Commit

Permalink
Merge pull request #76 from TykTechnologies/TT-8978
Browse files Browse the repository at this point in the history
[TT-8978] Fixing CosmosDB URL bug
  • Loading branch information
mativm02 authored May 22, 2023
2 parents 5116e3a + cbc5e70 commit 8451a35
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 13 deletions.
2 changes: 1 addition & 1 deletion persistent/internal/driver/mgo/life_cycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ type lifeCycle struct {

// Connect connects to the mongo database given the ClientOpts.
func (lc *lifeCycle) Connect(opts *types.ClientOpts) error {
opts.ConnectionString = helper.ParsePassword(opts.ConnectionString)
opts.ConnectionString = helper.EncodeConnectionString(opts.ConnectionString)

dialInfo, err := mgo.ParseURL(opts.ConnectionString)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion persistent/internal/driver/mongo/life_cycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (lc *lifeCycle) Connect(opts *types.ClientOpts) error {
var err error
var client *mongo.Client

opts.ConnectionString = helper.ParsePassword(opts.ConnectionString)
opts.ConnectionString = helper.EncodeConnectionString(opts.ConnectionString)

// we check if the connection string is valid before building the connOpts.
cs, err := connstring.ParseAndValidate(opts.ConnectionString)
Expand Down
39 changes: 32 additions & 7 deletions persistent/internal/helper/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,21 @@ func IsCosmosDB(connectionString string) bool {
strings.Contains(connectionString, "AccountKey=")
}

// ParsePassword parses the password from the connection string and URL encodes it.
// It's useful when the password contains special characters.
// EncodeConnectionString URL encodes the password and the username from the connection string.
// It's useful when they contains special characters.
// Example: mongodb://user:p@ssword@localhost:27017/db -> mongodb://user:p%40word@40localhost:27017/db
// If there's any conflict, the function returns the original connection string.
func ParsePassword(connectionString string) string {
// Find the last '@' (the delimiter between credentials and host)
at := strings.LastIndex(connectionString, "@")
func EncodeConnectionString(connectionString string) string {
// Find the last '@' before the last ':' (the delimiter between credentials and host)
// we use ':' since the URL can contain '@' characters after the port number
at := findLastAtBeforeLastColon(connectionString)
if at == -1 {
return connectionString
// If there's no ':' in the connection string, we use the last '@' as delimiter
at = findLastAt(connectionString)
// If there's no '@' in the connection string, we return the original connection string
if at == -1 {
return connectionString
}
}

credentialsAndScheme := connectionString[:at]
Expand All @@ -62,8 +68,27 @@ func ParsePassword(connectionString string) string {
// URL encode the password
encodedPassword := url.QueryEscape(password)

encodedUsername := url.QueryEscape(username)

// Construct the new connection string
newConnectionString := fmt.Sprintf("%s://%s:%s@%s", scheme, username, encodedPassword, hostAndDB)
newConnectionString := fmt.Sprintf("%s://%s:%s@%s", scheme, encodedUsername, encodedPassword, hostAndDB)

return newConnectionString
}

func findLastAtBeforeLastColon(str string) int {
lastColon := strings.LastIndex(str, ":")
if lastColon == -1 {
return -1
}

subStr := str[:lastColon]

lastAt := strings.LastIndex(subStr, "@")

return lastAt
}

func findLastAt(str string) int {
return strings.LastIndex(str, "@")
}
13 changes: 9 additions & 4 deletions persistent/internal/helper/functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func TestIsCosmosDB(t *testing.T) {
}
}

func TestParsePassword(t *testing.T) {
func TestEncodeConnectionString(t *testing.T) {
tests := []struct {
name string
originalConnString string
Expand All @@ -80,8 +80,8 @@ func TestParsePassword(t *testing.T) {
},
{
name: "valid connection string with @ and /",
originalConnString: "mongodb://user:p@sswor/d@localhost:27017/test",
expectedConnString: "mongodb://user:p%40sswor%2Fd@localhost:27017/test",
originalConnString: "mongodb://u=s@r:p@sswor/d@localhost:27017/test",
expectedConnString: "mongodb://u%3Ds%40r:p%40sswor%2Fd@localhost:27017/test",
},
{
name: "valid connection string with @ and / and '?' outside of the credentials part",
Expand Down Expand Up @@ -138,11 +138,16 @@ func TestParsePassword(t *testing.T) {
originalConnString: "mongodb://user:password@localhost:27017",
expectedConnString: "mongodb://user:password@localhost:27017",
},
{
name: "cosmosdb url",
originalConnString: "mongodb://4-0-qa:zFAQ==@4-0-qa.azure:10/a1?maxIdleTimeMS=120000&appName=@4-testing@",
expectedConnString: "mongodb://4-0-qa:zFAQ%3D%3D@4-0-qa.azure:10/a1?maxIdleTimeMS=120000&appName=@4-testing@",
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
connString := ParsePassword(test.originalConnString)
connString := EncodeConnectionString(test.originalConnString)
assert.Equal(t, test.expectedConnString, connString)
})
}
Expand Down

0 comments on commit 8451a35

Please sign in to comment.