forked from denisenkom/go-mssqldb
-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into kerberos_auth
- Loading branch information
Showing
21 changed files
with
637 additions
and
304 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// +build !windows | ||
|
||
package mssql | ||
|
||
import ( | ||
"github.com/microsoft/go-mssqldb/integratedauth" | ||
// nolint importing the ntlm package causes it to be registered as an available authentication provider | ||
_ "github.com/microsoft/go-mssqldb/integratedauth/ntlm" | ||
) | ||
|
||
func init() { | ||
// we set the default authentication provider name here, rather than within each imported package, | ||
// to force a known default. Go will order execution of init() calls but it is better to be explicit. | ||
integratedauth.DefaultProviderName = "ntlm" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,18 @@ | ||
// +build windows | ||
|
||
package mssql | ||
|
||
import "github.com/microsoft/go-mssqldb/msdsn" | ||
import ( | ||
"github.com/microsoft/go-mssqldb/integratedauth" | ||
|
||
func getAuthN(user, password, serverSPN, workstation string, _ map[string]interface{}) (auth auth, authOk bool) { | ||
auth, authOk = getAuth(user, password, serverSPN, workstation) | ||
return | ||
} | ||
// nolint importing the ntlm package causes it to be registered as an available authentication provider | ||
_ "github.com/microsoft/go-mssqldb/integratedauth/ntlm" | ||
// nolint importing the winsspi package causes it to be registered as an available authentication provider | ||
_ "github.com/microsoft/go-mssqldb/integratedauth/winsspi" | ||
) | ||
|
||
func getKrbParams(krb msdsn.KerberosConfig) (krbParams map[string]interface{}, err error) { | ||
return | ||
func init() { | ||
// we set the default authentication provider name here, rather than within each imported package, | ||
// to force a known default. Go will order execution of init() calls but it is better to be explicit. | ||
integratedauth.DefaultProviderName = "winsspi" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,128 +1,128 @@ | ||
//go:build go1.18 | ||
// +build go1.18 | ||
|
||
package azuread | ||
|
||
import ( | ||
"testing" | ||
|
||
mssql "github.com/microsoft/go-mssqldb" | ||
"github.com/microsoft/go-mssqldb/msdsn" | ||
) | ||
|
||
func TestValidateParameters(t *testing.T) { | ||
passphrase := "somesecret" | ||
certificatepath := "/user/cert/cert.pfx" | ||
appid := "applicationclientid=someguid" | ||
certprop := "clientcertpath=" + certificatepath | ||
tests := []struct { | ||
name string | ||
dsn string | ||
expected *azureFedAuthConfig | ||
}{ | ||
{ | ||
name: "no fed auth configured", | ||
dsn: "server=someserver", | ||
expected: &azureFedAuthConfig{fedAuthLibrary: mssql.FedAuthLibraryReserved}, | ||
}, | ||
{ | ||
name: "application with cert/key", | ||
dsn: `sqlserver://service-principal-id%40tenant-id:somesecret@someserver.database.windows.net?fedauth=ActiveDirectoryApplication&` + certprop + "&" + appid, | ||
expected: &azureFedAuthConfig{ | ||
fedAuthLibrary: mssql.FedAuthLibraryADAL, | ||
clientID: "service-principal-id", | ||
tenantID: "tenant-id", | ||
certificatePath: certificatepath, | ||
clientSecret: passphrase, | ||
adalWorkflow: mssql.FedAuthADALWorkflowPassword, | ||
fedAuthWorkflow: ActiveDirectoryApplication, | ||
applicationClientID: "someguid", | ||
}, | ||
}, | ||
{ | ||
name: "application with cert/key missing tenant id", | ||
dsn: "server=someserver.database.windows.net;fedauth=ActiveDirectoryApplication;user id=service-principal-id;password=somesecret;" + certprop + ";" + appid, | ||
expected: &azureFedAuthConfig{ | ||
fedAuthLibrary: mssql.FedAuthLibraryADAL, | ||
clientID: "service-principal-id", | ||
certificatePath: certificatepath, | ||
clientSecret: passphrase, | ||
adalWorkflow: mssql.FedAuthADALWorkflowPassword, | ||
fedAuthWorkflow: ActiveDirectoryApplication, | ||
applicationClientID: "someguid", | ||
}, | ||
}, | ||
{ | ||
name: "application with secret", | ||
dsn: "server=someserver.database.windows.net;fedauth=ActiveDirectoryServicePrincipal;user id=service-principal-id@tenant-id;password=somesecret;", | ||
expected: &azureFedAuthConfig{ | ||
clientID: "service-principal-id", | ||
tenantID: "tenant-id", | ||
clientSecret: passphrase, | ||
adalWorkflow: mssql.FedAuthADALWorkflowPassword, | ||
fedAuthWorkflow: ActiveDirectoryServicePrincipal, | ||
}, | ||
}, | ||
{ | ||
name: "user with password", | ||
dsn: "server=someserver.database.windows.net;fedauth=ActiveDirectoryPassword;user id=azure-ad-user@example.com;password=somesecret;" + appid, | ||
expected: &azureFedAuthConfig{ | ||
adalWorkflow: mssql.FedAuthADALWorkflowPassword, | ||
user: "azure-ad-user@example.com", | ||
password: passphrase, | ||
applicationClientID: "someguid", | ||
fedAuthWorkflow: ActiveDirectoryPassword, | ||
}, | ||
}, | ||
{ | ||
name: "managed identity without client id", | ||
dsn: "server=someserver.database.windows.net;fedauth=ActiveDirectoryMSI", | ||
expected: &azureFedAuthConfig{ | ||
adalWorkflow: mssql.FedAuthADALWorkflowMSI, | ||
fedAuthWorkflow: ActiveDirectoryMSI, | ||
}, | ||
}, | ||
{ | ||
name: "managed identity with client id", | ||
dsn: "server=someserver.database.windows.net;fedauth=ActiveDirectoryManagedIdentity;user id=identity-client-id", | ||
expected: &azureFedAuthConfig{ | ||
adalWorkflow: mssql.FedAuthADALWorkflowMSI, | ||
clientID: "identity-client-id", | ||
fedAuthWorkflow: ActiveDirectoryManagedIdentity, | ||
}, | ||
}, | ||
{ | ||
name: "managed identity with resource id", | ||
dsn: "server=someserver.database.windows.net;fedauth=ActiveDirectoryManagedIdentity;resource id=/subscriptions/{guid}/resourceGroups/{resource-group-name}/{resource-provider-namespace}/{resource-type}/{resource-name}", | ||
expected: &azureFedAuthConfig{ | ||
adalWorkflow: mssql.FedAuthADALWorkflowMSI, | ||
resourceID: "/subscriptions/{guid}/resourceGroups/{resource-group-name}/{resource-provider-namespace}/{resource-type}/{resource-name}", | ||
fedAuthWorkflow: ActiveDirectoryManagedIdentity, | ||
}, | ||
}, | ||
} | ||
for _, tst := range tests { | ||
config, err := parse(tst.dsn) | ||
if tst.expected == nil { | ||
if err == nil { | ||
t.Errorf("No error returned when error expected in test case '%s'", tst.name) | ||
} | ||
continue | ||
} | ||
if err != nil { | ||
t.Errorf("Error returned when none expected in test case '%s': %v", tst.name, err) | ||
continue | ||
} | ||
if tst.expected.fedAuthLibrary != mssql.FedAuthLibraryReserved { | ||
if tst.expected.fedAuthLibrary == 0 { | ||
tst.expected.fedAuthLibrary = mssql.FedAuthLibraryADAL | ||
} | ||
} | ||
// mssqlConfig is not idempotent due to pointers in it, plus we aren't testing its correctness here | ||
config.mssqlConfig = msdsn.Config{} | ||
if *config != *tst.expected { | ||
t.Errorf("Captured parameters do not match in test case '%s'. Expected:%+v, Actual:%+v", tst.name, tst.expected, config) | ||
} | ||
} | ||
|
||
} | ||
//go:build go1.18 | ||
// +build go1.18 | ||
|
||
package azuread | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
mssql "github.com/microsoft/go-mssqldb" | ||
"github.com/microsoft/go-mssqldb/msdsn" | ||
) | ||
|
||
func TestValidateParameters(t *testing.T) { | ||
passphrase := "somesecret" | ||
certificatepath := "/user/cert/cert.pfx" | ||
appid := "applicationclientid=someguid" | ||
certprop := "clientcertpath=" + certificatepath | ||
tests := []struct { | ||
name string | ||
dsn string | ||
expected *azureFedAuthConfig | ||
}{ | ||
{ | ||
name: "no fed auth configured", | ||
dsn: "server=someserver", | ||
expected: &azureFedAuthConfig{fedAuthLibrary: mssql.FedAuthLibraryReserved}, | ||
}, | ||
{ | ||
name: "application with cert/key", | ||
dsn: `sqlserver://service-principal-id%40tenant-id:somesecret@someserver.database.windows.net?fedauth=ActiveDirectoryApplication&` + certprop + "&" + appid, | ||
expected: &azureFedAuthConfig{ | ||
fedAuthLibrary: mssql.FedAuthLibraryADAL, | ||
clientID: "service-principal-id", | ||
tenantID: "tenant-id", | ||
certificatePath: certificatepath, | ||
clientSecret: passphrase, | ||
adalWorkflow: mssql.FedAuthADALWorkflowPassword, | ||
fedAuthWorkflow: ActiveDirectoryApplication, | ||
applicationClientID: "someguid", | ||
}, | ||
}, | ||
{ | ||
name: "application with cert/key missing tenant id", | ||
dsn: "server=someserver.database.windows.net;fedauth=ActiveDirectoryApplication;user id=service-principal-id;password=somesecret;" + certprop + ";" + appid, | ||
expected: &azureFedAuthConfig{ | ||
fedAuthLibrary: mssql.FedAuthLibraryADAL, | ||
clientID: "service-principal-id", | ||
certificatePath: certificatepath, | ||
clientSecret: passphrase, | ||
adalWorkflow: mssql.FedAuthADALWorkflowPassword, | ||
fedAuthWorkflow: ActiveDirectoryApplication, | ||
applicationClientID: "someguid", | ||
}, | ||
}, | ||
{ | ||
name: "application with secret", | ||
dsn: "server=someserver.database.windows.net;fedauth=ActiveDirectoryServicePrincipal;user id=service-principal-id@tenant-id;password=somesecret;", | ||
expected: &azureFedAuthConfig{ | ||
clientID: "service-principal-id", | ||
tenantID: "tenant-id", | ||
clientSecret: passphrase, | ||
adalWorkflow: mssql.FedAuthADALWorkflowPassword, | ||
fedAuthWorkflow: ActiveDirectoryServicePrincipal, | ||
}, | ||
}, | ||
{ | ||
name: "user with password", | ||
dsn: "server=someserver.database.windows.net;fedauth=ActiveDirectoryPassword;user id=azure-ad-user@example.com;password=somesecret;" + appid, | ||
expected: &azureFedAuthConfig{ | ||
adalWorkflow: mssql.FedAuthADALWorkflowPassword, | ||
user: "azure-ad-user@example.com", | ||
password: passphrase, | ||
applicationClientID: "someguid", | ||
fedAuthWorkflow: ActiveDirectoryPassword, | ||
}, | ||
}, | ||
{ | ||
name: "managed identity without client id", | ||
dsn: "server=someserver.database.windows.net;fedauth=ActiveDirectoryMSI", | ||
expected: &azureFedAuthConfig{ | ||
adalWorkflow: mssql.FedAuthADALWorkflowMSI, | ||
fedAuthWorkflow: ActiveDirectoryMSI, | ||
}, | ||
}, | ||
{ | ||
name: "managed identity with client id", | ||
dsn: "server=someserver.database.windows.net;fedauth=ActiveDirectoryManagedIdentity;user id=identity-client-id", | ||
expected: &azureFedAuthConfig{ | ||
adalWorkflow: mssql.FedAuthADALWorkflowMSI, | ||
clientID: "identity-client-id", | ||
fedAuthWorkflow: ActiveDirectoryManagedIdentity, | ||
}, | ||
}, | ||
{ | ||
name: "managed identity with resource id", | ||
dsn: "server=someserver.database.windows.net;fedauth=ActiveDirectoryManagedIdentity;resource id=/subscriptions/{guid}/resourceGroups/{resource-group-name}/{resource-provider-namespace}/{resource-type}/{resource-name}", | ||
expected: &azureFedAuthConfig{ | ||
adalWorkflow: mssql.FedAuthADALWorkflowMSI, | ||
resourceID: "/subscriptions/{guid}/resourceGroups/{resource-group-name}/{resource-provider-namespace}/{resource-type}/{resource-name}", | ||
fedAuthWorkflow: ActiveDirectoryManagedIdentity, | ||
}, | ||
}, | ||
} | ||
for _, tst := range tests { | ||
config, err := parse(tst.dsn) | ||
if tst.expected == nil { | ||
if err == nil { | ||
t.Errorf("No error returned when error expected in test case '%s'", tst.name) | ||
} | ||
continue | ||
} | ||
if err != nil { | ||
t.Errorf("Error returned when none expected in test case '%s': %v", tst.name, err) | ||
continue | ||
} | ||
if tst.expected.fedAuthLibrary != mssql.FedAuthLibraryReserved { | ||
if tst.expected.fedAuthLibrary == 0 { | ||
tst.expected.fedAuthLibrary = mssql.FedAuthLibraryADAL | ||
} | ||
} | ||
// mssqlConfig is not idempotent due to pointers in it, plus we aren't testing its correctness here | ||
config.mssqlConfig = msdsn.Config{} | ||
if !reflect.DeepEqual(config, tst.expected) { | ||
t.Errorf("Captured parameters do not match in test case '%s'. Expected:%+v, Actual:%+v", tst.name, tst.expected, config) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package integratedauth | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"github.com/microsoft/go-mssqldb/msdsn" | ||
) | ||
|
||
var ( | ||
providers map[string]Provider | ||
DefaultProviderName string | ||
|
||
ErrProviderCannotBeNil = errors.New("provider cannot be nil") | ||
ErrProviderNameMustBePopulated = errors.New("provider name must be populated") | ||
) | ||
|
||
func init() { | ||
providers = make(map[string]Provider) | ||
} | ||
|
||
// GetIntegratedAuthenticator calls the authProvider specified in the 'authenticator' connection string parameter, if supplied. | ||
// Otherwise fails back to the DefaultProviderName implementation for the platform. | ||
func GetIntegratedAuthenticator(config msdsn.Config) (IntegratedAuthenticator, error) { | ||
authenticatorName, ok := config.Parameters["authenticator"] | ||
if !ok { | ||
provider, err := getProvider(DefaultProviderName) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
p, err := provider.GetIntegratedAuthenticator(config) | ||
// we ignore the error in this case to force a fallback to sqlserver authentication. | ||
// this preserves the original behaviour | ||
if err != nil { | ||
return nil, nil | ||
} | ||
|
||
return p, nil | ||
} | ||
|
||
provider, err := getProvider(authenticatorName) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return provider.GetIntegratedAuthenticator(config) | ||
} | ||
|
||
func getProvider(name string) (Provider, error) { | ||
provider, ok := providers[name] | ||
|
||
if !ok { | ||
return nil, fmt.Errorf("provider %v not found", name) | ||
} | ||
|
||
return provider, nil | ||
} | ||
|
||
// SetIntegratedAuthenticationProvider stores a named authentication provider. It should be called before any connections are created. | ||
func SetIntegratedAuthenticationProvider(providerName string, p Provider) error { | ||
if p == nil { | ||
return ErrProviderCannotBeNil | ||
} | ||
|
||
if providerName == "" { | ||
return ErrProviderNameMustBePopulated | ||
} | ||
|
||
providers[providerName] = p | ||
|
||
return nil | ||
} |
Oops, something went wrong.