Confused with the SmtpClient.UseDefaultCredentials Property - asp.net-mvc

In my MVC4 application, I'm using the SmtpClient to send out email via Gmail's smtp.gmail.com SMTP server.
I've configured my Web.Config file with the following settings:
<system.net>
<mailSettings>
<smtp deliveryMethod="Network">
<network enableSsl="true"
defaultCredentials="false"
host="smtp.gmail.com"
port="587"
userName="xxMyUserNamexx#gmail.com"
password="xxMyPasswordxx" />
</smtp>
</mailSettings>
</system.net>
The method that uses the SmtpClient and sends an email message looks like:
public void SendMail(string fromDisplayName, string fromEmailAddress, string toEmailAddress, string subject, string body)
{
MailAddress from = new MailAddress(fromEmailAddress, fromDisplayName);
MailAddress to = new MailAddress(toEmailAddress);
MailMessage mailMessage = new MailMessage(from, to);
mailMessage.Body = body;
mailMessage.Subject = subject;
SmtpClient client = new SmtpClient();
//client.UseDefaultCredentials = false;
client.Send(mailMessage);
}
The code above works as expected and is fine. What confuses me is the commented line client.UseDefaultCredentials = false; - If I were to uncomment that line, I'll receive an exception message that states:
The SMTP server requires a secure connection or the client was not
authenticated. The server response was: 5.5.1 Authentication Required.
What's more is, it doesn't matter if I set the UseDefaultCredentials property to true or false, I'll still receive the exception message. The only way for me to avoid the exception message is to remove the line altogether.
Is this behavior normal? Can you explain why I'm receiving the exception message?

So why would me explicitly setting the property to false throw an exception?
The reason for this is because the setter for UseDefaultCredentials sets the Credentials property to null if you set it to false, or it sets it to the CredentialCache.DefaultNetworkCredentials property if set to true. The DefaultNetworkCredentials property is defined by MSDN as:
The credentials returned by DefaultNetworkCredentials represents the authentication credentials for the current security context in which the application is running. For a client-side application, these are usually the Windows credentials (user name, password, and domain) of the user running the application. For ASP.NET applications, the default network credentials are the user credentials of the logged-in user, or the user being impersonated.
When you set UseDefaultCredentials to true, it's using your IIS user, and I'm assuming that your IIS user does not have the same authentication credentials as your account for whatever SMTP server you're using. Setting UseDefaultCredentials to false null's out the credentials that are set. So either way you're getting that error.
Here's a look at the setter for UseDefaultCredentials using dotPeek:
set
{
if (this.InCall)
{
throw new InvalidOperationException(
SR.GetString("SmtpInvalidOperationDuringSend"));
}
this.transport.Credentials = value
? (ICredentialsByHost) CredentialCache.DefaultNetworkCredentials
: (ICredentialsByHost) null;
}

I was getting the same message and it was driving me crazy. After reading this thread I realized that the order mattered on setting my credentials. This worked:
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(smtpSettings.Username, smtpSettings.Password);
While this generated the error you describe:
client.Credentials = new NetworkCredential(smtpSettings.Username, smtpSettings.Password);
client.UseDefaultCredentials = false;
This is just an FYI to anybody else having the same problem.

This option will set the client to use the default credentials of the currently logged in user
If you set it to true, then it will try to use the user's credentials. If you set it to false, then it will use the values explicitly set for the Credentials property of the client, and if they aren't explicitly set, then it will try to connect anonymously as you are seeing.

This is how we can create SMTP Client with or without NetworkCredentials. I am using this code to send emails. We should use client.UseDefaultCredentials only when we are not passing credentials and going by default.
private SmtpClient InitializeSMTPClient()
{
var client = new SmtpClient(_smtpServer, _smtpPort);
client.UseDefaultCredentials = _useSMTPDefaultCredentials;
if (_useSMTPDefaultCredentials)
return client;
var credentials = new NetworkCredential(_smtpUsername, _smtpPassword);
client.Credentials = credentials;
return client;
}
SMTPEmailResult SendSMTPEmail(List<string> to_email, List<string> ccEmails, string subject, string message)
{
try
{
using (var client = InitializeSMTPClient())
{
var mail_message = GetMailMessage(to_email, ccEmails, subject, message);
log.Debug("Sending SMTP email.");
client.Send(mail_message);
log.Debug("SMTP email sent successfully.");
return SMTPEmailResult.SendSuccess;
}
}
catch (Exception ex)
{
log.Error(ex.Message, ex);
return SMTPEmailResult.SendFailed;
}
}

