Thanks to visit codestin.com
Credit goes to github.com

Skip to content
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
45 changes: 42 additions & 3 deletions aspx/wwwroot/App_Code/AuthService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ public string ValidateCredentials(string username, string password)
{
return new JavaScriptSerializer().Serialize(new { success = false, error = result.Item2, domain = domain });
}



}

[WebMethod]
Expand All @@ -61,4 +58,46 @@ public string GetDomainName()
{
return AuthUtilities.SignOn.GetDomainName();
}

[WebMethod]
[ScriptMethod]
public string ChangeCredentials(string username, string oldPassword, string newPassword)
{
if (System.Configuration.ConfigurationManager.AppSettings["PasswordChange.Enabled"] == "false")
{
return new JavaScriptSerializer().Serialize(new { success = false, error = "Password change is disabled." });
}

// if the username contains a domain, split it to get the username and domain separately
string domain = null;
if (username.Contains("\\"))
{
string[] parts = username.Split(new[] { '\\' }, 2);
domain = parts[0]; // the part before the backslash is the domain
username = parts[1]; // the part after the backslash is the username
}
else
{
domain = AuthUtilities.SignOn.GetDomainName();
}

if (string.IsNullOrEmpty(username))
{
return new JavaScriptSerializer().Serialize(new { success = false, error = "Username must be provided.", domain = domain });
}

// attempt to change the credentials for the user
var result = AuthUtilities.SignOn.ChangeCredentials(username, oldPassword, newPassword, domain);
var success = result.Item1;
var errorMessage = result.Item2;

if (success)
{
return new JavaScriptSerializer().Serialize(new { success = true, username = username, domain = domain });
}
else
{
return new JavaScriptSerializer().Serialize(new { success = false, error = errorMessage, domain = domain });
}
}
}
128 changes: 127 additions & 1 deletion aspx/wwwroot/App_Code/AuthUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ public UserInformation GetUserInformation(HttpRequest request)

// get the full name of the user
string fullName = user.DisplayName ?? user.Name ?? user.SamAccountName;

// get all groups of which the user is a member (checks all domains and local machine groups)
var groupInformation = UserInformation.GetAllUserGroups(user);

Expand Down Expand Up @@ -857,6 +857,7 @@ out IntPtr phToken
public const int ERROR_INVALID_WORKSTATION = 1329; // the user is not allowed to log on to this workstation
public const int ERROR_PASSWORD_EXPIRED = 1330; // the user's password has expired
public const int ERROR_ACCOUNT_DISABLED = 1331; // the user account is disabled
public const int ERROR_PASSWORD_MUST_CHANGE = 1907; // the user account password must change before signing in

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
Expand Down Expand Up @@ -944,10 +945,135 @@ public static Tuple<bool, string> ValidateCredentials(string username, string pa
return Tuple.Create(false, Resources.WebResources.Login_PasswordExpiredError);
case ERROR_ACCOUNT_DISABLED:
return Tuple.Create(false, Resources.WebResources.Login_AccountDisabledError);
case ERROR_PASSWORD_MUST_CHANGE:
return Tuple.Create(false, Resources.WebResources.Login_PasswordMustChange);
default:
return Tuple.Create(false, "An unknown error occurred: " + errorCode);
}
}
}

