diff --git a/AzureCP/TEMPLATE/ADMIN/AzureCP/AzureCPGlobalSettings.ascx.cs b/AzureCP/TEMPLATE/ADMIN/AzureCP/AzureCPGlobalSettings.ascx.cs
index 62b71231..a7026f6e 100644
--- a/AzureCP/TEMPLATE/ADMIN/AzureCP/AzureCPGlobalSettings.ascx.cs
+++ b/AzureCP/TEMPLATE/ADMIN/AzureCP/AzureCPGlobalSettings.ascx.cs
@@ -25,6 +25,7 @@ public partial class AzureCPGlobalSettings : AzureCPUserControl
readonly string TextErrorTestAzureADConnection = "Unable to get access token for tenant '{0}': {1}";
readonly string TextConnectionSuccessful = "Connection successful.";
readonly string TextErrorNewTenantCreds = "Specify either a client secret or a client certificate, but not both.";
+ readonly string TextErrorExtensionAttributesApplicationId = "Please specify a valid Client ID for AD Connect.";
protected void Page_Load(object sender, EventArgs e)
{
@@ -59,7 +60,7 @@ void PopulateConnectionsGrid()
PropertyCollectionBinder pcb = new PropertyCollectionBinder();
foreach (AzureTenant tenant in PersistedObject.AzureTenants)
{
- pcb.AddRow(tenant.Identifier, tenant.Name, tenant.ApplicationId, tenant.CloudInstance.ToString());
+ pcb.AddRow(tenant.Identifier, tenant.Name, tenant.ApplicationId, tenant.CloudInstance.ToString(), tenant.ExtensionAttributesApplicationId);
}
pcb.BindGrid(grdAzureTenants);
}
@@ -260,6 +261,20 @@ void AddTenantConnection()
return;
}
+ if (!string.IsNullOrWhiteSpace(this.TxtExtensionAttributesApplicationId.Text))
+ {
+ try
+ {
+ Guid extensionAttributesApplicationId = Guid.Parse(this.TxtExtensionAttributesApplicationId.Text);
+ }
+ catch (Exception)
+ {
+
+ this.LabelErrorTestLdapConnection.Text = TextErrorExtensionAttributesApplicationId;
+ }
+
+ }
+
if ((InputClientCertFile.PostedFile == null && String.IsNullOrWhiteSpace(this.TxtClientSecret.Text)) ||
(InputClientCertFile.PostedFile != null && InputClientCertFile.PostedFile.ContentLength == 0 && String.IsNullOrWhiteSpace(TxtClientSecret.Text)) ||
(InputClientCertFile.PostedFile != null && InputClientCertFile.PostedFile.ContentLength != 0 && !String.IsNullOrWhiteSpace(TxtClientSecret.Text)))
@@ -272,7 +287,9 @@ void AddTenantConnection()
if (String.IsNullOrWhiteSpace(this.TxtClientSecret.Text))
{
if (ValidateUploadedCertFile(InputClientCertFile, this.InputClientCertPassword.Text, out cert) == false)
- { return; }
+ {
+ return;
+ }
}
if (PersistedObject.AzureTenants == null)
@@ -287,7 +304,8 @@ void AddTenantConnection()
ApplicationSecret = this.TxtClientSecret.Text,
ExcludeGuests = this.ChkMemberUserTypeOnly.Checked,
ClientCertificatePrivateKey = cert,
- CloudInstance = (AzureCloudInstance)Enum.Parse(typeof(AzureCloudInstance), this.DDLAzureCloudInstance.SelectedValue)
+ CloudInstance = (AzureCloudInstance)Enum.Parse(typeof(AzureCloudInstance), this.DDLAzureCloudInstance.SelectedValue),
+ ExtensionAttributesApplicationId = string.IsNullOrWhiteSpace(this.TxtExtensionAttributesApplicationId.Text) ? Guid.Empty : Guid.Parse(this.TxtExtensionAttributesApplicationId.Text)
});
CommitChanges();
@@ -298,6 +316,7 @@ void AddTenantConnection()
this.TxtClientId.Text = String.Empty;
this.TxtClientSecret.Text = String.Empty;
this.InputClientCertPassword.Text = String.Empty;
+ this.TxtExtensionAttributesApplicationId.Text = String.Empty;
this.DDLAzureCloudInstance.SelectedValue = AzureCloudInstance.AzurePublic.ToString();
}
@@ -335,15 +354,16 @@ private bool ValidateUploadedCertFile(
{
byte[] buffer = new byte[inputFile.PostedFile.ContentLength];
inputFile.PostedFile.InputStream.Read(buffer, 0, buffer.Length);
- cert = new X509Certificate2(buffer, certificatePassword, X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.Exportable);
- if (cert.HasPrivateKey == false)
+ // The certificate must be exportable so it can be saved in the persisted object
+ cert = AzureTenant.ImportPfxCertificateBlob(buffer, certificatePassword, X509KeyStorageFlags.Exportable);
+ if (cert == null)
{
this.LabelErrorTestLdapConnection.Text = $"Certificate does not contain the private key.";
return false;
}
// Try to export the certificate with its private key to validate that it succeeds
- cert.Export(X509ContentType.Pkcs12, "Yvan");
+ cert.Export(X509ContentType.Pfx, "Yvan");
}
catch (CryptographicException ex)
{
@@ -364,9 +384,10 @@ public PropertyCollectionBinder()
PropertyCollection.Columns.Add("ClientID", typeof(string));
//PropertyCollection.Columns.Add("MemberUserTypeOnly", typeof(bool));
PropertyCollection.Columns.Add("CloudInstance", typeof(string));
+ PropertyCollection.Columns.Add("ExtensionAttributesApplicationId", typeof(Guid));
}
- public void AddRow(Guid Id, string TenantName, string ClientID, string CloudInstance)
+ public void AddRow(Guid Id, string TenantName, string ClientID, string CloudInstance, Guid ExtensionAttributesApplicationId)
{
DataRow newRow = PropertyCollection.Rows.Add();
newRow["Id"] = Id;
@@ -374,6 +395,7 @@ public void AddRow(Guid Id, string TenantName, string ClientID, string CloudInst
newRow["ClientID"] = ClientID;
//newRow["MemberUserTypeOnly"] = MemberUserTypeOnly;
newRow["CloudInstance"] = CloudInstance;
+ newRow["ExtensionAttributesApplicationId"] = ExtensionAttributesApplicationId;
}
public void BindGrid(SPGridView grid)
diff --git a/AzureCP/TEMPLATE/ADMIN/AzureCP/AzureCPGlobalSettings.ascx.designer.cs b/AzureCP/TEMPLATE/ADMIN/AzureCP/AzureCPGlobalSettings.ascx.designer.cs
index c7ba4eb6..cb08e82b 100644
--- a/AzureCP/TEMPLATE/ADMIN/AzureCP/AzureCPGlobalSettings.ascx.designer.cs
+++ b/AzureCP/TEMPLATE/ADMIN/AzureCP/AzureCPGlobalSettings.ascx.designer.cs
@@ -122,6 +122,15 @@ public partial class AzureCPGlobalSettings
///
protected global::Microsoft.SharePoint.WebControls.InputFormCheckBox ChkMemberUserTypeOnly;
+ ///
+ /// TxtExtensionAttributesApplicationId control.
+ ///
+ ///
+ /// Auto-generated field.
+ /// To modify move field declaration from designer file to code-behind file.
+ ///
+ protected global::Microsoft.SharePoint.WebControls.InputFormTextBox TxtExtensionAttributesApplicationId;
+
///
/// BtnTestAzureTenantConnection control.
///
diff --git a/AzureCP/TEMPLATE/ADMIN/AzureCP/ClaimTypesConfig.ascx.cs b/AzureCP/TEMPLATE/ADMIN/AzureCP/ClaimTypesConfig.ascx.cs
index 9763ed40..9608a5d9 100644
--- a/AzureCP/TEMPLATE/ADMIN/AzureCP/ClaimTypesConfig.ascx.cs
+++ b/AzureCP/TEMPLATE/ADMIN/AzureCP/ClaimTypesConfig.ascx.cs
@@ -309,11 +309,17 @@ private void BuildGraphPropertyDDLs(KeyValuePair
azureObje
// Ensure property exists for the current object type
if (azureObject.Value.EntityType == DirectoryObjectType.User)
{
- if (AzureCP.GetPropertyValue(new User(), prop.ToString()) == null) { continue; }
+ if (AzureCP.GetPropertyValue(new User(), prop.ToString()) == null)
+ {
+ continue;
+ }
}
else
{
- if (AzureCP.GetPropertyValue(new Group(), prop.ToString()) == null) { continue; }
+ if (AzureCP.GetPropertyValue(new Group(), prop.ToString()) == null)
+ {
+ continue;
+ }
}
graphPropertySelected = azureObject.Value.DirectoryObjectProperty == prop ? "selected" : String.Empty;
diff --git a/CHANGELOG.md b/CHANGELOG.md
index acda680d..0a0d65a4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Change log for AzureCP
+## AzureCP 21.0
+
+* Fixed "Unsupported or invalid query filter" when AzureCP queries some properties like 'companyName' - (https://github.com/Yvand/AzureCP/pull/172 and https://github.com/Yvand/AzureCP/pull/177)
+* Add support for extension attributes ([#174](https://github.com/Yvand/AzureCP/pull/174))
+* Fix multiple reliability issues when using a certificate to authenticate in Azure AD
+* Fix the properties of the identity claim type not updated (https://github.com/Yvand/AzureCP/pull/171)
+* Switch from Azure DevOps to GitHub Actions to build the project and create the unit tests environments
+
## AzureCP 20.0.20220421.1391 enhancements & bug-fixes - Published in April 21, 2022
* Fix: In claims configurfation page, the values in the list of "PickerEntity metadata" was not populated correctly, which caused an issue with the "Title" (and a few others)
diff --git a/testEnvironments.json b/testEnvironments.json
new file mode 100644
index 00000000..a110b57d
--- /dev/null
+++ b/testEnvironments.json
@@ -0,0 +1,17 @@
+{
+ "version": "1",
+ "environments": [
+ // See https://aka.ms/remotetesting for more details
+ // about how to configure remote environments.
+ //{
+ // "name": "WSL Ubuntu",
+ // "type": "wsl",
+ // "wslDistribution": "Ubuntu"
+ //},
+ //{
+ // "name": "Docker dotnet/sdk",
+ // "type": "docker",
+ // "dockerImage": "mcr.microsoft.com/dotnet/sdk"
+ //}
+ ]
+}
\ No newline at end of file