Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SqlServerDatabaseMail: Added Authentication configuration #1374

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,25 @@
- Can also pipe in 'Microsoft.SqlServer.Management.Smo.Server' object
- Can pipe Connect-SQL | Invoke-Query
- Added default vaules to Invoke-Query
- Changes to SqlServerDatabaseMail
- Added new parameter `EnableSsl` which controls encryption of communication
using Secure Sockets Layer.
- Added new parameter `Authentication` and `SMTPAccount` for configuration of
SMTP authentication mode and credential used [issue #1215](https://github.com/PowerShell/SqlServerDsc/issues/1215).
- Added new helper function `Get-MailServerCredentialId` which gets
credential Id used by mail server.
- Added new helper function `Get-ServiceMasterKey` which gets unencrypted
Service Master Key for specified SQL Instance.
- Added new helper function `Get-SqlPSCredential` which decrypts and returns
PSCredential object of SQL Credential by Id.
- Added DAC switch to function 'Connect-SQL' with default value $false.
Used to specify that non-pooled Dedicated Admin Connection should be
established.
- Added UsingDAC switch to function 'Invoke-Query' with default value $false.
Used to specify that query should be executed using Dedicated Admin
Connection. After execution DAC connection will be closed.
- Added PSCredential option to function 'Test-DscParameterState' which will
compare PSCredential objects using username/password keys.

## 13.0.0.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@
ReplyToAddress = $null
Description = $null
TcpPort = $null
EnableSsl = $null
Authentication = $null
SMTPAccount = $null
}