[DllImport("Netapi32.dll", SetLastError = true)]
public static extern int NetUserChangePassword(
[In] string domainname,
[In] string username,
[In] string oldpassword,
[In] string newpassword
);
public static Tuple<bool, string> ChangeCredentials(string username, string oldPassword, string newPassword, string domain)
{
if (domain.Trim() == Environment.MachineName)
{
domain = null; // for local machine
}

string entryUrl = null;

// if the user is on the local machine, we can use the WinNT provider to change the password
if (string.IsNullOrEmpty(domain))
{
entryUrl = "WinNT://" + Environment.MachineName + "/" + username + ",user";
}
// othwerwise, we need to find the user's distinguished name in the domain
// so we can use the LDAP provider to change the password
else
{
string userDistinguishedName = null;
string ldapPath = "LDAP://" + domain;
try
{

using (DirectoryEntry searchRoot = new DirectoryEntry(ldapPath))
{
using (DirectorySearcher searcher = new DirectorySearcher(searchRoot))
{
searcher.Filter = "(&(objectClass=user)(sAMAccountName=" + username + "))";
searcher.PropertiesToLoad.Add("distinguishedName");

SearchResult result = searcher.FindOne();
if (result != null && result.Properties.Contains("distinguishedName"))
{
userDistinguishedName = result.Properties["distinguishedName"][0].ToString();
}
}
}
}
catch (Exception ex)
{
return Tuple.Create(false, "The domain cannot be accessed.");
}

if (string.IsNullOrEmpty(userDistinguishedName))
{
return Tuple.Create(false, "User could not be found in the domain: " + domain);
}

entryUrl = "LDAP://" + domain + "/" + userDistinguishedName;
}

// get the user's directory entry and then attempt to change the password
using (DirectoryEntry user = new DirectoryEntry(entryUrl))
{
// if the user is not found, throw an exception
if (user == null)
{
return Tuple.Create(false, "The user could not be found.");
}

// change the password
{
try
{
user.Invoke("ChangePassword", new object[] { oldPassword, newPassword });
user.CommitChanges();
return Tuple.Create(true, (string)null);
}
catch (System.Reflection.TargetInvocationException ex)
{
// if the password change fails, return false with an error message
if (ex.InnerException != null)
{
// if there is a constraint violation, try the PrincipalContext method
if (ex.InnerException is System.DirectoryServices.DirectoryServicesCOMException)
{
try
{
if (string.IsNullOrEmpty(domain))
{
using (var pc = new PrincipalContext(ContextType.Machine))
using (var userPrincipal = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, username))
{
userPrincipal.ChangePassword(oldPassword, newPassword);
userPrincipal.Save();
return Tuple.Create(true, (string)null);
}
}
else
{
using (var pc = new PrincipalContext(ContextType.Domain, domain ?? Environment.MachineName))
using (var userPrincipal = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, username))
{
userPrincipal.ChangePassword(oldPassword, newPassword);
userPrincipal.Save();
return Tuple.Create(true, (string)null);
}
}
}
catch (Exception pEx)
{
return Tuple.Create(false, pEx.Message);
}
}
return Tuple.Create(false, ex.InnerException.Message);
}
throw ex; // rethrow if there is no inner exception - we don't know what went wrong
}
catch (Exception ex)
{
return Tuple.Create(false, ex.Message);
}
}
}
}
}
}
1 change: 1 addition & 0 deletions aspx/wwwroot/App_Data/appSettings.config
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
<appSettings>
<add key="RegistryApps.Enabled" value="true" />
<add key="RegistryApps.AdditionalProperties" value="drivestoredirect:s:*;redirectclipboard:i:1" />
<add key="PasswordChange.Enabled" value="false" />
</appSettings>
5 changes: 4 additions & 1 deletion aspx/wwwroot/App_GlobalResources/WebResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@
<value>You are not allowed to sign in to this server.</value>
</data>
<data name="Login_PasswordExpiredError" xml:space="preserve">
<value>The password for this account has expired.</value>
<value>The password for this account has expired. {password_change_button}</value>
</data>
<data name="Login_AccountDisabledError" xml:space="preserve">
<value>Your account is currently disabled.</value>
</data>
<data name="Login_PasswordMustChange" xml:space="preserve">
<value>You must change your password before you can sign in. {password_change_button}</value>
</data>
</root>
1 change: 1 addition & 0 deletions aspx/wwwroot/lib/controls/AppRoot.ascx
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@
hidePortsEnabled: '<%= System.Configuration.ConfigurationManager.AppSettings["App.HidePortsEnabled"] %>',
iconBackgroundsEnabled: '<%= System.Configuration.ConfigurationManager.AppSettings["App.IconBackgroundsEnabled"] %>',
simpleModeEnabled: '<%= System.Configuration.ConfigurationManager.AppSettings["App.SimpleModeEnabled"] %>',
passwordChangeEnabled: '<%= System.Configuration.ConfigurationManager.AppSettings["PasswordChange.Enabled"] %>',
}
window.__machineName = '<%= resolver.Resolve(Environment.MachineName) %>';
window.__envMachineName = '<%= Environment.MachineName %>';
Expand Down
49 changes: 49 additions & 0 deletions aspx/wwwroot/password.aspx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<%-- This page should only be used in the version of the app built with vite. --%>
<%@ Page Language="C#" AutoEventWireup="true"%>
<%@ Register Src="~/lib/controls/AppRoot.ascx" TagName="AppRoot" TagPrefix="raweb" %>

<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
// prevent client-side caching
Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);
Response.Cache.SetNoStore();
Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));

if (System.Configuration.ConfigurationManager.AppSettings["PasswordChange.Enabled"] == "false")
{
Response.StatusCode = 403;
Response.Write("<h1>403 Forbidden</h3><p>Password change is disabled.</p>");
Response.End();
return;
}
}
</script>

<raweb:AppRoot runat="server" />

<script type="module">
const mainScript = document.createElement('script');
mainScript.type = 'module';
mainScript.src = '<%= ResolveUrl("~/lib/assets/password.js") %>';
mainScript.crossOrigin = 'use-credentials';
document.body.appendChild(mainScript);

const mainStylesheet = document.createElement('link');
mainStylesheet.rel = 'stylesheet';
mainStylesheet.href = '<%= ResolveUrl("~/lib/assets/password.css") %>';
mainStylesheet.crossOrigin = 'use-credentials';
document.head.appendChild(mainStylesheet);

const sharedScript = document.createElement('script');
sharedScript.type = 'module';
sharedScript.src = '<%= ResolveUrl("~/lib/assets/shared.js") %>';
sharedScript.crossOrigin = 'use-credentials';
document.body.appendChild(sharedScript);

const sharedStylesheet = document.createElement('link');
sharedStylesheet.rel = 'stylesheet';
sharedStylesheet.href = '<%= ResolveUrl("~/lib/assets/shared.css") %>';
sharedStylesheet.crossOrigin = 'use-credentials';
document.head.appendChild(sharedStylesheet);
</script>
Loading