@@ -307,34 +307,87 @@ CREATE USER [%s] FOR LOGIN [%s];
307307 return nil
308308}
309309
310- // CreateWindowsLogin creates a SQL Server login from Windows AD for the specified domain and username.
311- // If domain is provided, it will create the login in the format [DOMAIN\Username],
312- // otherwise it will use just [Username].
313- func (c * Client ) CreateWindowsLogin (ctx context.Context , domain , username string ) error {
310+ // LoginType represents the SQL Server login type.
311+ type LoginType string
312+
313+ const (
314+ // LoginTypeWindows represents Windows authentication.
315+ LoginTypeWindows LoginType = "WINDOWS"
316+ // LoginTypeSQL represents SQL Server authentication.
317+ LoginTypeSQL LoginType = "SQL"
318+ // LoginTypeAzureAD represents Azure AD authentication.
319+ LoginTypeAzureAD LoginType = "AZURE_AD"
320+ // LoginTypeEntraID represents Azure Entra ID authentication.
321+ LoginTypeEntraID LoginType = "ENTRA_ID"
322+ )
323+
324+ // CreateLogin creates a SQL Server login with the specified authentication type.
325+ // For Windows authentication (loginType=WINDOWS):
326+ // - If domain is provided, it will create the login in the format [DOMAIN\Username]
327+ // - otherwise it will use just [Username]
328+ //
329+ // For SQL authentication (loginType=SQL):
330+ // - It requires a password
331+ // - Domain is ignored
332+ //
333+ // For Azure AD authentication (loginType=AZURE_AD):
334+ // - It creates from EXTERNAL PROVIDER
335+ // - Username should be the full Azure AD username/email
336+ //
337+ // For Entra ID authentication (loginType=ENTRA_ID):
338+ // - It creates from EXTERNAL PROVIDER
339+ // - Username should be the full Entra ID username/email
340+ func (c * Client ) CreateLogin (ctx context.Context , loginType LoginType , domain , username , password string ) error {
314341 l := ctxzap .Extract (ctx )
315342
316343 // Check for invalid characters to prevent SQL injection
317344 if (domain != "" && strings .ContainsAny (domain , "[]\" ';" )) || strings .ContainsAny (username , "[]\" ';" ) {
318345 return fmt .Errorf ("invalid characters in domain or username" )
319346 }
320347
321- var loginName string
322- if domain != "" {
323- loginName = fmt .Sprintf ("[%s\\ %s]" , domain , username )
324- l .Debug ("creating windows login with domain" , zap .String ("login" , loginName ))
325- } else {
326- loginName = fmt .Sprintf ("[%s]" , username )
327- l .Debug ("creating windows login without domain" , zap .String ("login" , loginName ))
348+ var query string
349+ switch loginType {
350+ case LoginTypeWindows :
351+ var loginName string
352+ if domain != "" {
353+ loginName = fmt .Sprintf ("[%s\\ %s]" , domain , username )
354+ l .Debug ("creating windows login with domain" , zap .String ("login" , loginName ))
355+ } else {
356+ loginName = fmt .Sprintf ("[%s]" , username )
357+ l .Debug ("creating windows login without domain" , zap .String ("login" , loginName ))
358+ }
359+ query = fmt .Sprintf ("CREATE LOGIN %s FROM WINDOWS;" , loginName )
360+ case LoginTypeSQL :
361+ if password == "" {
362+ return fmt .Errorf ("password is required for SQL Server authentication" )
363+ }
364+ // For SQL Server authentication, only username and password are used
365+ loginName := fmt .Sprintf ("[%s]" , username )
366+ l .Debug ("creating SQL login" , zap .String ("login" , loginName ))
367+ query = fmt .Sprintf ("CREATE LOGIN %s WITH PASSWORD = '%s';" , loginName , password )
368+ case LoginTypeAzureAD , LoginTypeEntraID :
369+ // Azure AD and Entra ID use external provider
370+ loginName := fmt .Sprintf ("[%s]" , username )
371+ l .Debug ("creating external provider login" , zap .String ("login" , loginName ), zap .String ("type" , string (loginType )))
372+ query = fmt .Sprintf ("CREATE LOGIN %s FROM EXTERNAL PROVIDER;" , loginName )
373+ default :
374+ return fmt .Errorf ("unsupported login type: %s" , loginType )
328375 }
329376
330- query := fmt .Sprintf ("CREATE LOGIN %s FROM WINDOWS;" , loginName )
331-
332377 l .Debug ("SQL QUERY" , zap .String ("q" , query ))
333378
334379 _ , err := c .db .ExecContext (ctx , query )
335380 if err != nil {
336- return fmt .Errorf ("failed to create Windows login: %w" , err )
381+ return fmt .Errorf ("failed to create login: %w" , err )
337382 }
338383
339384 return nil
340385}
386+
387+ // CreateWindowsLogin creates a SQL Server login from Windows AD for the specified domain and username.
388+ // If domain is provided, it will create the login in the format [DOMAIN\Username],
389+ // otherwise it will use just [Username].
390+ // This is a convenience method that calls CreateLogin with LoginTypeWindows.
391+ func (c * Client ) CreateWindowsLogin (ctx context.Context , domain , username string ) error {
392+ return c .CreateLogin (ctx , LoginTypeWindows , domain , username , "" )
393+ }
0 commit comments