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

Update global config page to allow updating credentials of existing tenants #248

Merged
merged 7 commits into from
Apr 18, 2024
Merged
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

* Update the global configuration page to give the possibility to update the credentials of tenants already registered - https://github.com/Yvand/EntraCP/pull/248
* Fix an issue where tenant credentials could not be changed from a client certificate to a client secret - https://github.com/Yvand/EntraCP/pull/248
* Prompt user for confirmation before actually deleting a tenant - https://github.com/Yvand/EntraCP/pull/248
* New feature: It is now possible to configure EntraCP, to return only users that are members of some Entra groups, configured by the administrator - https://github.com/Yvand/EntraCP/pull/243
* Fix the connection to Microsoft Graph not working when the tenant is hosted in a national cloud

Expand Down
99 changes: 61 additions & 38 deletions Yvand.EntraCP/TEMPLATE/ADMIN/EntraCP/GlobalSettings.ascx
Original file line number Diff line number Diff line change
Expand Up @@ -134,39 +134,62 @@
</table>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<wssuc:ButtonSection runat="server">
<template_buttons>
<Template_Buttons>
<asp:Button UseSubmitBehavior="false" runat="server" class="ms-ButtonHeightWidth" OnClick="BtnOK_Click" Text="<%$Resources:wss,multipages_okbutton_text%>" ID="BtnOKTop" AccessKey="<%$Resources:wss,okbutton_accesskey%>" />
</template_buttons>
</Template_Buttons>
</wssuc:ButtonSection>
<wssuc:InputFormSection Title="Registered Microsoft Entra ID tenants" runat="server">
<template_description>
<Template_Description>
<wssawc:EncodedLiteral runat="server" Text="Microsoft Entra ID tenants currently registered in EntraCP configuration." EncodeMethod='HtmlEncodeAllowSimpleTextFormatting' />
<br />
<br />
<wssawc:EncodedLiteral runat="server" Text="<a href='https://entracp.yvand.net/docs/configure-the-credentials/' target='_blank'>Read this article</a> to find how to update the credentials on a tenant already registered." EncodeMethod='NoEncode' />
</template_description>
<template_inputformcontrols>
</Template_Description>
<Template_InputFormControls>
<tr>
<td>
<wssawc:SPGridView runat="server" ID="grdAzureTenants" AutoGenerateColumns="false" OnRowDeleting="grdAzureTenants_RowDeleting">
<wssawc:SPGridView runat="server" ID="grdAzureTenants" AutoGenerateColumns="false" OnRowDeleting="grdAzureTenants_RowDeleting" OnRowEditing="grdAzureTenants_RowEditing" OnRowCancelingEdit="grdAzureTenants_RowCancelingEdit" OnRowUpdating="grdAzureTenants_RowUpdating" OnRowDataBound="grdAzureTenants_RowDataBound">
<Columns>
<asp:BoundField DataField="Id" ItemStyle-CssClass="Entracp-HideCol" HeaderStyle-CssClass="Entracp-HideCol" />
<asp:BoundField HeaderText="Tenant" DataField="TenantName" />
<asp:BoundField HeaderText="Application ID" DataField="ClientID" />
<asp:BoundField HeaderText="Authentication mode" DataField="AuthenticationMode" />
<asp:BoundField HeaderText="Extension Attributes Application ID" DataField="ExtensionAttributesApplicationId" />
<asp:CommandField HeaderText="Action" ButtonType="Button" DeleteText="Remove" ShowDeleteButton="True" />
<asp:TemplateField HeaderText="Tenant name">
<ItemTemplate>
<asp:Label ID="grdAzureTenants_TenantNameLbl" runat="server" Text='<%# Bind("TenantName") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:Label ID="grdAzureTenants_TenantNameLbl" runat="server" Text='<%# Bind("TenantName") %>'></asp:Label>
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Client ID">
<ItemTemplate>
<asp:Label ID="grdAzureTenants_TenantClientIdLbl" runat="server" Text='<%# Bind("ClientID") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:Label runat="server" Text="New client ID:"></asp:Label><br />
<asp:TextBox ID="EditTenantNewClientID" runat="server" Text='<%# Bind("ClientID") %>' />
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Credential">
<ItemTemplate>
<asp:Label ID="grdAzureTenants_AuthenticationModeLbl" runat="server" Text='<%# Bind("AuthenticationMode") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:Label runat="server" Text="New secret &#9432;:" ToolTip="Leave blank to keep the current secret or certificate"></asp:Label><br />
<asp:TextBox ID="EditTenantNewSecret" runat="server" ToolTip="New secret, or leave blank to keep the current secret or certificate" />
</EditItemTemplate>
</asp:TemplateField>
<%--<asp:BoundField HeaderText="Extension Attributes Application ID" DataField="ExtensionAttributesApplicationId" />--%>
<asp:CommandField HeaderText="Action" ButtonType="Button" ShowDeleteButton="True" DeleteText="Delete" ShowEditButton="true" EditText="Edit" />
</Columns>
</wssawc:SPGridView>
</td>
</tr>
</template_inputformcontrols>
</Template_InputFormControls>
</wssuc:InputFormSection>
<wssuc:InputFormSection Title="Register a new Microsoft Entra ID tenant" runat="server">
<template_description>
<Template_Description>
<wssawc:EncodedLiteral runat="server" Text="<p>EntraCP needs its own app registration to connect to your Microsoft Entra ID tenant, with permissions 'GroupMember.Read.All' and 'User.Read.All'.<br /><br />Read <a href='https://entracp.yvand.net/overview/register-application/' target='_blank'>this article</a> to find how to register the app in your tenant.<br /><br />EntraCP can authenticate using <a href='https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow#get-a-token' target='_blank'>either a secret or a certificate</a>.</p>" EncodeMethod='NoEncode' />
</template_description>
<template_inputformcontrols>
</Template_Description>
<Template_InputFormControls>
<tr>
<td>
<div class="divfieldset">
Expand Down Expand Up @@ -223,10 +246,10 @@
</div>
</td>
</tr>
</template_inputformcontrols>
</Template_InputFormControls>
</wssuc:InputFormSection>
<wssuc:InputFormSection runat="server" Title="Configuration for the user identifier">
<template_description>
<Template_Description>
<sharepoint:encodedliteral runat="server" text="Specify the settings to search, create and display the permissions for users." encodemethod='HtmlEncodeAllowSimpleTextFormatting' />
<br />
<br />
Expand All @@ -239,8 +262,8 @@
<sharepoint:encodedliteral runat="server" text="- For guests:" encodemethod='HtmlEncodeAllowSimpleTextFormatting' />
<br />
<b><span><%= UserIdentifierEncodedValuePrefix %><span id="lblGuestPermissionValuePreview"></span></span></b>
</template_description>
<template_inputformcontrols>
</Template_Description>
<Template_InputFormControls>
<tr>
<td colspan="2">
<div class="divfieldset">
Expand Down Expand Up @@ -269,11 +292,11 @@
</div>
</td>
</tr>
</template_inputformcontrols>
</Template_InputFormControls>
</wssuc:InputFormSection>

