使用SSO

时间:2017-02-26 15:38:37

标签: asp.net sharepoint single-sign-on office365 adfs

我正在尝试连接到一个sharepoint网站,该网站首先重定向到Microsoft登录页面/ office 365登录页面,然后一旦我输入我的公司电子邮件ID,然后将其重定向到我的公司ADFS登录页面,其中已存在电子邮件ID文本框和密码是必需的。我在这里尝试的是避免登录页面,即(第一个microsoft / 0ffice365登录页面,然后到我公司的sso登录页面)并直接打开sharepoint在线网站,没有任何重定向/提示登录信用。我正在尝试使用asp.net实现这一目标。

ADFS SSO: - https://sso.mycompany.com/adfs/services/trust/13/usernamemixed

RP信任网址: - https://login.microsoftonline.com/extSTS.srf

SharePoint在线网址: - https://mycompanyo365.sharepoint.com/sites/procC/SitePages/Index.aspx

在这里,我可以使用.net连接到我公司的ADFS,并从ADFS获取SAML令牌。但是当我将令牌传递给sharepoint网站时,我的响应状态为OK,但我没有收到FedAuth cookie。

步骤: -

  • 开发了一个包含用户凭据的.net页面,即(用户 名称和密码)。
  • 以编程方式我们将用户凭据传递给ADFS。
  • 然后,一旦用户通过身份验证,我们就会收到SMAL令牌。
  • 然后我们将SAML令牌发布到SharePoint网站,但没有回复Fedauth cookie(即使状态代码为200(OK))。

页面加载具有用户信用并重定向到sharepoint站点。

protected void Page_Load(object sender, EventArgs e)
        {
            UserName = UserNmae;
            password = Password;
            ConnectAdfsToGetSamlToken();
            Response.Redirect("https://Mycompanyo365.sharepoint.com/sites/ProcC/SitePages/Index.aspx", false);
        }

连接ADFS并获取SAML令牌

 #region Connect Adfs To Get SamlToken to pass in fedauth cookies
        public void ConnectAdfsToGetSamlToken()
        {
                // STS endpoint...
                WSTrustChannelFactory factory = new WSTrustChannelFactory(new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential), new EndpointAddress("https://sso.mycompany.com/adfs/services/trust/13/usernamemixed"));
                factory.TrustVersion = TrustVersion.WSTrust13;

                // Username and Password here...
                factory.Credentials.UserName.UserName = UserName;
                factory.Credentials.UserName.Password = password;

                //Request creation with relaying party...
                RequestSecurityToken rst = new RequestSecurityToken
                {
                    RequestType = Microsoft.IdentityModel.Protocols.WSTrust.WSTrust13Constants.RequestTypes.Issue,
                    AppliesTo = new EndpointAddress("https://login.microsoftonline.com/extSTS.srf"),
                    KeyType = Microsoft.IdentityModel.Protocols.WSTrust.WSTrust13Constants.KeyTypes.Bearer,
                };

                IWSTrustChannelContract channel = factory.CreateChannel();

                //Saml token created...
                GenericXmlSecurityToken genericToken = channel.Issue(rst) as GenericXmlSecurityToken;

                //cookie  created...
                Cookie fedauthcookiesdata = TransformSamlTokenToFedAuth(genericToken.TokenXml.OuterXml, "https://mycompanyo365.sharepoint.com/sites/ProcC/SitePages/Index.aspx");

                //Cookie assigned...
                Response.Cookies["FedAuth"].Domain = "mycompany.com";
                Response.Cookies["FedAuth"].Expires = fedauthcookiesdata.Expires;
                Response.Cookies["FedAuth"].HttpOnly = fedauthcookiesdata.HttpOnly;
                Response.Cookies["FedAuth"].Name = fedauthcookiesdata.Name;
                Response.Cookies["FedAuth"].Path = fedauthcookiesdata.Path;
                Response.Cookies["FedAuth"].Secure = fedauthcookiesdata.Secure;
                Response.Cookies["FedAuth"].Value = fedauthcookiesdata.Value;
        }
        #endregion

