[英]Web Service Call for ADFS 2.0 Authentication
I have an ASP.NET MVC web app that uses ADFS 2.0 for authentication. 我有一个使用ADFS 2.0进行身份验证的ASP.NET MVC Web应用程序。 Some of the MVC controller actions function as generic web service endpoints, receiving and serving JSON. 一些MVC控制器动作用作通用Web服务端点,接收和提供JSON。 I want to build a client application that automates some of the app's functionality. 我想构建一个自动化应用程序功能的客户端应用程序。 For that purpose, I am building an API access library that will make HTTP requests to the web service in order to do its job. 为此,我正在构建一个API访问库,它将向Web服务发出HTTP请求以完成其工作。
I am stuck at trying to authenticate. 我被困在试图验证。 I am using forms authentication for ADFS 2.0, so shouldn't I be able to simply simulate the form post with a valid username and password in order to generate a token? 我正在使用ADFS 2.0的表单身份验证,所以我不能简单地使用有效的用户名和密码模拟表单帖子以生成令牌? Instead of receiving a token back, I just get the login page. 我没有收到令牌,而只是获取登录页面。 I am not sure what else I need to do in order to authenticate my request. 我不确定我需要做什么才能验证我的请求。 My code is pasted below... but maybe I'm doing it totally wrong and there's something I don't know about? 我的代码粘贴在下面...但也许我做错了,而且我不知道的是什么?
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);
I have also tried another approach, which also doesn't work. 我也尝试过另一种方法,但也行不通。 This uses WCF. 这使用WCF。 I get the error: 我收到错误:
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. 无法打开安全通道,因为与远程端点的安全协商失败。这可能是由于在用于创建通道的EndpointAddress中缺少或错误指定了EndpointIdentity。 Please verify the EndpointIdentity specified or implied by the EndpointAddress correctly identifies the remote endpoint. 请验证EndpointAddress指定或暗示的EndpointIdentity是否正确标识远程端点。
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;
Most likely the problem is in: string url = "{url of website}";
最有可能的问题是: string url = "{url of website}";
. 。 And/or missing parameters in the POST. 和/或POST中缺少参数。
It shouldn't be just any URL. 它不应该只是任何URL。 It should be a properly formatted WS-Federation request. 它应该是格式正确的WS-Federation请求。 With timestamps etc. etc. And normally/sometimes (in current ADFS) it is a two step process. 有时间戳等等。通常/有时(在当前的ADFS中)它是一个两步过程。 First the normal request, then the real (uid+pwd) authentication. 首先是正常请求,然后是真实(uid + pwd)认证。 Both with proper WS-Fed parameters in the proper places. 两者都在适当的位置使用适当的WS-Fed参数。 Only uid and pwd is not enough. 只有uid和pwd是不够的。
Now the obvious reply, no insult intended: I suggest you make a trace of the regular logon process and then compare those exact HTTP requests with your requests. 现在明显的答复,没有任何侮辱:我建议您跟踪常规登录过程,然后将这些确切的HTTP请求与您的请求进行比较。
Forms Authentication in ASP.NET relies on cookies by default. ASP.NET中的表单身份验证默认情况下依赖于Cookie。 Once the user is signed in to an Application the runtime can issue a cookie on the browser. 用户登录到应用程序后,运行时可以在浏览器上发出cookie。 The browser will then send the cookie with every subsequent request to the application. 然后,浏览器将向每个后续请求发送cookie给应用程序。 ASP.NET will see the cookie and know that the user is already authenticate and does not need to sign on again. ASP.NET将看到cookie并知道用户已经过身份验证,无需再次登录。
So you need something like this with or without WebRequest.Credentials
: 无论有没有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()
}
I wish to solve your problem. 我希望解决你的问题。
You have to first request to ADFS to identify your self , accept a token back, and Than send the request to your application including the token inside (as a cookie) 您必须首先请求ADFS识别您的自己,接受令牌,然后将请求发送到您的应用程序,包括内部令牌(作为cookie)
I suggest you use Fiddler to capture the request sent from Browser, and see which parts of your request are missing 我建议您使用Fiddler捕获从浏览器发送的请求,并查看您的请求的哪些部分缺失
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.