<wssuc:InputFormSection runat="server" Title="Configuration for the group identifier">
<template_description>
<Template_Description>
<sharepoint:encodedliteral runat="server" text="Specify the settings to search, create and display the permissions for groups." encodemethod='HtmlEncodeAllowSimpleTextFormatting' />
<br />
<br />
Expand All @@ -283,8 +306,8 @@
<br />
<br />
<sharepoint:encodedliteral runat="server" text="- Augmentation: If enabled, EntraCP gets the group membership of the users when they sign-in, or whenever SharePoint asks for it. If not enabled, permissions granted to Microsoft Entra ID groups may not work." encodemethod='HtmlEncodeAllowSimpleTextFormatting' />
</template_description>
<template_inputformcontrols>
</Template_Description>
<Template_InputFormControls>
<tr>
<td colspan="2">
<div class="divfieldset">
Expand Down Expand Up @@ -319,11 +342,11 @@
</div>
</td>
</tr>
</template_inputformcontrols>
</Template_InputFormControls>
</wssuc:InputFormSection>

<wssuc:InputFormSection runat="server" Title="Bypass Entra ID">
<template_description>
<Template_Description>
<sharepoint:encodedliteral runat="server" text="Bypass the Entra ID tenant(s) registered and, depending on the context:" encodemethod='HtmlEncodeAllowSimpleTextFormatting' />
<br />
<sharepoint:encodedliteral runat="server" text="- Search: Uses the input as the claim's value, and return 1 entity per claim type." encodemethod='HtmlEncodeAllowSimpleTextFormatting' />
Expand All @@ -334,37 +357,37 @@
<br />
<br />
<sharepoint:encodedliteral runat="server" text="It can be used as a mitigation if one or more SharePoint server(s) lost the connection with your Entra ID tenant(s), until it is restored." encodemethod='HtmlEncodeAllowSimpleTextFormatting' />
</template_description>
<template_inputformcontrols>
</Template_Description>
<Template_InputFormControls>
<asp:CheckBox runat="server" Name="ChkAlwaysResolveUserInput" ID="ChkAlwaysResolveUserInput" Text="Bypass the Entra ID tenant(s) registered" />
</template_inputformcontrols>
</Template_InputFormControls>
</wssuc:InputFormSection>
<wssuc:InputFormSection runat="server" Title="Require exact match" Description="Enable this to return only results that match exactly the user input (case-insensitive).">
<template_inputformcontrols>
<Template_InputFormControls>
<asp:CheckBox runat="server" Name="ChkFilterExactMatchOnly" ID="ChkFilterExactMatchOnly" Text="Require exact match when typing in the people picker" />
</template_inputformcontrols>
</Template_InputFormControls>
</wssuc:InputFormSection>