转移SMAL以获取FedAuth Cookie

 #region Transform Saml Token To get FedAuth cookies
        internal Cookie TransformSamlTokenToFedAuth(string samlToken, string samlSite)
        {
            samlToken = WrapInSoapMessage(samlToken, samlSite);
            string samlServer = samlSite.EndsWith("/") ? samlSite : samlSite + "/";
            Uri samlServerRoot = new Uri(samlServer);
            var sharepointSite = new
            {
                Wctx = "https://mycompanyo365.sharepoint.com/sites/ProcC/SitePages/Index.aspx",
                Wtrealm = "urn:federation:MicrosoftOnline",
                Wreply = String.Format("{0}://{1}/_trust/", samlServerRoot.Scheme, samlServerRoot.Host)
            };

            string stringData = String.Format("wa=wsignin1.0&wctx={0}&wresult={1}", HttpUtility.UrlEncode(sharepointSite.Wctx), HttpUtility.UrlEncode(samlToken));
            Cookie fedAuthCookieValue;

            HttpWebRequest sharepointRequest = HttpWebRequest.Create("https://mycompanyo365.sharepoint.com/_trust/default.aspx/") as HttpWebRequest;
            sharepointRequest.Method = "POST";
            sharepointRequest.ContentType = "application/x-www-form-urlencoded";
            sharepointRequest.CookieContainer = new CookieContainer();
            sharepointRequest.AllowAutoRedirect = false; // This is important
            Stream newStream = sharepointRequest.GetRequestStream();

            byte[] data = Encoding.UTF8.GetBytes(stringData);
            newStream.Write(data, 0, data.Length);
            newStream.Close();

            HttpWebResponse webResponse = sharepointRequest.GetResponse() as HttpWebResponse;
            string[] strCookies = webResponse.Headers.GetValues(1);
            fedAuthCookieValue = webResponse.Cookies["FedAuth"];
            return fedAuthCookieValue;

        }
        #endregion

包装肥皂消息

