原來SmtpClient的Credentials有這GGSAPI、Login、NTLM、WDigest四種。
Posted on 2007-11-28 20:29 黃偉榮 阅读(4480) 评论(11) 编辑 收藏 举报
今天在寫SmtpClient寄Mail,用自己架的MailServer正常,但用對方的MailServer都是失敗,發現是在驗證方面出現,但Outlook寄又是正常,找不出結果下使用封包監聽軟體(Wireshark)去看這SmtpClient與Outlook寄出的有什麼不同,最後使用Reflector找出怎麼設定驗證方式。
這是測試的專案
SmtpTest.rar
這是捕捉Outlook封包內容(塗黑的是隱私的資訊如Host、UserID等)
紅色:本機送出的文字
藍色:MailServer回傳的文字
這是補捉SmtpClient的封包內容
從中發現Auth outlock是用Login(只用Base64加密),而SmtpClient是用GSSAPI(上網查是Kerberos的一種,Win2000(沒升級SP2)還不支源這種)。
由此可知,會錯的原因是客戶的MailServer,用GSSAPI驗證會失敗,可以要怎麼改StmpClient方式呢?
今天以前我只知道用這樣的方式 : smtpClient.Credentials = new NetworkCredential(userNameTextBox.Text, passwordTextBox.Text);
Google查也沒有找到更改験證的方法,只好用Reflector看看他是怎麼實作的。
注:下列都省略System.Net.Mail的命名空間
查到是在SmtpConnection.GetConnection方法中的(Reflector沒有行號)
....
NetworkCredential credential = this.credentials.GetCredential(host, port, this.authenticationModules[i].AuthenticationType);
if (credential != null)
{
....
}
....
這幾行去決定驗證方法
而authenticationModules屬性是ISmtpAuthenticationModule陣列
成員有這四個
SmtpNegotiateAuthenticationModule AuthenticationType=gssapi
SmtpNtlmAuthenticationModule AuthenticationType=ntlm
SmtpNtlmAuthenticationModule AuthenticationType=WDigest
SmtpNtlmAuthenticationModule AuthenticationType=login
會跑四次用SmtpClient.Credentials.GetCredential方法檢查是否支援本Module。
而SmtpClient.Credentials是ICredentialsByHost介面
實作ICredentialsByHost的有這二個
CredentialCache
NetworkCredential
而NetworkCredential
public NetworkCredential GetCredential(string host, int port, string authenticationType)
{
return this;
}
不管什麼Module都支援(所以使用第一個Module SmtpNegotiateAuthenticationModule)。
而CredentialCache
public NetworkCredential GetCredential(string host, int port, string authenticationType)
{
NetworkCredential credential = null;
IDictionaryEnumerator enumerator = this.cacheForHosts.GetEnumerator();
while (enumerator.MoveNext())
{
CredentialHostKey key = (CredentialHostKey) enumerator.Key;
if (key.Match(host, port, authenticationType))
{
credential = (NetworkCredential) enumerator.Value;
}
}
return credential;
}
會比較AuthenticationType
結語
所以StmpClient要改變驗證方式的話要用CredentialCache類別
CredentialCache myCache = new CredentialCache();
myCache.Add(hostTextBox.Text, 25, "login", new NetworkCredential(userNameTextBox.Text, passwordTextBox.Text));
smtpClient.Credentials = myCache;
第三個參數不能打錯(打錯就Match不到了,視同沒有驗證),有這下列四種(從Module看出),不分大小寫。
gssapi
ntlm
WDigest
login
這樣就跟用Outlook寄出的封包內容一模一樣了。
這是測試的專案
SmtpTest.rar
這是捕捉Outlook封包內容(塗黑的是隱私的資訊如Host、UserID等)
紅色:本機送出的文字
藍色:MailServer回傳的文字
這是補捉SmtpClient的封包內容
從中發現Auth outlock是用Login(只用Base64加密),而SmtpClient是用GSSAPI(上網查是Kerberos的一種,Win2000(沒升級SP2)還不支源這種)。
由此可知,會錯的原因是客戶的MailServer,用GSSAPI驗證會失敗,可以要怎麼改StmpClient方式呢?
今天以前我只知道用這樣的方式 : smtpClient.Credentials = new NetworkCredential(userNameTextBox.Text, passwordTextBox.Text);
Google查也沒有找到更改験證的方法,只好用Reflector看看他是怎麼實作的。
注:下列都省略System.Net.Mail的命名空間
查到是在SmtpConnection.GetConnection方法中的(Reflector沒有行號)
....
NetworkCredential credential = this.credentials.GetCredential(host, port, this.authenticationModules[i].AuthenticationType);
if (credential != null)
{
....
}
....
這幾行去決定驗證方法
而authenticationModules屬性是ISmtpAuthenticationModule陣列
成員有這四個
SmtpNegotiateAuthenticationModule AuthenticationType=gssapi
SmtpNtlmAuthenticationModule AuthenticationType=ntlm
SmtpNtlmAuthenticationModule AuthenticationType=WDigest
SmtpNtlmAuthenticationModule AuthenticationType=login
會跑四次用SmtpClient.Credentials.GetCredential方法檢查是否支援本Module。
而SmtpClient.Credentials是ICredentialsByHost介面
實作ICredentialsByHost的有這二個
CredentialCache
NetworkCredential
而NetworkCredential
public NetworkCredential GetCredential(string host, int port, string authenticationType)
{
return this;
}
不管什麼Module都支援(所以使用第一個Module SmtpNegotiateAuthenticationModule)。
而CredentialCache
public NetworkCredential GetCredential(string host, int port, string authenticationType)
{
NetworkCredential credential = null;
IDictionaryEnumerator enumerator = this.cacheForHosts.GetEnumerator();
while (enumerator.MoveNext())
{
CredentialHostKey key = (CredentialHostKey) enumerator.Key;
if (key.Match(host, port, authenticationType))
{
credential = (NetworkCredential) enumerator.Value;
}
}
return credential;
}
會比較AuthenticationType
結語
所以StmpClient要改變驗證方式的話要用CredentialCache類別
CredentialCache myCache = new CredentialCache();
myCache.Add(hostTextBox.Text, 25, "login", new NetworkCredential(userNameTextBox.Text, passwordTextBox.Text));
smtpClient.Credentials = myCache;
第三個參數不能打錯(打錯就Match不到了,視同沒有驗證),有這下列四種(從Module看出),不分大小寫。
gssapi
ntlm
WDigest
login
這樣就跟用Outlook寄出的封包內容一模一樣了。