EWS Use credentials from logged in user - c#

I have a ASP MVC web application which uses Form Authentication. Users Have to log in with their AD username and password. I only store the AD username in a cookie not the password.
In this application users need to add contacts to outlook. I'm using EWS and the code works perfectly if I use my own AD username and password.
Code sample:
var eS = new ExchangeService
{
Credentials = new WebCredentials("Username", "Password", "Domain"),
TraceEnabled = true,
};
eS.AutodiscoverUrl("email");
var contact = new Microsoft.Exchange.WebServices.Data.Contact(eS)
{
GivenName = "Nanou",
Surname = "Ponette",
};
contact.PhoneNumbers[PhoneNumberKey.BusinessPhone] = "00000000000";
contact.Save();
The question I have is how can I make this work for every user that logs in?

You should be able to use Impersonation and Kerberos delegation see http://blogs.msdn.com/b/emeamsgdev/archive/2012/11/05/exchange-web-services-from-a-web-application-using-windows-authentication.aspx which has a sample for what you need to do.
Cheers
Glen

Related

Unable to get access token from Google for Service Account

I'm trying to configure an application able to work with Gmail API. As you know to work with it we must have an access token. There are several way of requesting this token, but for my needs it should be a service account, because in future this program code will be inside the Windows Service... (so, there is no opportunity to receive the token manually by redirecting from Google URL, only a web-request and response is a way out)
So, what I have done already:
Created new project (in Google Cloud Platform);
Created new service account in this project (according to the steps mentioned here: https://developers.google.com/identity/protocols/oauth2/service-account#creatinganaccount );
Generated and downloaded *.P12 key;
Enabled domain-wide delegation [before step 4 as were suggested in many similar questions];
Authorized the scope "https://mail.google.com/" in G Suite admin account for correct Client Id (according to the steps mentioned here: https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority );
Used such simple code for authorization and requesting token:
const string serviceAccountEmail = "***test#oauthtester-271011.iam.gserviceaccount.com";
const string serviceAccountCertPath = #"C:\Users\user\Documents\Visual Studio 2017\Projects\OAuthTester\OAuthTester\bin\Debug\oauthtester-271011-bd2cced31ea5.p12";
const string serviceAccountCertPassword = "notasecret";
const string userEmail = "***oauthtest#***.com";
X509Certificate2 certificate = new X509Certificate2(
serviceAccountCertPath,
serviceAccountCertPassword,
X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { GoogleScope.ImapAndSmtp.Name }, //"https://mail.google.com/"
User = userEmail
}.FromCertificate(certificate));
credential.RequestAccessTokenAsync(CancellationToken.None).Wait();
Unfortunately, I'm facing with an error:
Client is unauthorized to retrieve access tokens using this method, or client not authorized for any of the scopes requested.
I have also tried:
To change serviceAccountEmail to ClientId;
To create, remove and add again the Authorized access in G Suite for the same Client Id;
To delete and create another service account and then Authorize new Client Id in G Suite.
Unfortunately, each time I'm facing with the same error. Maybe somebody guesses what I do wrong?

Azure Graph Api - Change Password does not work

I have the following code in order to update the password profile on azure:
ActiveDirectoryClient client = AuthenticationHelper.GetActiveDirectoryClient();
IUser toUpdate = await client.Users.GetByObjectId(user.ObjectId).ExecuteAsync();
toUpdate.PasswordProfile = new PasswordProfile()
{
ForceChangePasswordNextLogin = false,
Password = password
};
toUpdate.UpdateAsync().Wait();
Apparently I am able to change the user password in Azure (Cloud) but it is not write back to local Active Directory. I have reviewed the settings in Azure Coennect and the PasswordWriteBack option is checked.
Before you can enable and use the Password Writeback, you must make sure you complete the following prerequisites:
You have an Azure AD tenant with Azure AD Premium enabled
Password reset has been configured and enabled in your tenant
Please refer the document here about the detail of PasswordWriteBack.

ASP.NET MVC and Identity - Reset password doesn't work