#region wrap in soap message
            /// <summary>
            /// Wrap SAML token in RequestSecurityTokenResponse soap message
            /// </summary>
            /// <param name="stsResponse">SAML token obtained via active authentication to ADFS</param>
            /// <param name="relyingPartyIdentifier">Identifier of the ADFS relying party that we're hitting</param>
            /// <returns>RequestSecurityTokenResponse soap message</returns>
            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "System.Xml.XmlDocument.CreateTextNode(System.String)")]
            private string WrapInSoapMessage(string stsResponse, string relyingPartyIdentifier)
            {
                try
                {
                    XmlDocument samlAssertion = new XmlDocument();
                    samlAssertion.PreserveWhitespace = true;
                    samlAssertion.LoadXml(stsResponse);

                    //Select the book node with the matching attribute value.
                    String notBefore = samlAssertion.DocumentElement.FirstChild.Attributes["NotBefore"].Value;
                    String notOnOrAfter = samlAssertion.DocumentElement.FirstChild.Attributes["NotOnOrAfter"].Value;

                    XmlDocument soapMessage = new XmlDocument();
                    XmlElement soapEnvelope = soapMessage.CreateElement("t", "RequestSecurityTokenResponse", "http://schemas.xmlsoap.org/ws/2005/02/trust");
                    soapMessage.AppendChild(soapEnvelope);
                    XmlElement lifeTime = soapMessage.CreateElement("t", "Lifetime", soapMessage.DocumentElement.NamespaceURI);
                    soapEnvelope.AppendChild(lifeTime);
                    XmlElement created = soapMessage.CreateElement("wsu", "Created", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
                    XmlText createdValue = soapMessage.CreateTextNode(notBefore);
                    created.AppendChild(createdValue);
                    lifeTime.AppendChild(created);
                    XmlElement expires = soapMessage.CreateElement("wsu", "Expires", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
                    XmlText expiresValue = soapMessage.CreateTextNode(notOnOrAfter);
                    expires.AppendChild(expiresValue);
                    lifeTime.AppendChild(expires);
                    XmlElement appliesTo = soapMessage.CreateElement("wsp", "AppliesTo", "http://schemas.xmlsoap.org/ws/2004/09/policy");
                    soapEnvelope.AppendChild(appliesTo);
                    XmlElement endPointReference = soapMessage.CreateElement("wsa", "EndpointReference", "http://www.w3.org/2005/08/addressing");
                    appliesTo.AppendChild(endPointReference);
                    XmlElement address = soapMessage.CreateElement("wsa", "Address", endPointReference.NamespaceURI);
                    XmlText addressValue = soapMessage.CreateTextNode(relyingPartyIdentifier);
                    address.AppendChild(addressValue);
                    endPointReference.AppendChild(address);
                    XmlElement requestedSecurityToken = soapMessage.CreateElement("t", "RequestedSecurityToken", soapMessage.DocumentElement.NamespaceURI);
                    XmlNode samlToken = soapMessage.ImportNode(samlAssertion.DocumentElement, true);
                    requestedSecurityToken.AppendChild(samlToken);
                    soapEnvelope.AppendChild(requestedSecurityToken);
                    XmlElement tokenType = soapMessage.CreateElement("t", "TokenType", soapMessage.DocumentElement.NamespaceURI);
                    XmlText tokenTypeValue = soapMessage.CreateTextNode("urn:oasis:names:tc:SAML:1.0:assertion");
                    tokenType.AppendChild(tokenTypeValue);
                    soapEnvelope.AppendChild(tokenType);
                    XmlElement requestType = soapMessage.CreateElement("t", "RequestType", soapMessage.DocumentElement.NamespaceURI);
                    XmlText requestTypeValue = soapMessage.CreateTextNode("http://schemas.xmlsoap.org/ws/2005/02/trust/Issue");
                    requestType.AppendChild(requestTypeValue);
                    soapEnvelope.AppendChild(requestType);
                    XmlElement keyType = soapMessage.CreateElement("t", "KeyType", soapMessage.DocumentElement.NamespaceURI);
                    XmlText keyTypeValue = soapMessage.CreateTextNode("http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey");
                    keyType.AppendChild(keyTypeValue);
                    soapEnvelope.AppendChild(keyType);

                    return soapMessage.OuterXml;
                }
                catch (Exception ex)
                {
                   // ExceptionLogging.SendErrorToText(ex);
                    Response.Write("WrapInSoapMessage" + "Some Technical Error occurred,Please visit after some time" + ex.InnerException);
                    return "";
                }
            }
            #endregion

1 个答案:

答案 0 :(得分:0)

我自己尝试做类似的事情......我使用此代码使用集成身份验证从ADFS服务器生成令牌:

        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;

GenericXmlSecurityToken对象具有TokenXml属性,该属性可以通过XmlReader传递到Saml2SecurityTokenHandler.ReadToken以获取令牌。然后,我得到了一个参数化SOAP请求的方法,该请求被传递到Microsof的STS服务器上:

        StringBuilder s = new StringBuilder();
        s.Append("<s:Envelope xmlns:s=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:a=\"http://www.w3.org/2005/08/addressing\" xmlns:u=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">");
        s.Append("<s:Header>");
        s.Append("<a:Action s:mustUnderstand=\"1\">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</a:Action>");
        s.Append("<a:ReplyTo>");
        s.Append("<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>");
        s.Append("</a:ReplyTo>");
        s.Append("<a:To s:mustUnderstand=\"1\">[toUrl]</a:To>");
        s.Append("<o:Security s:mustUnderstand=\"1\" xmlns:o=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">[assertion]");
        s.Append("</o:Security>");
        s.Append("</s:Header>");
        s.Append("<s:Body>");
        s.Append("<t:RequestSecurityToken xmlns:t=\"http://schemas.xmlsoap.org/ws/2005/02/trust\">");
        s.Append("<wsp:AppliesTo xmlns:wsp=\"http://schemas.xmlsoap.org/ws/2004/09/policy\">");
        s.Append("<a:EndpointReference>");
        s.Append("<a:Address>[url]</a:Address>");
        s.Append("</a:EndpointReference>");
        s.Append("</wsp:AppliesTo>");
        s.Append("<t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>");
        s.Append("<t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>");
        s.Append("<t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>");
        s.Append("</t:RequestSecurityToken>");
        s.Append("</s:Body>");
        s.Append("</s:Envelope>");

        string samlRTString = s.ToString();
        samlRTString = samlRTString.Replace("[assertion]", samlAssertion);
        samlRTString = samlRTString.Replace("[url]", url);
        samlRTString = samlRTString.Replace("[toUrl]", toUrl);

        return samlRTString;

无论如何,这个计划......我还没有机会在我们的环境中测试我的想法,而且我在下个月离开办公室,但希望这个可能会帮助你:)