Write-Verbose -Message (
Expand Down Expand Up @@ -142,6 +145,37 @@

$returnValue['MailServerName'] = $mailServer.Name
$returnValue['TcpPort'] = $mailServer.Port
$returnValue['EnableSsl'] = $mailServer.EnableSsl

<#
When UseDefaultCredentials is True, Database Mail uses the
credentials of the SQL Server Database Engine service. When
this parameter is False, Database Mail uses the **@username**
and **@password** for authentication on the SMTP server.
If **@username** and **@password** are NULL, then Database Mail
uses anonymous authentication.
#>
if ($mailServer.UseDefaultCredentials)
{
$returnValue['Authentication'] = 'Windows'
}
elseif ($mailServer.UserName)
{
$returnValue['Authentication'] = 'Basic'

$credentialId = Get-MailServerCredentialId -SQLServer $ServerName `
-SQLInstanceName $InstanceName `
-MailServerName $mailServer.Name `
-AccountId $databaseMailAccount.ID

$returnValue['SMTPAccount'] = Get-SqlPSCredential -SQLServer $ServerName `
-SQLInstanceName $InstanceName `
-CredentialId $credentialId
}
else
{
$returnValue['Authentication'] = 'Anonymous'
}

# Currently only one profile is handled, so this make sure only the first string (profile name) is returned.
$returnValue['ProfileName'] = $databaseMail.Profiles | Select-Object -First 1 -ExpandProperty Name
Expand Down Expand Up @@ -224,6 +258,15 @@
.PARAMETER TcpPort
The TCP port used for communication. Default value is port 25.

.PARAMETER EnableSsl
Specifies whether to encrypt communication using Secure Sockets Layer or not.

.PARAMETER Authentication
SMTP authentication mode to be used. Default value is 'Anonymous'.

.PARAMETER SMTPAccount
Account used for SMTP authentication if 'Basic' mode was chosen.

.NOTES
Information about the different properties can be found here
https://docs.microsoft.com/en-us/sql/relational-databases/database-mail/configure-database-mail.
Expand Down Expand Up @@ -283,9 +326,29 @@

[Parameter()]
[System.UInt16]
$TcpPort = 25
$TcpPort = 25,

[Parameter()]
[System.Boolean]
$EnableSsl,

[Parameter()]
[ValidateSet('Anonymous', 'Basic', 'Windows')]
[System.String]
$Authentication = 'Anonymous',

[Parameter()]
[System.Management.Automation.PSCredential]
$SMTPAccount
)

if (-not $PSBoundParameters.ContainsKey('SMTPAccount') -and `
$Authentication -eq 'Basic')
{
$errorMessage = $script:localizedData.SMTPAccountMissingParameter
New-InvalidArgumentException -ArgumentName 'SMTPAccount' -Message $errorMessage

Check warning on line 349 in DSCResources/MSFT_SqlServerDatabaseMail/MSFT_SqlServerDatabaseMail.psm1

View check run for this annotation

Codecov / codecov/patch

DSCResources/MSFT_SqlServerDatabaseMail/MSFT_SqlServerDatabaseMail.psm1#L348-L349

Added lines #L348 - L349 were not covered by tests
}

Write-Verbose -Message (
$script:localizedData.ConnectToSqlInstance `
-f $ServerName, $InstanceName
Expand Down Expand Up @@ -372,6 +435,28 @@
$mailServer.Port = $TcpPort
}

if ($PSBoundParameters.ContainsKey('EnableSsl'))
{
$mailServer.EnableSsl = $EnableSsl
}

if ($PSBoundParameters.ContainsKey('Authentication'))
{
# Default Authentication is Anonymous so it's absent in the selection.
switch ($Authentication)
{
'Basic'
{
$mailServer.SetAccount($SMTPAccount.UserName, $SMTPAccount.Password)
}

'Windows'
{
$mailServer.UseDefaultCredentials = $true

Check warning on line 455 in DSCResources/MSFT_SqlServerDatabaseMail/MSFT_SqlServerDatabaseMail.psm1

View check run for this annotation

Codecov / codecov/patch

DSCResources/MSFT_SqlServerDatabaseMail/MSFT_SqlServerDatabaseMail.psm1#L455

Added line #L455 was not covered by tests
}
}
}

$mailServer.Alter()
}
}
Expand Down Expand Up @@ -473,6 +558,118 @@
$mailServer.Port = $TcpPort
$mailServer.Alter()
}

$currentEnableSsl = $mailServer.EnableSsl
if ($currentEnableSsl -ne $EnableSsl)
{
Write-Verbose -Message (
$script:localizedData.UpdatingPropertyOfMailServer -f @(
$currentEnableSsl
$EnableSsl
$script:localizedData.MailServerPropertyEnableSsl
)
)

$mailServer.EnableSsl = $EnableSsl
$mailServer.Alter()
}

# Checking current SMTP Authentication mode and SMTP Account
$currentSMTPAccount = $null
if ($mailServer.UseDefaultCredentials)
{
$currentAuthentication = 'Windows'

Check warning on line 581 in DSCResources/MSFT_SqlServerDatabaseMail/MSFT_SqlServerDatabaseMail.psm1

View check run for this annotation

Codecov / codecov/patch

DSCResources/MSFT_SqlServerDatabaseMail/MSFT_SqlServerDatabaseMail.psm1#L581

Added line #L581 was not covered by tests
}
elseif ($mailServer.UserName)
{
$currentAuthentication = 'Basic'

$credentialId = Get-MailServerCredentialId -SQLServer $ServerName `
-SQLInstanceName $InstanceName `
-MailServerName $MailServerName `
-AccountId $databaseMailAccount.ID

$currentSMTPAccount = Get-SqlPSCredential -SQLServer $ServerName `
-SQLInstanceName $InstanceName `
-CredentialId $credentialId
}
else
{
$currentAuthentication = 'Anonymous'

Check warning on line 598 in DSCResources/MSFT_SqlServerDatabaseMail/MSFT_SqlServerDatabaseMail.psm1

View check run for this annotation

Codecov / codecov/patch

DSCResources/MSFT_SqlServerDatabaseMail/MSFT_SqlServerDatabaseMail.psm1#L598

Added line #L598 was not covered by tests
}

if ($currentAuthentication -ne $Authentication)
{
Write-Verbose -Message (
$script:localizedData.UpdatingPropertyOfMailServer -f @(
$currentAuthentication
$Authentication
$script:localizedData.MailServerPropertyAuthentication
)
)

$mailServer.UseDefaultCredentials = switch ($Authentication)
{
'Windows'
{
$true
}

Default
{
$false

Check warning on line 620 in DSCResources/MSFT_SqlServerDatabaseMail/MSFT_SqlServerDatabaseMail.psm1

View check run for this annotation

Codecov / codecov/patch

DSCResources/MSFT_SqlServerDatabaseMail/MSFT_SqlServerDatabaseMail.psm1#L620

Added line #L620 was not covered by tests
}
}

if ($Authentication -ne 'Basic' -and $currentSMTPAccount.UserName)
{
Write-Verbose -Message (
$script:localizedData.UpdatingPropertyOfMailServer -f @(
$currentSMTPAccount.UserName
''
$script:localizedData.MailServerPropertySMTPAccount
)
)
$mailServer.UserName = ''
}

$mailServer.Alter()
}

if ($Authentication -eq 'Basic')
{
if ($SMTPAccount.UserName -ne $currentSMTPAccount.UserName)
{
Write-Verbose -Message (
$script:localizedData.UpdatingPropertyOfMailServer -f @(
$currentSMTPAccount.UserName
$SMTPAccount.UserName
$script:localizedData.MailServerPropertySMTPAccount
)
)

$mailServer.SetAccount($SMTPAccount.UserName, $SMTPAccount.Password)
}
elseif (([System.String]::IsNullOrEmpty($currentSMTPAccount.Password) -and $SMTPAccount.Password) -or `
([System.String]::IsNullOrEmpty($SMTPAccount.Password) -and $currentSMTPAccount.Password) -or `
($currentSMTPAccount.GetNetworkCredential().Password -ne `
$SMTPAccount.GetNetworkCredential().Password))
{
<#
Message will not include real password values unless password is not set.
This was done on purpose.
#>
Write-Verbose -Message (
$script:localizedData.UpdatingPropertyOfMailServer -f @(
$currentSMTPAccount.Password
$SMTPAccount.Password
$script:localizedData.MailServerPropertySMTPAccountPassword
)
)

$mailServer.SetPassword($SMTPAccount.Password)
}
}
}

$databaseMailProfile = $databaseMail.Profiles | Where-Object -FilterScript {
Expand Down Expand Up @@ -623,6 +820,15 @@

.PARAMETER TcpPort
The TCP port used for communication. Default value is port 25.

.PARAMETER EnableSsl
Specifies whether to encrypt communication using Secure Sockets Layer or not.

.PARAMETER Authentication
SMTP authentication mode to be used. Default value is 'Anonymous'.

.PARAMETER SMTPAccount
Account used for SMTP authentication if 'Basic' mode was chosen.
#>
function Test-TargetResource
{
Expand Down Expand Up @@ -679,7 +885,20 @@

[Parameter()]
[System.UInt16]
$TcpPort = 25
$TcpPort = 25,

[Parameter()]
[System.Boolean]
$EnableSsl,

[Parameter()]
[ValidateSet('Anonymous', 'Basic', 'Windows')]
[System.String]
$Authentication = 'Anonymous',

[Parameter()]
[System.Management.Automation.PSCredential]
$SMTPAccount
)

$getTargetResourceParameters = @{
Expand All @@ -701,10 +920,7 @@

if ($Ensure -eq 'Present')
{
$returnValue = Test-DscParameterState `
-CurrentValues $getTargetResourceResult `
-DesiredValues $PSBoundParameters `
-ValuesToCheck @(
$valuesToCheck = @(
'AccountName'
'EmailAddress'
'MailServerName'
Expand All @@ -715,7 +931,27 @@
'DisplayName'
'Description'
'LoggingLevel'
'EnableSsl'
'Authentication'
)

# If current or desired Authentication is set to 'Basic' we need to include SMTPAccount property
if ('Basic' -in @($Authentication, $getTargetResourceResult.Authentication))
{
$valuesToCheck += 'SMTPAccount'

# Ignore SMTPAccount property value if it was specified with Authentication not set to 'Basic'
if ($Authentication -ne 'Basic' -and $PSBoundParameters.ContainsKey('SMTPAccount'))
{
Write-Warning -Message $script:localizedData.SMTPAccountIgnoringParameter
$PSBoundParameters['SMTPAccount'] = [System.Management.Automation.PSCredential]::Empty
}
}

$returnValue = Test-DscParameterState `
-CurrentValues $getTargetResourceResult `
-DesiredValues $PSBoundParameters `
-ValuesToCheck $valuesToCheck
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ class MSFT_SqlServerDatabaseMail : OMI_BaseResource
[Write, Description("The description for the Database Mail profile and account.")] String Description;
[Write, Description("The logging level that the Database Mail will use. If not specified the default logging level is 'Extended'."), ValueMap{"Normal","Extended","Verbose"}, Values{"Normal","Extended","Verbose"}] String LoggingLevel;
[Write, Description("The TCP port used for communication. Default value is port 25.")] UInt16 TcpPort;
[Write, Description("Specifies whether to encrypt communication using Secure Sockets Layer or not.")] Boolean EnableSsl;
[Write, Description("SMTP authentication mode to be used. Default value is 'Anonymous'."), ValueMap{"Anonymous","Basic","Windows"}, Values{"Anonymous","Basic","Windows"}] String Authentication;
[Write, EmbeddedInstance("MSFT_Credential"), Description("Account used for SMTP authentication if 'Basic' was chosen.")] String SMTPAccount;
};
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ ConvertFrom-StringData @'
MailServerPropertyReplyToEmailAddress = reply to e-mail address
MailServerPropertyServerName = server name
MailServerPropertyTcpPort = TCP port
MailServerPropertyEnableSsl = SSL property
MailServerPropertySMTPAccount = SMTP account
MailServerPropertySMTPAccountPassword = password for SMTP account
MailServerPropertyAuthentication = authentication
CreatingMailProfile = Creating a public default profile '{0}'.
MailProfileExist = The public default profile '{0}' already exist.
ConfigureSqlAgent = Configure the SQL Agent to use Database Mail.
Expand All @@ -30,4 +34,6 @@ ConvertFrom-StringData @'
RemovingSqlAgentConfiguration = Configure the SQL Agent to not use Database Mail (changing it back to SQL Agent Mail).
RemovingMailProfile = Removing the public default profile '{0}'.
RemovingMailAccount = Removing the mail account '{0}'.
SMTPAccountMissingParameter = SMTPAccount parameter must be specified when Authentication is set to 'Basic'.
SMTPAccountIgnoringParameter = SMTPAccount parameter was specified and will be ignored as Authentication was not set to 'Basic'.
'@
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ $ConfigurationData = @{
)
}

Configuration Example
Configuration EnableDatabaseMail
{
param
(
Expand All @@ -35,9 +35,9 @@ Configuration Example
Import-DscResource -ModuleName 'SqlServerDsc'

node localhost {

SqlServerConfiguration 'EnableDatabaseMailXPs'
{

ServerName = $Node.ServerName
InstanceName = $Node.InstanceName
OptionName = 'Database Mail XPs'
Expand Down
Loading