I have problem with resetting password for user account. I am using Microsoft way to do it, but it's just not working. Here is the code that I use to generate reset password token
var resetPasswordToken = new ResetPasswordToken
{
Id = Guid.NewGuid().ToString(),
Token = UserManager.GeneratePasswordResetToken(user.Id),
User = user,
ValidFrom = DateTime.Now,
ValidTo = DateTime.Now.AddMinutes(ApplicationConstants.SettingsResetPasswordTokensValidTimeInMinutes)
};
_resetPasswordTokensRepository.Insert(resetPasswordToken);
_resetPasswordTokensRepository.Save();
var email = new ResetPasswordEmailModel
{
ResetPasswordToken = resetPasswordToken,
User = user
};
IUserMailer mailer = new UserMailer();
mailer.ResetPassword(email).Send();
That works fine, I have the token in database and I send it to user via email. Then user has to click the link. Here is how I generate new password and replace old password with the new one in database.
var resetPasswordToken = _resetPasswordTokensRepository.GetByEmailAndToken(email, code);
var newPassword = Membership.GeneratePassword(10, 2);
var result = await UserManager.ResetPasswordAsync(user.Id, resetPasswordToken.Token, newPassword);
if (result.Succeeded)
{
_resetPasswordTokensRepository.Remove(resetPasswordToken);
_usersRepository.Save();
var model = new NewPasswordEmailModel
{
User = user,
Password = newPassword
};
IUserMailer mailer = new UserMailer();
mailer.NewPassword(model).Send();
}
And this also works. I mean it changes password in database and sends it to user via email. The problem is user can not login with the new password or with the old password.
I did not show it here, but I check if both token and user exist in database.
What am I doing wrong?
Despite that you already found the issue, I'll try to point in a better direction.
What you describe is not a "Microsoft" way. First time I see something like that. Is this part of a template? Open Visual Studio 2013 and create a new MVC project with Individual Accounts - this will give you the "Microsoft" way.
You save the token in you DB. No need for that. Token should be emailed to a user as a link and then clicked by user and this way the token will be passed to the controller where you reset the email.
You generate a new password for user. Don't do that - let users pick their own password. And you use Membership for that - bad practice to mix Identity and MembershipProvider. MebershipProvider is very invasive and tries to take over when it can. Possibly it can cause issues later down the lifetime.
You email the password to a user. Very bad security practice. Email is not a secure channel. Let the user pick their new password on your web-page and don't ever email the passwords.
Highly recommended article by Troy Hunt about password resetting - a very worthy reading if you work with passwords.

How to configure ASP.Net website to have access to Active Directory

I am trying to create a intranet website which can look up a users email address based on their Active Directory username.
I have the following in my web.config:
<authentication mode="Windows"/>
<identity impersonate="true"/>
And I can obtain the the users UserName with:
Environment.UserName
Running on localhost, the following code allows me to query the AD and obtain the email:
public string GetADUser(string userName)
{
DirectoryEntry entry = new DirectoryEntry();
// get a DirectorySearcher object
DirectorySearcher search = new DirectorySearcher(entry);
// specify the search filter
search.Filter = "(&(objectClass=user)(anr=" + userName + "))";
// specify which property values to return in the search
search.PropertiesToLoad.Add("mail"); // smtp mail address
// perform the search
SearchResult result = search.FindOne();
string email = string.Empty;
if (result != null)
{
if (result.Properties["mail"].Count == 1)
{
email = result.Properties["mail"][0].ToString();
}
else
{
email = "no email";
}
}
else
{
email = "not found";
}
return email;
}
Great, this code authenticates using my credentials by default and allows me to pass in a username and look up the users email address.
However, when I upload this test code to the server, the code stops working if I browse to the site from anywhere other than localhost.
[COMException (0x80072020): An operations error occurred.]
Googling this reveals that I have a permissions issue.
To get around this I have tried setting the application pool identity to my credentials but this still does not allow the code to search the AD.
The website authentication is configured in IIS as follows (enabled items tagged with <<):
Anonymous Authentication:Disabled
ASP.NET Impersonation:Enabled <<
Basic Authentication:Disabled
Digest Authentication:Disabled
Forms Authentication:Disabled
Windows Authentication:Enabled <<
Is it even possible to do what I am trying to do?
What am I missing?
OK I found the problem.
In this case, having ASP.NET Impersonation:Enabled in IIS and my Web.Config was conflicting with the Application Pool identity I had configured. (I think).
Once I set the application pool identity to run using an appropriate account authenticated to query the AD, disabled Impersonation and left Windows Authentication:Enabled I was able to get the website to query the AD without passing any credentials in my code.

Authenticate user by ADFS (Active Directory Federation Service)

I need to check whether particular user exist OR not in Active Directory by ADFS.
So, I want my ADFS to check user Authentication by UserName/Password.
Could anybody please provide the sample code OR tutorial for the same.
Thanks in advance!
To use Username/Password authentication you can use the
trust/13/UsernameMixed
endpoint of the ADFS 2.0.
This does NOT check if the user exists in the Active Directory!
In code you request the token like this:
WSTrustChannelFactory adfsfactory = new WSTrustChannelFactory(new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
StsEndpoint);
adfsfactory.TrustVersion = TrustVersion.WSTrust13;
// Username and Password here...
factory.Credentials.UserName.UserName = "domain\username";
factory.Credentials.UserName.Password = "password";
IWSTrustChannelContract channel = adfsfactory.CreateChannel();
// request the token
SecurityToken token = channel.Issue(rst);
Then create the channel factory for your service using your token:
var binding = new WS2007FederationHttpBinding(WSFederationHttpSecurityMode.Message);
var factory = new ChannelFactory<IYourInterface >(binding, "your service address");
factory.ConfigureChannelFactory();
IYourInterface channel = factory.CreateChannelWithIssuedToken(token);
Hope this helps!
The AD FS 2.0 sign-in pages support username/password authentication out of the box. No code or customizations necessary.
As per #Marnix, this is out the box behavior.
However, just to point out:
Authenticating the user is NOT the same as checking whether a particular user exists in Active Directory.
e.g. the user could be locked out. He still exists in AD but will not be able to authenticate.

Categories