Skip to content

Commit e2be667

Browse files
btiplingclaude
andcommitted
[BB-610] Add password generation for SQL Server authentication
- Remove manual password field in favor of automatic generation - Implement secure random password generator for SQL Server logins - Return generated password as plaintext data - Fix linting issues and improve code organization 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 68bac57 commit e2be667

File tree

2 files changed

+69
-19
lines changed

2 files changed

+69
-19
lines changed

pkg/connector/connector.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,6 @@ func (o *Mssqldb) Metadata(ctx context.Context) (*v2.ConnectorMetadata, error) {
6767
Placeholder: "username",
6868
Order: 3,
6969
},
70-
"password": {
71-
DisplayName: "Password",
72-
Required: false,
73-
Description: "The password for SQL Server authentication. Required when using SQL Server Authentication.",
74-
Field: &v2.ConnectorAccountCreationSchema_Field_StringField{
75-
StringField: &v2.ConnectorAccountCreationSchema_StringField{},
76-
},
77-
Placeholder: "password",
78-
Order: 4,
79-
},
8070
},
8171
},
8272
}, nil

pkg/connector/server_user.go

Lines changed: 69 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package connector
22

33
import (
44
"context"
5+
"crypto/rand"
56
"fmt"
7+
"math/big"
68
"net/mail"
79

810
v2 "github.com/conductorone/baton-sdk/pb/c1/connector/v2"
@@ -129,12 +131,9 @@ func (d *userPrincipalSyncer) CreateAccount(
129131
formattedUsername = username
130132
}
131133
case mssqldb.LoginTypeSQL:
132-
// For SQL auth, extract password
133-
passwordVal := accountInfo.Profile.GetFields()["password"]
134-
if passwordVal == nil || passwordVal.GetStringValue() == "" {
135-
return nil, nil, nil, fmt.Errorf("missing required password field for SQL Server authentication")
136-
}
137-
password = passwordVal.GetStringValue()
134+
// For SQL auth, generate a strong random password
135+
password = generateStrongPassword()
136+
l.Debug("generated random password for SQL Server authentication")
138137
formattedUsername = username
139138
case mssqldb.LoginTypeAzureAD, mssqldb.LoginTypeEntraID:
140139
// For Azure AD or Entra ID, just use the username as is
@@ -183,13 +182,26 @@ func (d *userPrincipalSyncer) CreateAccount(
183182
return nil, nil, nil, fmt.Errorf("failed to create resource for new user: %w", err)
184183
}
185184

186-
// Return success result with the new user resource
185+
// Prepare the response - for SQL auth, we need to return the generated password
187186
successResult := &v2.CreateAccountResponse_SuccessResult{
188187
Resource: resource,
189188
IsCreateAccountResult: true,
190189
}
191190

192-
return successResult, nil, nil, nil
191+
var plaintextData []*v2.PlaintextData
192+
// If this is SQL authentication, return the generated password
193+
if loginType == mssqldb.LoginTypeSQL {
194+
plaintextData = []*v2.PlaintextData{
195+
{
196+
Name: "password",
197+
Description: "The generated password for SQL Server authentication",
198+
Schema: "text/plain",
199+
Bytes: []byte(password),
200+
},
201+
}
202+
}
203+
204+
return successResult, plaintextData, nil, nil
193205
}
194206

195207
// CreateAccountCapabilityDetails returns the capability details for account creation.
@@ -198,12 +210,60 @@ func (d *userPrincipalSyncer) CreateAccountCapabilityDetails(
198210
) (*v2.CredentialDetailsAccountProvisioning, annotations.Annotations, error) {
199211
return &v2.CredentialDetailsAccountProvisioning{
200212
SupportedCredentialOptions: []v2.CapabilityDetailCredentialOption{
201-
v2.CapabilityDetailCredentialOption_CAPABILITY_DETAIL_CREDENTIAL_OPTION_NO_PASSWORD,
213+
v2.CapabilityDetailCredentialOption_CAPABILITY_DETAIL_CREDENTIAL_OPTION_NO_PASSWORD, // For Windows/Azure AD/Entra ID
214+
v2.CapabilityDetailCredentialOption_CAPABILITY_DETAIL_CREDENTIAL_OPTION_RANDOM_PASSWORD, // For SQL Server auth
202215
},
203216
PreferredCredentialOption: v2.CapabilityDetailCredentialOption_CAPABILITY_DETAIL_CREDENTIAL_OPTION_NO_PASSWORD,
204217
}, nil, nil
205218
}
206219

220+
// generateStrongPassword creates a secure random password for SQL Server.
221+
// The password meets SQL Server complexity requirements:
222+
// - At least 8 characters in length
223+
// - Contains uppercase, lowercase, numbers, and special characters.
224+
func generateStrongPassword() string {
225+
const (
226+
uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
227+
lowercaseChars = "abcdefghijklmnopqrstuvwxyz"
228+
numberChars = "0123456789"
229+
specialChars = "!@#$%^&*()-_=+[]{}|;:,.<>?"
230+
passwordLength = 16
231+
)
232+
233+
// Ensure at least one character from each category
234+
password := make([]byte, passwordLength)
235+
236+
// Add at least one character from each required group
237+
addRandomChar := func(charSet string, position int) {
238+
maxVal := big.NewInt(int64(len(charSet)))
239+
randomIndex, _ := rand.Int(rand.Reader, maxVal)
240+
password[position] = charSet[randomIndex.Int64()]
241+
}
242+
243+
// Add one of each required character type
244+
addRandomChar(uppercaseChars, 0)
245+
addRandomChar(lowercaseChars, 1)
246+
addRandomChar(numberChars, 2)
247+
addRandomChar(specialChars, 3)
248+
249+
// Fill the rest with random characters from all sets
250+
allChars := uppercaseChars + lowercaseChars + numberChars + specialChars
251+
for i := 4; i < passwordLength; i++ {
252+
maxVal := big.NewInt(int64(len(allChars)))
253+
randomIndex, _ := rand.Int(rand.Reader, maxVal)
254+
password[i] = allChars[randomIndex.Int64()]
255+
}
256+
257+
// Shuffle the password to avoid predictable positions of character types
258+
for i := passwordLength - 1; i > 0; i-- {
259+
maxVal := big.NewInt(int64(i + 1))
260+
j, _ := rand.Int(rand.Reader, maxVal)
261+
password[i], password[j.Int64()] = password[j.Int64()], password[i]
262+
}
263+
264+
return string(password)
265+
}
266+
207267
func newUserPrincipalSyncer(ctx context.Context, c *mssqldb.Client) *userPrincipalSyncer {
208268
return &userPrincipalSyncer{
209269
resourceType: resourceTypeUser,

0 commit comments

Comments
 (0)