<wssuc:InputFormSection runat="server" Title="Proxy">
<template_description>
<Template_Description>
<wssawc:EncodedLiteral runat="server" Text="Configure the proxy if it is needed for EntraCP to connect to Microsoft Graph." EncodeMethod='HtmlEncodeAllowSimpleTextFormatting' />
<br />
<br />
<wssawc:EncodedLiteral runat="server" Text="Additional configuration in Windows may still be required. Read <a href='https://entracp.yvand.net/docs/configure-the-proxy/' target='_blank'>this article</a> to fully configure the proxy." EncodeMethod='NoEncode' />
</template_description>
<template_inputformcontrols>
</Template_Description>
<Template_InputFormControls>
<label for="<%= InputProxyAddress.ClientID %>">Proxy address:</label><br />
<wssawc:InputFormTextBox title="Proxy address" class="ms-input" ID="InputProxyAddress" Columns="50" runat="server" />
</template_inputformcontrols>
</Template_InputFormControls>
</wssuc:InputFormSection>
<wssuc:InputFormSection runat="server" Title="Reset EntraCP configuration" Description="Restore configuration to its default values. All changes, including in claim types mappings, will be lost.">
<template_inputformcontrols>
<Template_InputFormControls>
<asp:Button runat="server" ID="BtnResetConfig" Text="Reset EntraCP configuration" OnClick="BtnResetConfig_Click" class="ms-ButtonHeightWidth" OnClientClick="return confirm('Do you really want to reset EntraCP configuration?');" />
</template_inputformcontrols>
</Template_InputFormControls>
</wssuc:InputFormSection>
<wssuc:ButtonSection runat="server">
<template_buttons>
<Template_Buttons>
<asp:Button UseSubmitBehavior="false" runat="server" class="ms-ButtonHeightWidth" OnClick="BtnOK_Click" Text="<%$Resources:wss,multipages_okbutton_text%>" ID="BtnOK" AccessKey="<%$Resources:wss,okbutton_accesskey%>" />
</template_buttons>
</Template_Buttons>
</wssuc:ButtonSection>
</table>
58 changes: 55 additions & 3 deletions Yvand.EntraCP/TEMPLATE/ADMIN/EntraCP/GlobalSettings.ascx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ protected void Initialize()
}