Related

Login to azure oauth2 with on premise adfs

I am trying to connect with oauth2 to our azure tenant inside some python script. I created an app registration and permitted some API access for it.
When I try to connect with username and password, I will just get an Error Code 50126 (Invalid username or password).
If I define some secret inside my app registration and switch to client secret as grant_type, I will have access to my app.
But I want to use username and password. Username is user#domain.com and password is correct, too.
So I think our ADFS server is making problems.
We are using some on premise AD and sync the user data to azure with Azure Connect, but we do not sync the passwords. So logins to Azure are forwarded to our adfs instance and are done on premise.
How can I implement that logic in my script? I need something like a redirect to adfs with my username and password and need the correct response to logon to azure.
I already searched a lot for this, but did not find an answer. It is not possible to me to activate the password sync.
My connection parameter to azure is like
tokenpost = {
'client_id':clientid,
'resource':crmorg,
'password':password,
'username':'user#domain.com',
'grant_type':'password'
}
tokenres = requests.post('https://login.microsoftonline.com/<tenantid>/oauth2/token', data=tokenpost)
Some had the same problem?
Best,
Robin
Got it.
It was necessary to get an assertion from ADFS first.
This was the doc which helped me a lot: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-saml-bearer-assertion
I wrote in Java now but it should be very equal in python:
package Azure
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import java.util.Base64;
String getAzureAccessToken(String clientId, String assertion, String azureURL)
{
HttpClient httpClient = new HttpClient();
PostMethod methodPost = new PostMethod(azureURL);
methodPost.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
methodPost.setRequestHeader("Host", "login.microsoftonline.com");
methodPost.addParameter("grant_type", "urn:ietf:params:oauth:grant-type:saml2-bearer");
methodPost.addParameter("assertion", Base64.getEncoder().encodeToString(assertion.getBytes()));
methodPost.addParameter("client_secret", "XXX");
methodPost.addParameter("client_id", clientId);
methodPost.addParameter("scope", "XXX");
methodPost.addParameter("Accept", "application/json");
int returnCode = httpClient.executeMethod(methodPost)
if(returnCode != 200)
{
throw new Exception("Cannot connect to Azure "+methodPost.getStatusLine().toString())
}
BufferedReader br = new BufferedReader(new InputStreamReader(methodPost.getResponseBodyAsStream()));
String response;
while ((response = br.readLine()) != null) {
return response.split("\"access_token\":\"")[1].split("\"")[0];
}
}
String getAdfsAssertion(String username, String password, String adfsURL)
{
String adfsSoapXML = """<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header><a:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action>
<a:MessageID>urn:uuid:XXX</a:MessageID>
<a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo>
<a:To s:mustUnderstand="1">"""+ adfsURL +"""</a:To>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" >
<o:UsernameToken u:Id="XXX">
<o:Username>"""+ username +"""</o:Username>
<o:Password>"""+ password +"""</o:Password>
</o:UsernameToken>
</o:Security>
</s:Header>
<s:Body>
<trust:RequestSecurityToken xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<a:EndpointReference>
<a:Address>urn:federation:MicrosoftOnline</a:Address>
</a:EndpointReference>
</wsp:AppliesTo>
<trust:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</trust:KeyType>
<trust:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</trust:RequestType>
<trust:TokenType>urn:oasis:names:tc:SAML:2.0:assertion</trust:TokenType>
</trust:RequestSecurityToken>
</s:Body>
</s:Envelope>
""";
HttpClient httpClient = new HttpClient();
PostMethod methodPost = new PostMethod(adfsURL);
methodPost.setRequestBody(adfsSoapXML);
methodPost.setRequestHeader("SOAPAction", "http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue");
methodPost.setRequestHeader("Content-type", "application/soap+xml");
methodPost.setRequestHeader("client-request-id", "XXX");
methodPost.setRequestHeader("return-client-request-id", "true");
methodPost.setRequestHeader("Accept", "application/json");
int returnCode = httpClient.executeMethod(methodPost)
if(returnCode != 200)
{
throw new Exception("Cannot connect to adfs "+methodPost.getStatusLine().toString())
}
BufferedReader br = new BufferedReader(new InputStreamReader(methodPost.getResponseBodyAsStream()));
String response;
while ((response = br.readLine()) != null) {
return response.split("<trust:RequestedSecurityToken>")[1].split("</trust:RequestedSecurityToken>")[0];
}
}

