I want to change active directory password in my web part in SharePoint but when i change the password, the stored account password in SharePoint does not change and i get this error:
This operation can be performed only on a computer that is joined to a server farm by users who have permissions in SQL Server to read from the configuration database. To connect this server to the server farm, use the SharePoint Products Configuration Wizard, located on the Start menu in Microsoft SharePoint 2010 Products.
This is my code for change password:
public void ChangePassword(string usrDomain, string username, string oldPassword, string newPassword)
{
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, usrDomain, username, oldPassword))
{
UserPrincipal user = new UserPrincipal(ctx);
user = UserPrincipal.FindByIdentity(ctx, username);
user.ChangePassword(oldPassword, newPassword);
user.Save();
}
}
Assuming your AD server is "in the sharepoint farm", you will have to run your code with another account.
Solution is to impersonate with an admin user token who has rights in the AD server :
SPUser AdminUser = SPContext.Current.Web.SiteUsers[#"domain\username"];
using(SPSite oSiteCollection = new SPSite("http://YOURSITE", AdminUser.UserToken))
{
//run your code
}
Related
I have a SharePoint solution with a custom application where a user should be able to change some properties in his own Active Directory object.
I am doing the following:
PrincipalContext ctx = ActiveDirectory.GetPrincipalContext("lab");
UserPrincipal user = ActiveDirectory.GetUserPrincipal(ctx, "Administrator");
user.DisplayName = user.DisplayName + DateTime.Now.ToString("ddMMyyyyHHmmss");
user.Save();
I am logged in to SharePoint as the domain administrator and i am trying to change my own DisplayName.
What is wrong with my code?
Update 20.04.2016
I have built a small Console Application with the following code:
static void Main(string[] args)
{
try
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "lab");
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "administrator");
DirectoryEntry de = (user.GetUnderlyingObject() as DirectoryEntry);
user.DisplayName = user.DisplayName + DateTime.Now.ToString("ddMMyyyyHHmmss");
user.Save();
Console.WriteLine("OK");
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
This works fine! That means normally, that the Authentication goes wrong or the user which is logged into SharePoint is not getting used to connect to AD and do the changes. If this could be the case, how could i find out with which user i am doing the operation?
Update 20.04.2016 - 2
I have now tried to put the username and password in the PrincipalContext contructor as below:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "lab", "administrator", "pass");
This works, too! That means now definitely, that the user which is logged in to SharePoint is not used to create the PrincipalContext. But why? Normally code is always executed in the context of the current user!?
How can i find out which user is used to create the PrincipalContext and how can i change it that the logged in user is getting used?
I had the same problem, I resolved it like this:
In IIS, in the advanced settings of my app -> In Identity I add my service account (example: domain\service-account)
In my active directory, I give to this service account full control on folder and sub-folder where I want to create/update user (you need to modify view to see security tab -> right click -> view -> advanced features)
If you already have that, check if your service account is not disabled
And now everything is working :)
I try to authenticate users belonging to remote ActiveDirectory from my machine, which is not the same domain as the current machine or user domain. There will be no trust between my machine and remote ActiveDirectory machine.
Initial Try
I tried to authenticate a user(Input: sAMAccountName, machine's ipaddress, machine's domain username("Administrator") and machine's password(***). Able to get result that the user with 'sAMAccountName' do exist in ActiveDirectory.
My Requirement:
Imagine that already a user("qwerty") is created in ActiveDirectory
From my local machine, I will have the following information,
a. Remote ActiveDirectory ipaddress
b. Remote ActiveDirectory machine's username and password.
c. Username and password of User "qwerty"
I need to check whether User "qwerty" is present in remote ActiveDirectory's users list and validate whether the password entered is same in ActiveDirectory's Users list
Code I tried:
DirectoryEntry entry = new DirectoryEntry("LDAP://ipaddress/DC=dinesh,DC=com", name, password);
DirectorySearcher searcher = new DirectorySearcher(entry);
searcher.Filter = "(sAMAccountName=" + name + ")";
try
{
SearchResult adsSearchResult = adsSearcher.FindOne();
isValid = true;
adsEntry.Close();
}
catch (Exception ex)
{
adsEntry.Close();
}
Do I need to create a trust between local machine and remote ActiveDirectory machine before validating Users in a remote ActiveDirectory? If yes please tell how it can be done;
After creating trust, how can I validate Users?
===========================================================================
I am able to use the solution suggested by Rainer, but with a new problem. When I create a new user via C# code from a different machine, then some properties do not set properly.
Does this need to be set compulsorily while creating user?
First some basics (independent of this question)
Authentication
The system checks if Bob is really Bob. In an Active Directory environment, this is usually done with a domain login from the workstation, Bob enters his username and password, and he gets a Kerberos ticket. Later, if he wants to access e.g. a file share on a remote fileserver, he does not need to login anymore, and can access the files without entering username/password.
Authorization
The system checks which resources Bob is allowed to access. Usually Bob is in domain groups, and a group is in the ACL (access control list) of the resource.
If there are multiple trusting domains, Bob needs to login in one domain, and can access resources in all other domains.
This is one of the main reasons using Active Directory: single sign on
Checking if user / password is valid
If you have a username and password and want to check if the password is valid, you have to do a login to the domain. There is no way of just “checking if the password is correct”.
Login means: if there is a security policy “lock account if more than 3 invalid logins”, the account will be locked out checking with wrong password, even if you “only want to check the user+password”.
Using .NET Directory Service functions
I assume here that the process is either run by a human account as a normal program, or the program is a Windows service or a scheduled task which runs under a domain “technical user” account. In this case, you do not need to provide credentials for using the AD functions. If accessing other trusting AD domains, this is also true.
If you want to login to a “foreign domain”, and there is no trust, you need to provide a username+password (as in your code).
"Manually" authenticating a user
Normally, this should not be needed. Example: ASP.NET intranet usage. The user access a web application on the current domain or trusting domain, the authentication is done “in the background” by browser and IIS (if integrated Windows authentication is on). So you never need to handle user passwords in the application.
I don’t see many use cases where a password is handled by code.
One may that your program is a helper tool for storing emergency user accounts/passwords. And you want to check periodically if these accounts are valid.
This is a simple way to check:
using System.DirectoryServices.AccountManagement;
...
PrincipalContext principalContext =
new PrincipalContext(ContextType.Domain, "192.168.1.1");
bool userValid = principalContext.ValidateCredentials(name, password);
One can also use the older, raw ADSI functions:
using System.DirectoryServices;
....
bool userOk = false;
string realName = string.Empty;
using (DirectoryEntry directoryEntry =
new DirectoryEntry"LDAP://192.168.1.1/DC=ad,DC=local", name, password))
{
using (DirectorySearcher searcher = new DirectorySearcher(directoryEntry))
{
searcher.Filter = "(samaccountname=" + name + ")";
searcher.PropertiesToLoad.Add("displayname");
SearchResult adsSearchResult = searcher.FindOne();
if (adsSearchResult != null)
{
if (adsSearchResult.Properties["displayname"].Count == 1)
{
realName = (string)adsSearchResult.Properties["displayname"][0];
}
userOk = true;
}
}
}
If your real requirement is actually a validity check of user+password, you can do it in one of these ways.
However, if it is a "normal application", which just wants to check if the entered credentials are valid, you should rethink your logic. In this case, you better should rely on the single sign on capabilities of AD.
If there are further questions, please comment.
b. Remote ActiveDirectory machine's username and password.
This sounds a bit unclear. I assume you mean "a username and corresponding password in the remote domain".
There is also the concept of a machine account, which is the hostname appended with $. But that's another topic.
Creating new user
Option 1
using (DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://192.168.1.1/CN=Users,DC=ad,DC=local",
name, password))
{
using (DirectoryEntry newUser = directoryEntry.Children.Add("CN=CharlesBarker", "user"))
{
newUser.Properties["sAMAccountName"].Value = "CharlesBarker";
newUser.Properties["givenName"].Value = "Charles";
newUser.Properties["sn"].Value = "Barker";
newUser.Properties["displayName"].Value = "CharlesBarker";
newUser.Properties["userPrincipalName"].Value = "CharlesBarker";
newUser.CommitChanges();
}
}
Option 2
using (PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, "192.168.1.1",
"CN=Users,DC=ad,DC=local", name, password))
{
using (UserPrincipal userPrincipal = new UserPrincipal(principalContext))
{
userPrincipal.Name = "CharlesBarker";
userPrincipal.SamAccountName = "CharlesBarker";
userPrincipal.GivenName = "Charles";
userPrincipal.Surname = "Barker";
userPrincipal.DisplayName = "CharlesBarker";
userPrincipal.UserPrincipalName = "CharlesBarker";
userPrincipal.Save();
}
}
I leave as an exercise to you to find out which attribute goes into which User dialog entry field :-)
I'm trying to authenticate login credentials against Active Directory (AD DS) using the following code:
using (var context = new PrincipalContext(ContextType.Domain, ipAddress))
{
Console.WriteLine("Connected to {0}:", context.ConnectedServer);
context.ValidateCredentials(username, password);
}
Where ipAddress is the address of the primary domain controller. However this gives the following error when attempting to read context.ConnectedServer:
System.DirectoryServices.DirectoryServicesCOMException (0x8007052E):
The username or password is incorrect.
In addition to this issue I have the following constraints:
The production environment may or may not be on the domain.
The clients do not want to enter any privileged credentials to query the directory.
Due to this second constraint I have tried to execute a SimpleBind, but without much luck:
using (var context = new PrincipalContext(ContextType.Domain,
ipAddress,
null,
ContextOptions.SimpleBind,
usernameToValidate,
password))
Based on these constraints, how can I authenticate against Active Directory?
I was able to authenticate using the following code:
using (var context = new PrincipalContext(ContextType.Domain, ipAddress))
{
// NOTE! Username must be of the format domain\username
return context.ValidateCredentials("domain\someuser", password, ContextOptions.SimpleBind);
}
The key part was to prefix the username with the short domain name. Once I did that, and specified SimpleBind in the call to ValidateCredentials instead of in the context constructor, it worked fine.
I'm trying to do user authorization though AAD in azure app with own client side. I have a user named "User" in my AAD with password "pass". When user is trying to connect the app:
try
{
if (false == Utils.DataBaseUtils.CheckLoginCorrect(sceneMessage.Login, sceneMessage.Pwd))
{
WriteToLog("Wrong password");
SendError(handler, "Wrong password");
return;
}
}
catch (Exception e)
{
WriteToLog("Unexpected problem when checking password: "+e.ToString());
SendError(handler, "Unexpected problem when checking password");
return;
}
//authorization using Azure Active Directory
public static bool CheckLoginCorrect(string login, string password)
{
if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(password)) //validatecredentials return true if log or pass is empty
return false;
using (PrincipalContext adContext = new PrincipalContext(ContextType.Domain, "mydomain156.onmicrosoft.com")) //represent AD
{
return adContext.ValidateCredentials(login, password, ContextOptions.Negotiate);
}
}
Where sceneMessage.Login == "User", sceneMessage.Pwd == "pass".
Here I'm getting error:
System.DirectoryServices.AccountManagement.PrincipalServerDownException:
The server could not be contacted. --->
System.DirectoryServices.Protocols.LdapException: The LDAP server is
unavailable.
Could anybody help, please?
It looks like you're using the AD libraries for traditional on-premise AD. To program against Azure AD, use the Auzre Authentication Library (AAL). Note, last week AAL was renamed to Active Directory Authentication Library.
http://msdn.microsoft.com/en-us/library/jj573266.aspx
Azure Active Directory Authentication Library (ADAL, formerly AAL) is the correct API to use for authenticating users in Azure Active Directory. Version 1 has been released and you can find more information here:
http://www.cloudidentity.com/blog/2013/09/12/active-directory-authentication-library-adal-v1-for-net-general-availability/
I want to take the current logged in user name (windows user) using c#, i have done the following.
Create one web application
Published the web application
Created the site in iis and given the physical path
when i try to get the user name , am getting the application pool name as current user name, i have used the below line of code. and i have given the anonymous access for this site.
string username = System.Environment.UserName.ToString();
WindowsIdentity.GetCurrent()
If you are using membership then,
MembershipUser currentUser = Membership.GetUser();
//Get Username of Currently logged in user
string username = currentUser.UserName;
//Get UserId of Currently logged in user
string UserId = currentUser.ProviderUserKey.ToString();
http://www.aspdotnet-suresh.com/2011/01/how-can-we-get-username-and-userid-of.html