From b03dcf1e77ab09e4ca5fd0ee9811232de1b5cf8b Mon Sep 17 00:00:00 2001 From: Amol Agarwal Date: Fri, 15 May 2020 16:03:14 -0700 Subject: [PATCH 1/4] Allow Azure Active Directory applications to be set as SQL Server Azure Active Directory admin. --- src/Sql/Sql/ChangeLog.md | 1 + src/Sql/Sql/Properties/Resources.Designer.cs | 29 ++++++++- src/Sql/Sql/Properties/Resources.resx | 11 +++- ...rverActiveDirectoryAdministratorAdapter.cs | 62 +++++++++++++++++-- 4 files changed, 97 insertions(+), 6 deletions(-) diff --git a/src/Sql/Sql/ChangeLog.md b/src/Sql/Sql/ChangeLog.md index 3423013a399d..f694251715cb 100644 --- a/src/Sql/Sql/ChangeLog.md +++ b/src/Sql/Sql/ChangeLog.md @@ -29,6 +29,7 @@ - `Disable-AzSqlInstanceDatabaseSensitivityRecommendation` * Removed client-side validation of 'RetentionDays' parameter from cmdlet `Set-AzSqlDatabaseBackupShortTermRetentionPolicy` * Auditing to a storage account in Vnet, fixing a bug when creating a Storage Blob Data Contributor role. +* Allow Azure Active Directory applications to be set as SQL Server Azure Active Directory admin. ## Version 2.6.0 * Added cmdlets `Get-AzSqlInstanceOperation` and `Stop-AzSqlInstanceOperation` diff --git a/src/Sql/Sql/Properties/Resources.Designer.cs b/src/Sql/Sql/Properties/Resources.Designer.cs index 20786e1127aa..fc40503d5aa4 100644 --- a/src/Sql/Sql/Properties/Resources.Designer.cs +++ b/src/Sql/Sql/Properties/Resources.Designer.cs @@ -60,6 +60,24 @@ internal Resources() { } } + /// + /// Looks up a localized string similar to Azure Active Directory application with the display name '{0}' was found. Display Name provided does not match with application display name '{1}'. Please provide right display name that names with display name of the application. To get the application id use Get-AzADApplication -SearchString "{0}" or Get-AzADApplication -SearchString "{1}".. + /// + internal static string ADApplicationDisplayNameMismatch { + get { + return ResourceManager.GetString("ADApplicationDisplayNameMismatch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to More than one Azure Active Directory application with the display name '{0}' was found. Please provide an Azure Active Directory application id of the application to select the correct application. To get the application id use Get-AzADApplication -SearchString "{0}". + /// + internal static string ADApplicationMoreThanOneFound { + get { + return ResourceManager.GetString("ADApplicationMoreThanOneFound", resourceCulture); + } + } + /// /// Looks up a localized string similar to Adding Storage Blob Data Contributor role for storage account {0} is forbidden. /// @@ -69,6 +87,15 @@ internal static string AddingStorageBlobDataContributorRoleForStorageAccountIsFo } } + /// + /// Looks up a localized string similar to Azure Active Directory application and group with same display name '{0}' was found. Please provide an Azure Active Directory application id of the application or object id of the group to select the correct application. To get the application id use Get-AzADApplication -SearchString "{0}" or to get object id use Get-AzADGroup -SearchString "{0}".. + /// + internal static string ADDuplicateGroupAndApplicationFound { + get { + return ResourceManager.GetString("ADDuplicateGroupAndApplicationFound", resourceCulture); + } + } + /// /// Looks up a localized string similar to More than one Active Directory group with the display name '{0}' was found. Please provide an Azure Active Directory object id to select the correct group. To get the object id use Get-AzADGroup -SearchString "{0}". /// @@ -79,7 +106,7 @@ internal static string ADGroupMoreThanOneFound { } /// - /// Looks up a localized string similar to Cannot find the Azure Active Directory object '{0}'. Please make sure that the user or group you are authorizing is registered in the current subscription's Azure Active directory. To get a list of Azure Active Directory groups use Get-AzADGroup, or to get a list of Azure Active Directory users use Get-AzADUser.. + /// Looks up a localized string similar to Cannot find the Azure Active Directory object '{0}'. Please make sure that the user or group or application you are authorizing is registered in the current subscription's Azure Active directory. To get a list of Azure Active Directory groups use Get-AzADGroup, or to get a list of Azure Active Directory users use Get-AzADUser or to get a list of Azure Active Directory applications use Get-AzADApplication.. /// internal static string ADObjectNotFound { get { diff --git a/src/Sql/Sql/Properties/Resources.resx b/src/Sql/Sql/Properties/Resources.resx index 82c753b04ee6..a115f7681c2d 100644 --- a/src/Sql/Sql/Properties/Resources.resx +++ b/src/Sql/Sql/Properties/Resources.resx @@ -121,11 +121,20 @@ More than one Active Directory group with the display name '{0}' was found. Please provide an Azure Active Directory object id to select the correct group. To get the object id use Get-AzADGroup -SearchString "{0}" - Cannot find the Azure Active Directory object '{0}'. Please make sure that the user or group you are authorizing is registered in the current subscription's Azure Active directory. To get a list of Azure Active Directory groups use Get-AzADGroup, or to get a list of Azure Active Directory users use Get-AzADUser. + Cannot find the Azure Active Directory object '{0}'. Please make sure that the user or group or application you are authorizing is registered in the current subscription's Azure Active directory. To get a list of Azure Active Directory groups use Get-AzADGroup, or to get a list of Azure Active Directory users use Get-AzADUser or to get a list of Azure Active Directory applications use Get-AzADApplication. More than one Azure Active Directory user with the display name '{0}' was found. Please provide an Azure Active Directory object id to select the correct user. To get the object id use Get-AzADUser -SearchString "{0}" + + More than one Azure Active Directory application with the display name '{0}' was found. Please provide an Azure Active Directory application id of the application to select the correct application. To get the application id use Get-AzADApplication -SearchString "{0}" + + + Azure Active Directory application with the display name '{0}' was found. Display Name provided does not match with application display name '{1}'. Please provide right display name that names with display name of the application. To get the application id use Get-AzADApplication -SearchString "{0}" or Get-AzADApplication -SearchString "{1}". + + + Azure Active Directory application and group with same display name '{0}' was found. Please provide an Azure Active Directory application id of the application or object id of the group to select the correct application. To get the application id use Get-AzADApplication -SearchString "{0}" or to get object id use Get-AzADGroup -SearchString "{0}". + Database with name: '{0}' already exists in server '{1}'. diff --git a/src/Sql/Sql/ServerActiveDirectoryAdministrator/Services/AzureSqlServerActiveDirectoryAdministratorAdapter.cs b/src/Sql/Sql/ServerActiveDirectoryAdministrator/Services/AzureSqlServerActiveDirectoryAdministratorAdapter.cs index d3dafde0de59..c0beba0e34e7 100644 --- a/src/Sql/Sql/ServerActiveDirectoryAdministrator/Services/AzureSqlServerActiveDirectoryAdministratorAdapter.cs +++ b/src/Sql/Sql/ServerActiveDirectoryAdministrator/Services/AzureSqlServerActiveDirectoryAdministratorAdapter.cs @@ -16,6 +16,8 @@ using Microsoft.Azure.Commands.Sql.ServerActiveDirectoryAdministrator.Model; using Microsoft.Azure.Management.Sql.Models; using Microsoft.Azure.Graph.RBAC.Version1_6.ActiveDirectory; +using Microsoft.Azure.Graph.RBAC.Version1_6.Models; +using Microsoft.Rest.Azure.OData; using System; using System.Collections.Generic; using System.Linq; @@ -178,8 +180,9 @@ protected ServerAzureADAdministrator GetActiveDirectoryInformation(string displa // Check for a Azure Active Directory group. Recommended to always use group. IEnumerable groupList = null; + PSADGroup group = null; - var filter = new ADObjectFilterOptions() + var filter = new ADObjectFilterOptions() { Id = (objectId != null && objectId != Guid.Empty) ? objectId.ToString() : null, SearchString = displayName, @@ -197,15 +200,66 @@ protected ServerAzureADAdministrator GetActiveDirectoryInformation(string displa else if (groupList.Count() == 1) { // Only one group was found. Get the group display name and object id - var group = groupList.First(); + group = groupList.First(); // Only support Security Groups if (group.SecurityEnabled.HasValue && !group.SecurityEnabled.Value) { throw new ArgumentException(string.Format(Microsoft.Azure.Commands.Sql.Properties.Resources.InvalidADGroupNotSecurity, displayName)); } + } + + // Lookup for applications + ODataQuery odataQueryFilter; + + if ((objectId != null && objectId != Guid.Empty)) + { + var applicationIdString = objectId.ToString(); + odataQueryFilter = new Rest.Azure.OData.ODataQuery(a => a.AppId == applicationIdString); + } + else + { + odataQueryFilter = new Rest.Azure.OData.ODataQuery(a => a.DisplayName == displayName); + } + var applicationList = ActiveDirectoryClient.GetApplicationWithFilters(odataQueryFilter); + + // No application was found + if (applicationList == null || applicationList.Count() == 0) + { + throw new ArgumentException(string.Format(Microsoft.Azure.Commands.Sql.Properties.Resources.ADObjectNotFound, displayName)); + } + else if (applicationList.Count() > 1) + { + // More than one application was found. + throw new ArgumentException(string.Format(Microsoft.Azure.Commands.Sql.Properties.Resources.ADApplicationMoreThanOneFound, displayName)); + } + else if (applicationList.Count() == 1) + { + // Only one user was found. Get the user display name and object id + PSADApplication app = applicationList.First(); + if (displayName != null && string.CompareOrdinal(displayName, app.DisplayName) != 0) + { + throw new ArgumentException(string.Format(Microsoft.Azure.Commands.Sql.Properties.Resources.ADApplicationDisplayNameMismatch, displayName, app.DisplayName)); + } + + if (group != null) + { + throw new ArgumentException(string.Format(Microsoft.Azure.Commands.Sql.Properties.Resources.ADDuplicateGroupAndApplicationFound, displayName)); + } + + return new ServerAzureADAdministrator() + { + Login = displayName, + Sid = app.ApplicationId, + TenantId = tenantId, + AzureADOnlyAuthentication = isAzureADOnlyAuthentication, + }; + } + + if (group != null) + { return new ServerAzureADAdministrator() { Login = group.DisplayName, @@ -215,7 +269,7 @@ protected ServerAzureADAdministrator GetActiveDirectoryInformation(string displa }; } - // No group was found. Check for a user + // No group or application was found. Check for a user filter = new ADObjectFilterOptions() { Id = (objectId != null && objectId != Guid.Empty) ? objectId.ToString() : null, @@ -284,4 +338,4 @@ protected Guid GetTenantId() return tenantIdGuid; } } -} +} \ No newline at end of file From 57d7bee547357874adcdc3f36c83a5d7afc7fb3e Mon Sep 17 00:00:00 2001 From: Amol Agarwal Date: Thu, 21 May 2020 00:49:41 -0700 Subject: [PATCH 2/4] Remove IsAzureADOnlyAuthenticaion option from SetAzureSqlServerActiveDirectoryAdministrator command. We will be adding a new API to enable this option. --- ...reSqlServerActiveDirectoryAdministrator.cs | 13 +----------- ...rverActiveDirectoryAdministratorAdapter.cs | 14 +++++-------- ...AzSqlServerActiveDirectoryAdministrator.md | 21 +++---------------- 3 files changed, 9 insertions(+), 39 deletions(-) diff --git a/src/Sql/Sql/ServerActiveDirectoryAdministrator/Cmdlet/SetAzureSqlServerActiveDirectoryAdministrator.cs b/src/Sql/Sql/ServerActiveDirectoryAdministrator/Cmdlet/SetAzureSqlServerActiveDirectoryAdministrator.cs index 764d591d2238..3a196df3ee1f 100644 --- a/src/Sql/Sql/ServerActiveDirectoryAdministrator/Cmdlet/SetAzureSqlServerActiveDirectoryAdministrator.cs +++ b/src/Sql/Sql/ServerActiveDirectoryAdministrator/Cmdlet/SetAzureSqlServerActiveDirectoryAdministrator.cs @@ -46,16 +46,6 @@ public class SetAzureSqlServerActiveDirectoryAdministrator : AzureSqlServerActiv [ValidateNotNullOrEmpty()] public Guid ObjectId { get; set; } - /// - /// Only Azure Active Directory authentication allowed - /// - [Parameter(Mandatory = false, - ValueFromPipelineByPropertyName = true, - Position = 4, - HelpMessage = "Specifies if only Azure Active Directory authentication is allowed.")] - [Alias("IsAzureOnlyAuthentication")] - public bool? IsAzureADOnlyAuthentication { get; set; } - /// /// Get the entities from the service /// @@ -107,8 +97,7 @@ protected override IEnumerable ResourceGroupName = ResourceGroupName, ServerName = ServerName, DisplayName = DisplayName, - ObjectId = ObjectId, - IsAzureADOnlyAuthentication = IsAzureADOnlyAuthentication, + ObjectId = ObjectId }); return newEntity; } diff --git a/src/Sql/Sql/ServerActiveDirectoryAdministrator/Services/AzureSqlServerActiveDirectoryAdministratorAdapter.cs b/src/Sql/Sql/ServerActiveDirectoryAdministrator/Services/AzureSqlServerActiveDirectoryAdministratorAdapter.cs index c0beba0e34e7..c302f02bd363 100644 --- a/src/Sql/Sql/ServerActiveDirectoryAdministrator/Services/AzureSqlServerActiveDirectoryAdministratorAdapter.cs +++ b/src/Sql/Sql/ServerActiveDirectoryAdministrator/Services/AzureSqlServerActiveDirectoryAdministratorAdapter.cs @@ -114,7 +114,7 @@ internal ICollection ListServer /// The upserted Azure SQL Server Active Directory administrator internal AzureSqlServerActiveDirectoryAdministratorModel UpsertServerActiveDirectoryAdministrator(string resourceGroup, string serverName, AzureSqlServerActiveDirectoryAdministratorModel model) { - var resp = Communicator.CreateOrUpdate(resourceGroup, serverName, GetActiveDirectoryInformation(model.DisplayName, model.ObjectId, model.IsAzureADOnlyAuthentication)); + var resp = Communicator.CreateOrUpdate(resourceGroup, serverName, GetActiveDirectoryInformation(model.DisplayName, model.ObjectId)); return CreateServerActiveDirectoryAdministratorModelFromResponse(resourceGroup, serverName, resp); } @@ -171,9 +171,8 @@ public static AzureSqlServerActiveDirectoryAdministratorModel CreateServerActive /// /// Azure Active Directory user or group display name /// Azure Active Directory user or group object id - /// Allow only Azure Active Directory authentication /// - protected ServerAzureADAdministrator GetActiveDirectoryInformation(string displayName, Guid objectId, bool? isAzureADOnlyAuthentication) + protected ServerAzureADAdministrator GetActiveDirectoryInformation(string displayName, Guid objectId) { // Gets the default Tenant id for the subscriptions Guid tenantId = GetTenantId(); @@ -253,8 +252,7 @@ protected ServerAzureADAdministrator GetActiveDirectoryInformation(string displa { Login = displayName, Sid = app.ApplicationId, - TenantId = tenantId, - AzureADOnlyAuthentication = isAzureADOnlyAuthentication, + TenantId = tenantId }; } @@ -264,8 +262,7 @@ protected ServerAzureADAdministrator GetActiveDirectoryInformation(string displa { Login = group.DisplayName, Sid = group.Id, - TenantId = tenantId, - AzureADOnlyAuthentication = isAzureADOnlyAuthentication, + TenantId = tenantId }; } @@ -313,8 +310,7 @@ protected ServerAzureADAdministrator GetActiveDirectoryInformation(string displa { Login = displayName, Sid = obj.Id, - TenantId = tenantId, - AzureADOnlyAuthentication = isAzureADOnlyAuthentication, + TenantId = tenantId }; } } diff --git a/src/Sql/Sql/help/Set-AzSqlServerActiveDirectoryAdministrator.md b/src/Sql/Sql/help/Set-AzSqlServerActiveDirectoryAdministrator.md index 4c2590e17338..70a1a15b93b4 100644 --- a/src/Sql/Sql/help/Set-AzSqlServerActiveDirectoryAdministrator.md +++ b/src/Sql/Sql/help/Set-AzSqlServerActiveDirectoryAdministrator.md @@ -14,9 +14,9 @@ Provisions an Azure AD administrator for SQL Server. ## SYNTAX ``` -Set-AzSqlServerActiveDirectoryAdministrator [-DisplayName] [[-ObjectId] ] - [[-IsAzureADOnlyAuthentication] ] [-ServerName] [-ResourceGroupName] - [-DefaultProfile ] [-WhatIf] [-Confirm] [] +Set-AzSqlServerActiveDirectoryAdministrator [-DisplayName] [[-ObjectId] ] [-ServerName] + [-ResourceGroupName] [-DefaultProfile ] [-WhatIf] [-Confirm] + [] ``` ## DESCRIPTION @@ -98,21 +98,6 @@ Accept pipeline input: True (ByPropertyName) Accept wildcard characters: False ``` -### -IsAzureADOnlyAuthentication -Specifies if only Azure Active Directory authentication is allowed. - -```yaml -Type: System.Nullable`1[System.Boolean] -Parameter Sets: (All) -Aliases: - -Required: False -Position: 4 -Default value: None -Accept pipeline input: True (ByPropertyName) -Accept wildcard characters: False -``` - ### -ObjectId Specifies the unique ID of the Azure AD administrator that this cmdlet provisions. If the display name is not unique, you must specify a value for this parameter. From e843064d92edb4d5c1a9155efb08f2566e68b286 Mon Sep 17 00:00:00 2001 From: Amol Agarwal Date: Thu, 21 May 2020 01:01:38 -0700 Subject: [PATCH 3/4] Update ChangeLog.md --- src/Sql/Sql/ChangeLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Sql/Sql/ChangeLog.md b/src/Sql/Sql/ChangeLog.md index 6436ac3f2bd3..1b4beb798b4c 100644 --- a/src/Sql/Sql/ChangeLog.md +++ b/src/Sql/Sql/ChangeLog.md @@ -20,6 +20,7 @@ ## Upcoming Release * Added UsePrivateLinkConnection to `New-AzSqlSyncGroup`, `Update-AzSqlSyncGroup`, `New-AzSqlSyncMember` and `Update-AzSqlSyncMember` * Added SyncMemberAzureDatabaseResourceId to `New-AzSqlSyncMember` and `Update-AzSqlSyncMember` +* Remove IsAzureADOnlyAuthentication parameter from Set-AzSqlServerActiveDirectoryAdministrator as it is not usable. ## Version 2.6.1 * Enhance performance of: From 8257a8ee12a78b32c50214adc7c46a2d5034596b Mon Sep 17 00:00:00 2001 From: Amol Agarwal Date: Tue, 26 May 2020 09:04:06 -0700 Subject: [PATCH 4/4] Add Static analysis exception to exceptions file. --- .../StaticAnalysis/Exceptions/Az.Sql/BreakingChangeIssues.csv | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tools/StaticAnalysis/Exceptions/Az.Sql/BreakingChangeIssues.csv diff --git a/tools/StaticAnalysis/Exceptions/Az.Sql/BreakingChangeIssues.csv b/tools/StaticAnalysis/Exceptions/Az.Sql/BreakingChangeIssues.csv new file mode 100644 index 000000000000..f85231ecb1ee --- /dev/null +++ b/tools/StaticAnalysis/Exceptions/Az.Sql/BreakingChangeIssues.csv @@ -0,0 +1,3 @@ +"AssemblyFileName","ClassName","Target","Severity","ProblemId","Description","Remediation" +"Microsoft.Azure.PowerShell.Cmdlets.Sql.dll","Microsoft.Azure.Commands.Sql.ServerActiveDirectoryAdministrator.Cmdlet.SetAzureSqlServerActiveDirectoryAdministrator","Set-AzSqlServerActiveDirectoryAdministrator","0","2000","The cmdlet 'Set-AzSqlServerActiveDirectoryAdministrator' no longer supports the parameter 'IsAzureADOnlyAuthentication' and no alias was found for the original parameter name.","Add the parameter 'IsAzureADOnlyAuthentication' back to the cmdlet 'Set-AzSqlServerActiveDirectoryAdministrator', or add an alias to the original parameter name." +"Microsoft.Azure.PowerShell.Cmdlets.Sql.dll","Microsoft.Azure.Commands.Sql.ServerActiveDirectoryAdministrator.Cmdlet.SetAzureSqlServerActiveDirectoryAdministrator","Set-AzSqlServerActiveDirectoryAdministrator","0","1050","The parameter set '__AllParameterSets' for cmdlet 'Set-AzSqlServerActiveDirectoryAdministrator' has been removed.","Add parameter set '__AllParameterSets' back to cmdlet 'Set-AzSqlServerActiveDirectoryAdministrator'."