Form data to an email address in asp.net core

What is the easiest way to have form data sent to an email address , in an asp.net core app? I have tried to send an email from my outlook account to gmail one wit Mailkit, but i keep getting an error AuthenticationException: AuthenticationInvalidCredentials , even if my credentials are corect.
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Joey Tribbiani", "joey#outlook.com"));
message.To.Add(new MailboxAddress("Mrs. Chanandler Bong", "Chandler#gmail.com"));
message.Subject = "How you doin'?";
message.Body = new TextPart("plain")
{
Text = #"Hey Chandler"
};
using (var client = new SmtpClient())
{
// For demo-purposes, accept all SSL certificates (in case the server supports STARTTLS)
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
client.Connect("smtp.outlook.com", 587, false);
// Note: since we don't have an OAuth2 token, disable
// the XOAUTH2 authentication mechanism.
client.AuthenticationMechanisms.Remove("XOAUTH2");
// Note: only needed if the SMTP server requires authentication
client.Authenticate("username", "*************");
client.Send(message);
client.Disconnect(true);
}

Umbraco mvc Please help me with the HandleForgottenPassword

I have been ask this question for few days but no answer, i am very new to Umbraco and junior of programming.i am working on trying to get admin user to reset password when they are forget their password and sent them an email to reset their password, after they
reset they password they will get a new password to login when they
login they we will force them to change password, so for now i am
struggle on the HandleForgottenPassword, getting
Object reference not set to an instance of an object. on the yellow line,
enter code here
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public ActionResult HandleForgottenPassword(ForgottenPasswordViewModel model)
{
if (!ModelState.IsValid)
{
return PartialView("ForgottenPassword", model);
}
//Find the member with the email address
var name =Member.GetMemberFromLoginName(model.LoginName);
var findMember = Member.GetMemberFromEmail(model.EmailAddress);
if (findMember != null)
{
//We found the member with that email
//Set expiry date to
DateTime expiryTime = DateTime.Now.AddMinutes(15);
//Lets update resetGUID property
// findMember.getProperty("resetGUID").Value = expiryTime.ToString("ddMMyyyyHHmmssFFFF");
//Save the member with the up[dated property value
findMember.Save();
//Send user an email to reset password with GUID in it
EmailHelper email = new EmailHelper();
email.SendResetPasswordEmail(findMember.Email, expiryTime.ToString("ddMMyyyyHHmmssFFFF"));
}
else
{
ModelState.AddModelError("ForgottenPasswordForm.", "No member found");
return PartialView("ForgottenPassword", model);
}
return PartialView("ForgottenPassword", model);
}
please help with sending email ( using EmailHelper from the package)
private const string SendGridUsername = "sendGridUsername";
private const string SendGridPassword = "sendGridPassword";
private const string EmailFromAddress = "you#yoursite.com";
public void SendResetPasswordEmail(string memberEmail, string resetGUID)
{
//Send a reset email to member
// Create the email object first, then add the properties.
var myMessage = SendGrid.GetInstance();
// Add the message properties.
myMessage.From = new MailAddress(EmailFromAddress);
//Send to the member's email address
myMessage.AddTo(memberEmail);
//Subject
myMessage.Subject = "Umb Jobs - Reset Your Password";
//Reset link
string baseURL = HttpContext.Current.Request.Url.AbsoluteUri.Replace(HttpContext.Current.Request.Url.AbsolutePath, string.Empty);
var resetURL = baseURL + "/reset-password?resetGUID=" + resetGUID;
//HTML Message
myMessage.Html = string.Format(
"<h3>Reset Your Password</h3>" +
"<p>You have requested to reset your password<br/>" +
"If you have not requested to reste your password, simply ignore this email and delete it</p>" +
"<p><a href='{0}'>Reset your password</a></p>", resetURL);
//PlainText Message
myMessage.Text = string.Format(
"Reset your password" + Environment.NewLine +
"You have requested to reset your password" + Environment.NewLine +
"If you have not requested to reste your password, simply ignore this email and delete it" +
Environment.NewLine + Environment.NewLine +
"Reset your password: {0}",
resetURL);
// Create credentials, specifying your user name and password.
var credentials = new NetworkCredential(SendGridUsername, SendGridPassword);
// Create an SMTP transport for sending email.
var transportSMTP = SMTP.GetInstance(credentials);
// Send the email.
transportSMTP.Deliver(myMessage);
}
when i try to sending the email i got this erro
Unable to read data from the transport connection: net_io_connectionclosed.
here is my *web.config *
<system.net>
<mailSettings>
<smtp>
<network host="127.0.0.1" userName="username" password="password" />
</smtp>
</mailSettings>
</system.net>
Thank you in advance. MC
If you are on a residential internet connection quite often your ISP will block outgoing email sends by blocking all outbound connections to port 25. This is quite common in the US. Try connecting to a local email server over TCP/IP, or to one on your own internal network.

