【问题标题】:Web Service Call for ADFS 2.0 AuthenticationADFS 2.0 身份验证的 Web 服务调用
【发布时间】:2015-08-30 22:01:53
【问题描述】:

我有一个使用 ADFS 2.0 进行身份验证的 ASP.NET MVC Web 应用程序。一些 MVC 控制器操作充当通用 Web 服务端点,接收和提供 JSON。我想构建一个自动执行某些应用程序功能的客户端应用程序。为此,我正在构建一个 API 访问库,它将向 Web 服务发出 HTTP 请求以完成其工作。

我一直在尝试进行身份验证。我正在为 ADFS 2.0 使用表单身份验证,所以我不应该能够简单地使用有效的用户名和密码模拟表单帖子以生成令牌吗?我没有收到令牌,而是得到了登录页面。我不确定我还需要做什么才能验证我的请求。我的代码粘贴在下面……但也许我做错了,还有一些我不知道的事情?

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。我得到了错误:

无法打开安全通道,因为与 远程端点失败。这可能是由于不存在或错误 EndpointAddress 中指定的 EndpointIdentity 用于创建 渠道。请验证指定或暗示的 EndpointIdentity EndpointAddress 正确识别远程端点。

        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;

【问题讨论】:

    标签: asp.net asp.net-mvc wcf forms-authentication adfs2.0


    【解决方案1】:

    问题很可能出在:string url = "{url of website}";。和/或 POST 中缺少参数。

    它不应该只是任何 URL。它应该是格式正确的 WS-Federation 请求。使用时间戳等。通常/有时(在当前的 ADFS 中)这是一个两步过程。首先是正常请求,然后是真正的(uid+pwd)身份验证。两者都在适当的位置使用适当的 WS-Fed 参数。只有 uid 和 pwd 是不够的。

    现在是显而易见的答复,没有侮辱的意思:我建议您跟踪常规登录过程,然后将这些确切的 HTTP 请求与您的请求进行比较。

    【讨论】:

    • 没有受到侮辱。我正在慢慢地将所有这些拼凑在一起,而我对这里的基本部分一无所知。有很多东西要研究——WS-Federation、SAML、WIF、WCF、ADFS 2.0 等。你的帖子很有帮助,谢谢。登录过程的棘手之处在于它所做的只是提交一个表单,至少从我可以跟踪的内容来看。我以编程方式构建的 POST 请求试图完美地复制表单提交,但我认为我没有使用所有 WS-Federation 参数。我没有看到它提交一个大的 XML SOAP 请求,我认为 WS-Federation 是基于它的。
    • 我只谈到了 WS-Fed 被动。我没有谈论活动(SOAP 和微软世界中的 WCF)。 SOAP 版本通常使用 WS-Trust 名称来标识。但是 WS-Trust/active 不是我的主题/专长....
    • 对于 PASSIVE:在您的帖子中应该有如下内容: wa=wsignin1.0 wtrealm=AppEntityID wctx=whatever-you-need wct=2011-04-04T20:54:33Z
    【解决方案2】:

    默认情况下,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()
    }
    

    我想解决你的问题。

    【讨论】:

      【解决方案3】:

      您必须先向 ADFS 请求以识别您的身份,然后接受一个令牌, 和 然后将请求发送到您的应用程序,包括里面的令牌(作为 cookie)

      我建议你使用 Fiddler 捕获浏览器发送的请求,并查看您的请求中缺少哪些部分

      【讨论】:

        猜你喜欢
        • 2018-06-17
        • 2013-08-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-11
        • 2019-06-24
        相关资源
        最近更新 更多