I wrote C# code to get email from Active Directory. It is working fine on my local system, but after hosting I am not getting email address. Followings are the things I already tried -
Changed application pool identity to NetworkService
Enabled Windows and Digest Authentications (both at the same time and one by one too)
Code:
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "comppany.com" , "DC=compnay,DC=com", ContextOptions.Negotiate))
// tried above and below//(ContextType.Domain, System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName))
{
// validate the credentials
bool isValid = pc.ValidateCredentials(Uid, Pwd);
if (isValid)
{
try
{
using (UserPrincipal up = UserPrincipal.FindByIdentity(pc, Uid))
{
return up != null && !String.IsNullOrEmpty(up.EmailAddress) ? up.EmailAddress : string.Empty;
}
//return "Validate successfully.";
}
catch (Exception ex)
{
return ex.Message;
}
}
}
Also tried following -
using (var connection = new DirectoryEntry())
{
using (var search = new DirectorySearcher(connection)
{
Filter = "(samaccountname=" + Uid + ")",
PropertiesToLoad = { "mail" },
})
{
return (string)search.FindOne().Properties["mail"][0];
}
}
None of them are working after hosting the app in IIS7.0
Please help.
Thanks
It will be because your user (i.e. you) will have rights to read from Active Directory, but the IIS user and Network Service won't.
Put a try catch round the using statement thing and you should see this in the exception.
There are alternative PrincipalContext constructors that allow you to specify the details of the user to connect as, or you could change the IIS app pool to run as a user with rights - I'd go with the PrincipalContext way though.
As a quick test try this version of the PrincipalContext constructor - put your username and password in the username and password paramemetrs and see if it works when hosted in IIS - if this works then you need to come up with some way of passing the user details in via config. (Generally a service account with only the rights to read, whose password does not change often is used for this)
Related
For our new Windows 10 application (C# + XAML) we are using the new https://github.com/Microsoft/winsdkfb/ login, however since we have migrated to this login I am having no luck with facebook login.
We are using FBResult result = await sess.LoginAsync(permissions); and I am getting this error all the time: "Not Logged In: You are not logged in. Please login and try again."
My code is litteraly a copy and paste from the samples they did on github:
I have checked my SID and FacebookAppId and they are the same on both the app and the Facebook website.
public async Task<string> LogIntoFacebook()
{
//getting application Id
string SID = WebAuthenticationBroker.GetCurrentApplicationCallbackUri().ToString();
//// Get active session
FBSession sess = FBSession.ActiveSession;
sess.FBAppId = FacebookAppId;
sess.WinAppId = SID;
//setting Permissions
FBPermissions permissions = new FBPermissions(PermissionList);
try
{
// Login to Facebook
FBResult result = await sess.LoginAsync(permissions);
if (result.Succeeded)
{
// Login successful
return sess.AccessTokenData.AccessToken;
}
else
{
// Login failed
return null;
}
}
catch (InvalidOperationException ex)
{
SimpleIoc.Default.GetInstance<IErrorService>().ReportErrorInternalOnly(ex);
return null;
}
catch (Exception ex)
{
SimpleIoc.Default.GetInstance<IErrorService>().ReportErrorInternalOnly(ex);
return null;
}
return null;
}
by doing this:
//getting application Id
string SID = WebAuthenticationBroker.GetCurrentApplicationCallbackUri().ToString();
it is generating me an SID that looks like this:
ms-app://s-1-15-2-0000-bla-bla-bla-667/
so I tried adding ms-app:// to the facebook developer settings page but it did not want it, so I tried removing ms-app:// from the SID when passing it to WinAppId but still no luck
I have filled the field Windows Store SID wih My FBAppId :
does anyone have this issue?
Edit 1:
My code is copy and paste from here: http://microsoft.github.io/winsdkfb/
Edit2: playing the samples from Microsoft my issues is coming from my Application Id.
I did follow step 6:
(Enable OAuth login)
Select the created app on developers.facebook.com.
Click “Settings” from the menu on the left.
Click on the “Advanced” tab.
Under the “OAuth Settings” section, enable “Client OAuth Login” and “Embedded browser OAuth Login”.
Click on “Save Changes”.
After trying everything and NOT wanting to use WebAuthentificationBroker I have found the solution.
Go on the Facebook Developer website: https://developers.facebook.com
Then:
Go to your app name -> Settings -> Advance:
Under: Valid OAuth redirect URIs
you need to add: https://www.facebook.com/connect/login_success.html
Save and you are good to go now!
I am trying to build a registration section for a website (internal to my dept). Now to get new users registered, I built a form where user enters his employee id i.e. AD account name and then clicks a button to fetch his details. Which are later saved in database where registration requests are queued. Once those requests are approved by admin then only those users can use the application. Now the problem is that user is not logged in, so is it possible for non logged in user to fetch details from AD server. if it is then how.? Because when I tried the below listed code I am getting bad username or password error using FindOne function.
public string getProperties(string StaffCode, string property)
{
try
{
string result = "";
using (var de = new DirectoryEntry(_path))
using (var ds = new DirectorySearcher(de))
{
ds.Filter = string.Format("(sAMAccountName={0})", StaffCode);
ds.PropertiesToLoad.AddRange(new[] {
"sn", // last name
"givenName", // first name
"mail", // email
"telephoneNumber", // phone number
// etc - add other properties you need
});
var res = ds.FindOne();
if (res == null)
{
result = "noUserFound";
}
else
{
foreach (string propName in res.Properties.PropertyNames)
{
ResultPropertyValueCollection valueCollection = res.Properties[propName];
foreach (Object propertyValue in valueCollection)
{
if (propName == property)
{
result = propertyValue.ToString();
}
}
}
}
}
return result;
}
catch (Exception ex)
{
return "someErrorOccurred";
}
Please help me in overcoming this issue.
Thanks in advance
My guess is that the identity of the application pool you run this code under doesn't have enough priviledges to query the AD without authentication.
Specifically, start with replacing this constructor
using ( var de = new DirectoryEntry( _path ) )
with the one that takes admin's username/password in an explicit way
using ( var de = new DirectoryEntry( _path, username, password ) )
and make sure the username has enough priviledges to query the catalog.
If this works, you could possibly try to go back to the original version but you'd have to make sure the identity of the asp.net application pool has enough priviledges to query the AD but also, that the asp.net server is a part of the domain (if it is not, authentication without providing username/password in an explicit way will most likely not work).
Using the Exchange Web Services API, is it possible to determine whether a mailbox/e-mail address such as someone#mydomain.com exists within an organization?
If so, which is the simplest way to do this and is it possible without the use of impersonation?
Case: A Windows Service regularly sends e-mails to people within the organization. It does not have any explicit knowledge about their e-mail adresses. It only knows their username and assumes that their e-mail address is username#mydomain.com. This is true for all users except for a few that do not have mailboxes. In these cases, it should not attempt to send the e-mail in the first place.
Solution:
As suggested by mathieu: look for user and e-mail address in Active Directory instead. This function gets the job done:
using System.DirectoryServices.AccountManagement;
// ...
public static bool TryGetUserEmailAddress(string userName, out string email)
{
using (PrincipalContext domainContext =
new PrincipalContext(ContextType.Domain, Environment.UserDomainName))
using (UserPrincipal user =
UserPrincipal.FindByIdentity(domainContext, userName))
{
if (user != null && !string.IsNullOrWhiteSpace(user.EmailAddress))
{
email = user.EmailAddress;
return true;
}
}
email = null;
return false; // user not found or no e-mail address specified
}
Determining if an user has a mailbox with EWS only could be more complicated than expected, especially without impersonation.
If you're in an Active Directory domain, you should rely on the DirectoryEntry information to determine the mailbox of an user, and send email accordingly. If you got your user login, it's really easy to get the associated DirectoryEntry.
there is an easy way to do it by checking the user availability like the following code.
I tried this and it is working for me.
I am not sure about other cases when availability result returns error but for sure when the email is not right it does
to define your exchange service refer to this: https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/get-started-with-ews-managed-api-client-applications
ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2007_SP1);//You version
service.Credentials = new WebCredentials("user1#contoso.com", "password");
service.AutodiscoverUrl("user1#contoso.com", RedirectionUrlValidationCallback);
string email = "TEST#YOUR.COM";
// Get User Availability after 6 months
AttendeeInfo attendee = new AttendeeInfo(email);
var attnds = new List<AttendeeInfo>();
attnds.Add(attendee);
var freeTime = service.GetUserAvailability(attnds, new
TimeWindow(DateTime.Now.AddMonths(6), DateTime.Now.AddMonths(6).AddDays(1)), AvailabilityData.FreeBusyAndSuggestions);
//if you receive result with error then there is a big possibility that the email is not right
if(freetimes.AttendeesAvailability.OverallResult == ServiceResult.Error)
{
return false;
}
return true;
I have a Windows Service (running as the Local System user) that needs to validate a user based on username and password, in addition to checking if the user belongs to the group WSMA. My current code is like this:
var pc = new PrincipalContext(ContextType.Machine);
using (pc)
{
try
{
if (pc.ValidateCredentials(username, password))
{
using (var groupEntry = new DirectoryEntry("WinNT://./WSMA,group"))
{
foreach (object member in (IEnumerable)groupEntry.Invoke("Members"))
{
using (var memberEntry = new DirectoryEntry(member))
{
if (memberEntry.Path.ToLower().EndsWith(username.ToLower()))
{
return new LoginResult{ success = true };
}
}
}
}
}
return new LoginResult{ success = false };
}
catch (PrincipalOperationException poe)
{
if (poe.ErrorCode == -2147023688)
{
return new LoginResult { Success = false, ErrorMessage = "Password expired" };
}
throw poe;
}
}
This all works as it should, as long as I'm connected to the network, but if I plug out my network cable, then the ValidateCredentials call give me the following error message:
FileNotFoundException unhandeled by user code. The network path was not found.
I guess this has something to do with AD, but I only need to check the local users, and not domain users so a network access should not be required.
Any way to do this using the PrincipalContext, or some other way that will work in a disconnected scenario?
Here's a way to logon the User (and thus check that it's a valid user/pass): MSDN Link
I guess this should work disconnected, too, if you use a local account
I currently use LogonUser() to authenticate my user's username and password on my local domain at the office and it works great for what i need it to do.
Since I developed the app I now need to make it work over my VPN. It seems LogonUser() will not work with REMOTELY validating credentials. Or will it? Is it possible to use LogonUser() to validate a user's credentials on a REMOTE domain account?
I have read in some places that using LOGON32_LOGON_NEW_CREDENTIALS for the 4th param (login type) and LOGON32_PROVIDER_WINNT50 for the 5th param (provider) would do the trick. But every time I try that I ALWAYS get success... I can supply a bogas user and pass and it will work every time :(.
Ideas?
Edit - Added Notes
Tried to use this function but I kept getting the exception telling me the user/pass was bad.
public bool Win2kCredentialsIsValid(string domain, string username, string password)
{
string adPath = "LDAP://" + domain + "/rootDSE";
DirectoryEntry adRoot = new DirectoryEntry(adPath, domain + "\\" + username, password, AuthenticationTypes.ReadonlyServer);
try
{
object o = adRoot.Properties["defaultNamingContext"];
}
catch
{
return false;
}
return true;
}
--
Edit - Added More Notes
OK so I tried yet another example just to get it to work and started down this path, and there are a few things to note...
MyServerHostName is exactly that, my server's hostname. EX: 'Server01'.
My domain name in this example is 'MyDomain.local'
So that makes my FQN for the server 'Server01.MyDomain.local'
I tried to make this work and got the following error...
The supplied context type does not match the server contacted. The server type is Domain.
This errored out at : var context = new PrincipalContext(ContextType.ApplicationDirectory, "MyServerHostName:389", "DC=MyDomain,DC=local"))
private bool CheckADCredentials()
{
bool bResults;
using (var context = new PrincipalContext(ContextType.ApplicationDirectory,
"MyServerHostName:389",
"DC=MyDomain,DC=local"))
{
var username = "firstname.lastname";
var email = "firstname.lastname#MyServerHostName";
var password = "123456";
var user = new UserPrincipal(context)
{
Name = username,
EmailAddress = email
};
user.SetPassword(password);
user.Save();
if (context.ValidateCredentials(username, password, ContextOptions.SimpleBind))
{
bResults = true;
}
else
{
bResults = false;
}
user.Dispose();
}
return bResults;
}
I ended up going with a different solution. Instead of trying to validate a user's account on a domain that my PC was not connected to I ended up caching my domain credentials in the database and just built a salted MD5 type encrypt function so it would make it hard .. er.. for someone to crack it. ;)
Now I just validate against cached credentials in the database when working remotely... It just required the user to first login on the domain but then the user can use it remotely day and night. ;)
Thanks!