Grails2.1 Dynamic mail configuration

I am trying to send an email from a grails app. I tried with recommended settings using gmail and it worked fine. I sent mail successfully. But I want to override the username and password dynamically. I don't know how can I do it. Can anybody help?
grails {
mail {
host = "smtp.gmail.com"
port = 465
username = "faruq#gmail.com" // Want to change dynamically like variable ${branch.mail}
password = "12345" // Want to change dynamically like variable ${branch.pass}
props = [
"mail.smtp.auth":"true",
"mail.smtp.socketFactory.port":"465",
"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
"mail.smtp.socketFactory.fallback":"false"
]
}
}
I use this process for overriding the username from the controller
grailsApplication.config.grails.mail.username = Branch.get(2).mail
by this process username successfully changes
here Branch is my domain class and mail is property
but an authentication problem comes up:
javax.mail.AuthenticationFailedException: 535-5.7.8 Username and Password not accepted
Now what can I do?
You can use an external configuration file - put placeholder values in the main Config.groovy
grails {
mail {
host = "smtp.gmail.com"
port = 465
username = "<changeme>"
password = "<changeme>"
props = [
"mail.smtp.auth":"true",
"mail.smtp.socketFactory.port":"465",
"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
"mail.smtp.socketFactory.fallback":"false"
]
}
}
and then override them with the correct values in the external config:
grails {
mail {
username = "faruq#gmail.com"
password = "12345"
}
}
To be able to change the credentials dynamically at run time it gets rather more complicated. Under the covers the mail plugin creates a Spring bean which is an instance of JavaMailSenderImpl to handle the actual sending of emails, and this bean is configured by default with static settings from the config. But at runtime this class appears to call its own getUsername() and getPassword() every time it needs to send a message. So you could replace this bean with your own custom subclass of JavaMailSenderImpl that overrides these methods to pull the details from the request context (code example, not tested, and imports/error handling omitted):
src/groovy/com/example/RequestCredentialsMailSender.groovy
class RequestCredentialsMailSender extends JavaMailSenderImpl {
public String getUsername() {
return RequestContextHolder.requestAttributes?.currentRequest?.mailUsername ?: super.getUsername()
}
public String getPassword() {
return RequestContextHolder.requestAttributes?.currentRequest?.mailPassword ?: super.getPassword()
}
}
You'd have to register this bean in your resources.groovy, and duplicate a fair bit of the configuration from the mail plugin itself, which is less than ideal:
grails-app/conf/spring/resources.groovy
beans = {
mailSender(com.example.RequestCredentialsMailSender) {
def mailConf = application.config.grails.mail
host = mailConf.host
port = mailConf.port
username = mailConf.username // the default, if not set in request
password = mailConf.password
protocol = mailConf.protocol
javaMailProperties = mailConf.props
}
}
Now when you need to send mail from a controller you can do
request.mailUsername = Branch.get(2).mail
request.mailPassword = Branch.get(2).mailPassword
sendMail { ... }
Just wanted to verify Ian's answer and expand it.
In the default Config.groovy file I have the added external config line:
grails.config.locations = [
"file:./${appName}-config.groovy",
"classpath:${appName}-config.groovy"
]
....
// and here is the mail config as above
grails{
mail{
....
In the config file at the root level I have my config file: TestApp-config.groovy (where TestApp is the name of my app) as above:
grails {
mail {
username = "faruq#gmail.com"
password = "12345"
}
}
Didn't need anything past this and it worked great.
We can also use replyTo field if our aim is only to get the reply back on specific Email Id. We can dynamically pass an email id to "replyTo" field and can expect an email back on the same.
Example :
asynchronousMailService.sendMail
{
to ["xyz#gmail.com","pqr#gmail.com"]
subject "Subject Text"
if(ccs) cc ["xyz1#gmail.com","pqr1#gmail.com"]
if(bccs) bcc ["xyz2#gmail.com","pqr2#gmail.com"]
if(replyTo) replyTo "xyz#gmail.com"
if(attachBytes) attachBytes attachBytes
}
NOTE: Adding "replyTo" will only allow us to get the emails back on the specified email-id and will not send the email from the configured email.
It was suitable in my use case. Hope it helps !

WSDL 1.1 Basic question on endpoint salesforce Apex code

From my WSDL I have the following service part:
<service name="BAPI_CUSTOMER_DISPLAYService">
<documentation>SAP Service BAPI_CUSTOMER_DISPLAY via SOAP</documentation>
<port name="BAPI_CUSTOMER_DISPLAYPortType" binding="s0:BAPI_CUSTOMER_DISPLAYBinding">
<soap:address location="http://2.3.4.100:8000/sap/bc/soap/rfc"/>
</port>
</service>
then what will be endpoint reference for this?
I am giving it as "http://2.3.4.100:8000/sap/bc/soap/rfc" in my salesforce client and it gives the following error.
"This service requires client certificate for authentication procedure."
I am sure that i need to give user name and password not knowing how i can set them in my client which is a Apex code.
Help is appreciated.
I imported the Enterprise WSDL and used the uri from the loginResult. Here's some code from my project:
LoginResult loginResult = null; // Login Result (save and make static)
SessionHeader sessionHeader = null; // Session Header (save and make static)
SoapClient soapClient = null; // This is the Enterprise WSDL
SecureStatusClient SecureStatusClient = null; // This is my custom #WebService
// Create Login Request
LoginScopeHeader loginScopeHeader = new LoginScopeHeader
{
organizationId = configuration["OrganizationId"],
portalId = configuration["PortalId"]
};
// Call Login Service
string userName = configuration["UserName"];
string password = configuration["Password"];
string securityToken = configuration["SecurityToken"];
using (SoapClient loginClient = new SoapClient())
{
loginResult = loginClient.login(loginScopeHeader, userName, password + securityToken);
if (result.passwordExpired)
{
string message = string.Format("Salesforce.com password expired for user {0}", userName);
throw new Exception(message);
}
}
// Create the SessionHeader
sessionHeader = new SessionHeader { sessionId = loginResult.sessionId };
// Create the SoapClient to use for queries/updates
soapClient = new SoapClient();
soapClient.Endpoint.Address = new EndpointAddress(loginResult.serverUrl);
// Create the SecureStatusServiceClient
secureStatusClient = new SecureStatusServiceClient();
Uri apexUri = new Uri(SoapClient.Endpoint.Address.Uri, "/services/Soap/class/SecureStatusService");
secureStatusClient.Endpoint.Address = new EndpointAddress(apexUri);

Resources