LabelMessage.Text = String.Format(TextSummaryPersistedObjectInformation, Configuration.Name, Configuration.Version, Configuration.Id);
PopulateConnectionsGrid();
if (!this.IsPostBack)
{
PopulateConnectionsGrid();
PopulateGraphPropertiesLists();
PopulateFields();
}
Expand Down Expand Up @@ -444,6 +444,58 @@ private bool ValidateUploadedCertFile(
}
return true;
}

protected void grdAzureTenants_RowEditing(object sender, GridViewEditEventArgs e)
{
grdAzureTenants.EditIndex = e.NewEditIndex;
PopulateConnectionsGrid();
}

protected void grdAzureTenants_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
grdAzureTenants.EditIndex = -1;
PopulateConnectionsGrid();
}

protected void grdAzureTenants_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
Guid tenantId = Guid.Parse(e.NewValues["Id"].ToString());
string newClientId = e.NewValues["ClientID"].ToString();
TextBox newSecretTextBox = (TextBox)grdAzureTenants.Rows[e.RowIndex].FindControl("EditTenantNewSecret");
string newSecret = newSecretTextBox.Text;

EntraIDTenant tenant = Settings.EntraIDTenants.First(x => x.Identifier == tenantId);
bool tenantUpdated = false;
if (String.IsNullOrWhiteSpace(newSecret))
{
if (tenant.ClientId != newClientId)
{
tenant.ClientId = newClientId;
tenantUpdated = true;
}
}
else
{
tenant.SetCredentials(newClientId, newSecret);
tenantUpdated = true;
}
if (tenantUpdated)
{
CommitChanges();
}
grdAzureTenants.EditIndex = -1;
PopulateConnectionsGrid();
}

protected void grdAzureTenants_RowDataBound(object sender, GridViewRowEventArgs e)
{
// Ask user for confirmation when cliking on button Delete - https://stackoverflow.com/questions/9026884/asp-net-gridview-delete-row-only-on-confirmation
if (e.Row.RowType == DataControlRowType.DataRow)
{
Button deleteButton = (Button)e.Row.Cells[4].Controls[2];
deleteButton.OnClientClick = "if(!confirm('Are you sure you want to delete this tenant?')) return;";
}
}
}

public class PropertyCollectionBinder
Expand All @@ -456,7 +508,7 @@ public PropertyCollectionBinder()
PropertyCollection.Columns.Add("ClientID", typeof(string));
//PropertyCollection.Columns.Add("MemberUserTypeOnly", typeof(bool));
PropertyCollection.Columns.Add("AuthenticationMode", typeof(string));
PropertyCollection.Columns.Add("ExtensionAttributesApplicationId", typeof(Guid));
//PropertyCollection.Columns.Add("ExtensionAttributesApplicationId", typeof(Guid));
}

public void AddRow(Guid Id, string TenantName, string ClientID, string AuthenticationMode, Guid ExtensionAttributesApplicationId)
Expand All @@ -467,7 +519,7 @@ public void AddRow(Guid Id, string TenantName, string ClientID, string Authentic
newRow["ClientID"] = ClientID;
//newRow["MemberUserTypeOnly"] = MemberUserTypeOnly;
newRow["AuthenticationMode"] = AuthenticationMode;
newRow["ExtensionAttributesApplicationId"] = ExtensionAttributesApplicationId;
//newRow["ExtensionAttributesApplicationId"] = ExtensionAttributesApplicationId;
}

public void BindGrid(SPGridView grid)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,12 @@ public X509Certificate2 ClientCertificateWithPrivateKey
}
protected set
{
if (value == null) { return; }
if (value == null)
{
_ClientCertificateWithPrivateKey = value;
return;
}

if (!value.HasPrivateKey) { throw new ArgumentException("The certificate cannot be imported because it does not have a private key"); }
_ClientCertificateWithPrivateKey = value;
try
Expand Down
Loading