使用HttpWebRequest进行ADFS身份验证

时间:2018-05-18 19:07:48

标签: c# httpwebrequest adfs webrequest windows-integrated-auth

我正在开发一个必须连接到我们的O365环境的应用程序。我们与O365联合,因此用户可以使用其正常的网络凭据访问服务。

该应用程序允许用户在连接到本地LAN时使用用户名/密码或集成的Windows身份验证进行连接。用户名/密码组合部分工作正常,但是当我使用默认凭据将Web请求传递给ADFS服务器时,我以网页的形式从ADFS获得响应,表示Web浏览器不支持JavaScript:

<div id="noScript" style="position:static; width:100%; height:100%; z-index:100">
    <h1>JavaScript required</h1>
    <p>JavaScript is required. This web browser does not support JavaScript or JavaScript in this web browser is not enabled.</p>
    <p>To find out if your web browser supports JavaScript or to enable JavaScript, see web browser help.</p>
</div>

我不确定为什么我会这样做,而不是自动验证。我已经包含了以下方法的代码:

    private string GetAdfsSAMLTokenWinAuth()
    {
        // Makes a seurity token request to the corporate ADFS proxy integrated auth endpoint.
        // If the user is logged on to a machine joined to the corporate domain with her Windows credentials and connected
        // to the corporate network Kerberos automatically takes care of authenticating the security token request to ADFS.
        // The logon token is used to talk to MSO STS to get an O365 service token that can then be used to sign into SPO.

        string samlAssertion = null;

        //HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(this.adfsIntegratedAuthUrl);
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.adfsIntegratedAuthUrl);
        request.UseDefaultCredentials = true; // use the default credentials so Kerberos can take care of authenticating our request

        // TODO: This fails becuase the request doesn't support JavaScript... Need to find a way around this...
        byte[] responseData = HttpHelper.SendHttpRequest(
            this.adfsIntegratedAuthUrl,
            "GET",
            null,
            "text/html; charset=utf-8",
            request);

        if (responseData != null)
        {
            try
            {
                StreamReader sr = new StreamReader(new MemoryStream(responseData), Encoding.GetEncoding("utf-8"));
                integratedauthresponse = sr.ReadToEnd();
                XPathNavigator nav = new XPathDocument(sr).CreateNavigator();
                XPathNavigator wresult = nav.SelectSingleNode("/html/body/form/input[@name='wresult']");
                if (wresult != null)
                {
                    responsedata = true;
                    string RequestSecurityTokenResponseText = wresult.GetAttribute("value", "");

                    sr = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(RequestSecurityTokenResponseText)));
                    nav = new XPathDocument(sr).CreateNavigator();
                    XmlNamespaceManager nsMgr = new XmlNamespaceManager(nav.NameTable);
                    nsMgr.AddNamespace("t", "http://schemas.xmlsoap.org/ws/2005/02/trust");
                    XPathNavigator requestedSecurityToken = nav.SelectSingleNode("//t:RequestedSecurityToken", nsMgr);

                    // Ensure whitespace is reserved
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(requestedSecurityToken.InnerXml);
                    doc.PreserveWhitespace = true;
                    samlAssertion = doc.InnerXml;
                }
            }
            catch
            {
                // we failed to sign the user using integrated Windows Auth... *sob*
            }
        }
        methodused = "Windows Authentication";
        return samlAssertion;
    }

有没有人有类似的经历?如果是这样,你是如何解决它的?我不认为我可以欺骗兼容JavaScript,但这并不重要......感谢任何人可以给予的任何建议。

1 个答案:

答案 0 :(得分:0)

我能够使用以下代码使用集成身份验证从ADFS获取令牌:

    public GenericXmlSecurityToken GetToken()
    {
        WS2007HttpBinding binding = new WS2007HttpBinding(SecurityMode.Transport);
        binding.Security.Message.EstablishSecurityContext = false;
        binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
        WSTrustChannelFactory factory = new WSTrustChannelFactory((binding), new EndpointAddress(stsEndpoint));
        factory.TrustVersion = TrustVersion.WSTrustFeb2005;
        factory.Credentials.SupportInteractive = false;
        var rst = new RequestSecurityToken
        {
            RequestType = RequestTypes.Issue,
            AppliesTo = new EndpointReference(realm),
            KeyType = KeyTypes.Bearer
        };
        IWSTrustChannelContract channel = factory.CreateChannel();
        return channel.Issue(rst) as GenericXmlSecurityToken;
    }