ADFS 2.0 身份验证的 Web 服务调用
Web Service Call for ADFS 2.0 Authentication
我有一个 ASP.NET MVC 网络应用程序,它使用 ADFS 2.0 进行身份验证。一些 MVC 控制器操作充当通用 Web 服务端点,接收和服务 JSON。我想构建一个客户端应用程序来自动执行应用程序的某些功能。为此,我正在构建一个 API 访问库,它将向 Web 服务发出 HTTP 请求以完成其工作。
我一直在尝试进行身份验证。我正在为 ADFS 2.0 使用表单身份验证,所以我不应该能够简单地使用有效的用户名和密码模拟表单 post 以生成令牌吗?我没有收到返回的令牌,而是获得了登录页面。我不确定我还需要做什么来验证我的请求。我的代码粘贴在下面......但也许我做的完全错了,还有一些我不知道的东西?
string postData = string.Empty;
postData += "ctl00$ContentPlaceHolder1$UsernameTextBox=" + username + "&";
postData += "ctl00$ContentPlaceHolder1$PasswordTextBox=" + password;
postData += "&AuthMethod=FormsAuthentication";// Submit the data back
string url = "{url of website}";
HttpWebRequest getTokenRequest = WebRequest.Create(url) as HttpWebRequest;
getTokenRequest.CookieContainer = cookies;
getTokenRequest.ContentType = "application/x-www-form-urlencoded";
getTokenRequest.ContentLength = postData.Length;
getTokenRequest.Method = "POST";
// post the data to the request
using (StreamWriter sw = new StreamWriter(getTokenRequest.GetRequestStream()))
{
sw.Write(postData);
sw.Flush();
sw.Close();
}
HttpWebResponse getTokenResponse = (HttpWebResponse)getTokenRequest.GetResponse();
string responseString = ResponseToString(getTokenResponse);
我也试过另一种方法,也没有用。这使用 WCF。我收到错误:
Secure channel cannot be opened because security negotiation with the
remote endpoint has failed.This may be due to absent or incorrectly
specified EndpointIdentity in the EndpointAddress used to create the
channel. Please verify the EndpointIdentity specified or implied by
the EndpointAddress correctly identifies the remote endpoint.
const string relyingPartyId = "[ID]"; //ID of the relying party in AD FS
const string adfsEndpoint = "https://[server]/adfs/services/trust/13/usernamemixed"; //url to hit - username & pw?
const string certSubject = "[subject]"; //?
//Setup the connection to ADFS
var factory = new Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannelFactory(
new WindowsWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress(adfsEndpoint));
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = "[un]";
factory.Credentials.UserName.Password = "[pw]";
//Setup the request object
var rst = new Microsoft.IdentityModel.Protocols.WSTrust.RequestSecurityToken
{
RequestType = Microsoft.IdentityModel.SecurityTokenService.RequestTypes.Issue,
KeyType = Microsoft.IdentityModel.SecurityTokenService.KeyTypes.Bearer,
AppliesTo = new EndpointAddress(relyingPartyId)
};
//Open a connection to ADFS and get a token for the logged in user
var channel = factory.CreateChannel();
//added to solve a trust certificate issue - bad from a security perspective
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
(se, cert, chain, sslerror) =>
{
return true;
};
var genericToken = channel.Issue(rst) as GenericXmlSecurityToken;
问题很可能出在:string url = "{url of website}";
。 And/or POST 中缺少参数。
它不应该只是任何 URL。它应该是格式正确的 WS-Federation 请求。使用时间戳等。和 normally/sometimes(在当前的 ADFS 中)这是一个两步过程。首先是正常请求,然后是真正的(uid+pwd)认证。两者都在适当的位置使用适当的 WS-Fed 参数。只有uid和pwd是不够的。
现在是明显的答复,没有侮辱的意思:我建议您跟踪常规登录过程,然后将这些确切的 HTTP 请求与您的请求进行比较。
ASP.NET 中的表单身份验证默认依赖于 cookie。一旦用户登录到应用程序,运行时就可以在浏览器上发出一个 cookie。然后,浏览器会将 cookie 与每个后续请求一起发送到应用程序。 ASP.NET 将看到 cookie 并知道用户已经通过身份验证并且不需要再次登录。
所以无论有没有WebRequest.Credentials
你都需要这样的东西:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("yoururl");
request.CookieContainer = new CookieContainer();
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
byte[] bytes = Encoding.UTF8.GetBytes(yourpostdata);//as user pass
request.ContentLength = bytes.Length;
//or use credentials
//request.Credentials = new NetworkCredential("UserName", "PassWord");
using (Stream streamOut = request.GetRequestStream())
{
streamOut.Write(bytes, 0, bytes.Length);
streamOut.Close();
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
Stream stream = response.GetResponseStream();
StreamReader sr = new StreamReader(stream);
//save cookie to reuse
//var _cookie = response.Cookies;
string responseString = sr.ReadToEnd()
}
我想解决你的问题。
您必须首先请求 ADFS 识别您的身份,接受返回的令牌,
和
然后将请求发送到您的应用程序,包括内部令牌(作为 cookie)
我建议你使用
Fiddler 捕获浏览器发送的请求,并查看您的请求缺少哪些部分
我有一个 ASP.NET MVC 网络应用程序,它使用 ADFS 2.0 进行身份验证。一些 MVC 控制器操作充当通用 Web 服务端点,接收和服务 JSON。我想构建一个客户端应用程序来自动执行应用程序的某些功能。为此,我正在构建一个 API 访问库,它将向 Web 服务发出 HTTP 请求以完成其工作。
我一直在尝试进行身份验证。我正在为 ADFS 2.0 使用表单身份验证,所以我不应该能够简单地使用有效的用户名和密码模拟表单 post 以生成令牌吗?我没有收到返回的令牌,而是获得了登录页面。我不确定我还需要做什么来验证我的请求。我的代码粘贴在下面......但也许我做的完全错了,还有一些我不知道的东西?
string postData = string.Empty;
postData += "ctl00$ContentPlaceHolder1$UsernameTextBox=" + username + "&";
postData += "ctl00$ContentPlaceHolder1$PasswordTextBox=" + password;
postData += "&AuthMethod=FormsAuthentication";// Submit the data back
string url = "{url of website}";
HttpWebRequest getTokenRequest = WebRequest.Create(url) as HttpWebRequest;
getTokenRequest.CookieContainer = cookies;
getTokenRequest.ContentType = "application/x-www-form-urlencoded";
getTokenRequest.ContentLength = postData.Length;
getTokenRequest.Method = "POST";
// post the data to the request
using (StreamWriter sw = new StreamWriter(getTokenRequest.GetRequestStream()))
{
sw.Write(postData);
sw.Flush();
sw.Close();
}
HttpWebResponse getTokenResponse = (HttpWebResponse)getTokenRequest.GetResponse();
string responseString = ResponseToString(getTokenResponse);
我也试过另一种方法,也没有用。这使用 WCF。我收到错误:
Secure channel cannot be opened because security negotiation with the remote endpoint has failed.This may be due to absent or incorrectly specified EndpointIdentity in the EndpointAddress used to create the channel. Please verify the EndpointIdentity specified or implied by the EndpointAddress correctly identifies the remote endpoint.
const string relyingPartyId = "[ID]"; //ID of the relying party in AD FS
const string adfsEndpoint = "https://[server]/adfs/services/trust/13/usernamemixed"; //url to hit - username & pw?
const string certSubject = "[subject]"; //?
//Setup the connection to ADFS
var factory = new Microsoft.IdentityModel.Protocols.WSTrust.WSTrustChannelFactory(
new WindowsWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress(adfsEndpoint));
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.UserName.UserName = "[un]";
factory.Credentials.UserName.Password = "[pw]";
//Setup the request object
var rst = new Microsoft.IdentityModel.Protocols.WSTrust.RequestSecurityToken
{
RequestType = Microsoft.IdentityModel.SecurityTokenService.RequestTypes.Issue,
KeyType = Microsoft.IdentityModel.SecurityTokenService.KeyTypes.Bearer,
AppliesTo = new EndpointAddress(relyingPartyId)
};
//Open a connection to ADFS and get a token for the logged in user
var channel = factory.CreateChannel();
//added to solve a trust certificate issue - bad from a security perspective
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
(se, cert, chain, sslerror) =>
{
return true;
};
var genericToken = channel.Issue(rst) as GenericXmlSecurityToken;
问题很可能出在:string url = "{url of website}";
。 And/or POST 中缺少参数。
它不应该只是任何 URL。它应该是格式正确的 WS-Federation 请求。使用时间戳等。和 normally/sometimes(在当前的 ADFS 中)这是一个两步过程。首先是正常请求,然后是真正的(uid+pwd)认证。两者都在适当的位置使用适当的 WS-Fed 参数。只有uid和pwd是不够的。
现在是明显的答复,没有侮辱的意思:我建议您跟踪常规登录过程,然后将这些确切的 HTTP 请求与您的请求进行比较。
ASP.NET 中的表单身份验证默认依赖于 cookie。一旦用户登录到应用程序,运行时就可以在浏览器上发出一个 cookie。然后,浏览器会将 cookie 与每个后续请求一起发送到应用程序。 ASP.NET 将看到 cookie 并知道用户已经通过身份验证并且不需要再次登录。
所以无论有没有WebRequest.Credentials
你都需要这样的东西:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("yoururl");
request.CookieContainer = new CookieContainer();
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
byte[] bytes = Encoding.UTF8.GetBytes(yourpostdata);//as user pass
request.ContentLength = bytes.Length;
//or use credentials
//request.Credentials = new NetworkCredential("UserName", "PassWord");
using (Stream streamOut = request.GetRequestStream())
{
streamOut.Write(bytes, 0, bytes.Length);
streamOut.Close();
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
Stream stream = response.GetResponseStream();
StreamReader sr = new StreamReader(stream);
//save cookie to reuse
//var _cookie = response.Cookies;
string responseString = sr.ReadToEnd()
}
我想解决你的问题。
您必须首先请求 ADFS 识别您的身份,接受返回的令牌, 和 然后将请求发送到您的应用程序,包括内部令牌(作为 cookie)
我建议你使用 Fiddler 捕获浏览器发送的请求,并查看您的请求缺少哪些部分