public static SendHttpRequest ( |
||
uri | The request uri | |
method | HttpMethod | The http method |
requestContent | Stream | A stream containing the request content |
contentType | string | The content type of the http request |
clientHandler | The request client handler | |
headers | string>.Dictionary | The http headers to append to the request |
return | Task |
private async Task <SPOAuthCookies> GetSPOAuthCookies(SamlSecurityToken stsToken) { // signs in to SPO with the security token issued by MSO STS and gets the fed auth cookies // the fed auth cookie needs to be attached to all SPO REST services requests Uri siteUri = this.spSiteUrl; Uri wsSigninUrl = new Uri(String.Format("{0}://{1}/{2}", siteUri.Scheme, siteUri.Authority, spowssigninUri)); HttpClientHandler clientHandler; if (WebRequest.DefaultWebProxy.GetProxy(siteUri).ToString() != siteUri.ToString()) { if (verbose) { Console.WriteLine("Using proxy...[" + WebRequest.DefaultWebProxy.GetProxy(siteUri).ToString() + "]"); } clientHandler = new HttpClientHandler(); WebProxy proxy = new WebProxy((WebRequest.DefaultWebProxy.GetProxy(siteUri))); proxy.Credentials = CredentialCache.DefaultCredentials; proxy.UseDefaultCredentials = true; clientHandler.UseCookies = true; clientHandler.UseProxy = true; clientHandler.Proxy = proxy; } else { clientHandler = new HttpClientHandler(); } SPOAuthCookies spoAuthCookies = null; if (verbose) { Console.Write("Retrieving Cookies...."); } try { await HttpUtility.SendHttpRequest( wsSigninUrl, HttpMethod.Post, new MemoryStream(stsToken.Token), "application/x-www-form-urlencoded", clientHandler); spoAuthCookies = new SPOAuthCookies(); spoAuthCookies.FedAuth = clientHandler.CookieContainer.GetCookies(wsSigninUrl)["FedAuth"].Value; spoAuthCookies.RtFA = clientHandler.CookieContainer.GetCookies(wsSigninUrl)["rtFA"].Value; spoAuthCookies.Expires = stsToken.Expires; spoAuthCookies.Host = wsSigninUrl; if (verbose) { Console.WriteLine("[OK]"); } } catch (Exception e) { Console.WriteLine("[ERROR]:" + e.Message); throw new Exception("Problems retrieving Cookies."); } return(spoAuthCookies); }
private async Task <string> GetAdfsSAMLTokenUsernamePassword() { // makes a seurity token request to the corporate ADFS proxy usernamemixed endpoint using // the user's corporate credentials. 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; // the corporate ADFS proxy endpoint that issues SAML seurity tokens given username/password credentials string stsUsernameMixedUrl = String.Format("https://{0}/adfs/services/trust/2005/usernamemixed/", this.adfsAuthUrl.Host); // generate the WS-Trust security token request SOAP message passing in the user's corporate credentials // and the site we want access to. We send the token request to the corporate ADFS proxy usernamemixed endpoint. byte[] requestBody = Encoding.UTF8.GetBytes(ParameterizeSoapRequestTokenMsgWithUsernamePassword( "urn:federation:MicrosoftOnline", // we are requesting a logon token to talk to the Microsoft Federation Gateway this.username, this.password, stsUsernameMixedUrl)); if (verbose) { Console.Write("Logging in and retrieving SAML Token..."); } try { byte[] response = await HttpUtility.SendHttpRequest( new Uri(stsUsernameMixedUrl), HttpMethod.Post, new MemoryStream(requestBody), "application/soap+xml; charset=utf-8", null); // the logon token is in the SAML assertion element of the message body XDocument xDoc = XDocument.Parse(Encoding.UTF8.GetString(response, 0, response.Length), LoadOptions.PreserveWhitespace); var assertion = from e in xDoc.Descendants() where e.Name == XName.Get("Assertion", saml) select e; samlAssertion = assertion.FirstOrDefault().ToString(); // for some reason the assertion string needs to be loaded into an XDocument // and written out for for the XML to be valid. Otherwise we get an invalid // XML error back from ADFSs XDocument doc1 = XDocument.Parse(samlAssertion); samlAssertion = doc1.ToString(SaveOptions.DisableFormatting); if (verbose) { Console.WriteLine("[OK]"); } } catch (Exception e) { Console.WriteLine("[ERROR]:" + e.Message); throw new Exception("Problems with authentication or SAML token retrieval"); } return(samlAssertion); }
private async Task <Uri> GetAdfsAuthUrl() { // make a post request with the user's login name to MSO HRD (Home Realm Discovery) service // so it can find out the url of the federation service (corporate ADFS) responsible for authenticating the user Uri corpAdfsProxyUrl = null; if (verbose) { Console.Write("Retrieving ADFS URL..."); } try { byte[] response = await HttpUtility.SendHttpRequest( new Uri(msoHrdUrl), HttpMethod.Post, new MemoryStream(Encoding.UTF8.GetBytes(String.Format("handler=1&login={0}", this.username))), // pass in the login name in the body of the form "application/x-www-form-urlencoded", null); var serializer = new JavaScriptSerializer(); var deserializedResponse = serializer.Deserialize <Dictionary <string, object> >(Encoding.UTF8.GetString(response, 0, response.Length)); corpAdfsProxyUrl = deserializedResponse.ContainsKey("AuthURL") ? new Uri(deserializedResponse["AuthURL"] as string) : null; if (verbose) { if (corpAdfsProxyUrl != null) { Console.WriteLine("[OK]"); } else { Console.WriteLine("[KO] (Probably not ADFS Federated)"); } } } catch (Exception e) { if (verbose) { Console.WriteLine("[ERROR]:" + e.Message); } } if (debug) { Console.WriteLine("ADFS PROXY URL=[" + corpAdfsProxyUrl + "]"); } return(corpAdfsProxyUrl); }
private async Task <SamlSecurityToken> GetMsoStsSAMLToken() { // Makes a request that conforms with the WS-Trust standard to // Microsoft Online Services Security Token Service to get a SAML // security token back so we can then use it to sign the user to SPO SamlSecurityToken samlST = new SamlSecurityToken(); byte[] saml11RTBytes = null; string logonToken = null; try { // find out whether the user's domain is a federated domain this.adfsAuthUrl = await GetAdfsAuthUrl(); // get logon token using windows integrated auth when the user is connected to the corporate network if (this.adfsAuthUrl != null && this.useIntegratedWindowsAuth) { UriBuilder ub = new UriBuilder(); ub.Scheme = this.adfsAuthUrl.Scheme; ub.Host = this.adfsAuthUrl.Host; ub.Path = string.Format("{0}auth/integrated/", this.adfsAuthUrl.LocalPath); // specify in the query string we want a logon token to present to the Microsoft Federation Gateway // for the corresponding user ub.Query = String.Format("{0}&wa=wsignin1.0&wtrealm=urn:federation:MicrosoftOnline", this.adfsAuthUrl.Query.Remove(0, 1)). Replace("&username="******"&username={0}", this.username)); this.adfsIntegratedAuthUrl = ub.Uri; // get the logon token from the corporate ADFS using Windows Integrated Auth logonToken = await GetAdfsSAMLTokenWinAuth(); if (!string.IsNullOrEmpty(logonToken)) { // generate the WS-Trust security token request SOAP message passing in the logon token we got from the corporate ADFS // and the site we want access to saml11RTBytes = Encoding.UTF8.GetBytes(ParameterizeSoapRequestTokenMsgWithAssertion( this.spSiteUrl.ToString(), logonToken, msoStsUrl)); } } // get logon token using the user's corporate credentials. Likely when not connected to the corporate network if (logonToken == null && this.adfsAuthUrl != null && !string.IsNullOrEmpty(password)) { logonToken = await GetAdfsSAMLTokenUsernamePassword(); // get the logon token from the corporate ADFS proxy usernamemixed enpoint if (logonToken != null) { // generate the WS-Trust security token request SOAP message passing in the logon token we got from the corporate ADFS // and the site we want access to saml11RTBytes = Encoding.UTF8.GetBytes(ParameterizeSoapRequestTokenMsgWithAssertion( this.spSiteUrl.ToString(), logonToken, msoStsUrl)); } } if (logonToken == null && this.adfsAuthUrl == null && (!string.IsNullOrEmpty(password))) // login with O365 credentials. Not a federated login. { // generate the WS-Trust security token request SOAP message passing in the user's credentials and the site we want access to saml11RTBytes = Encoding.UTF8.GetBytes(ParameterizeSoapRequestTokenMsgWithUsernamePassword( this.spSiteUrl.ToString(), this.username, this.password, msoStsUrl)); } if (saml11RTBytes != null) { // make the post request to MSO STS with the WS-Trust payload byte[] response = await HttpUtility.SendHttpRequest( new Uri(msoStsUrl), HttpMethod.Post, new MemoryStream(saml11RTBytes), "application/soap+xml; charset=utf-8", null); StreamReader sr = new StreamReader(new MemoryStream(response)); // the SAML security token is in the BinarySecurityToken element of the message body XDocument xDoc = XDocument.Parse(sr.ReadToEnd()); var binaryST = from e in xDoc.Descendants() where e.Name == XName.Get("BinarySecurityToken", wsse) select e; // get the security token expiration date from the message body var expires = from e in xDoc.Descendants() where e.Name == XName.Get("Expires", wsu) select e; if (binaryST.FirstOrDefault() != null && expires.FirstOrDefault() != null) { samlST.Token = Encoding.UTF8.GetBytes(binaryST.FirstOrDefault().Value); samlST.Expires = DateTime.Parse(expires.FirstOrDefault().Value); } } if (verbose) { Console.WriteLine("Retrieving STS Token...[OK]"); } } catch (Exception e) { Console.WriteLine("Retrieving STS Token...[ERROR]:" + e.Message); throw new Exception("Problems retrieving STS Token"); } return(samlST); }
private async Task <string> GetAdfsSAMLTokenWinAuth() { // makes a security 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; HttpClientHandler handler = new HttpClientHandler(); handler.UseDefaultCredentials = true; // use the default credentials so Kerberos can take care of authenticating our request if (verbose) { Console.Write("Logging in and retrieving SAML Token..."); } try { byte[] stsresponse = await HttpUtility.SendHttpRequest( this.adfsIntegratedAuthUrl, HttpMethod.Get, null, "text/html; charset=utf-8", handler); StreamReader sr = new StreamReader(new MemoryStream(stsresponse)); XDocument xDoc = XDocument.Parse(sr.ReadToEnd(), LoadOptions.PreserveWhitespace); var body = from e in xDoc.Descendants() where e.Name == XName.Get("body") select e; var form = from e in body.FirstOrDefault().Descendants() where e.Name == XName.Get("form") select e; // the security token response we got from ADFS is in the wresult input element var wresult = from e in form.FirstOrDefault().Descendants() where e.Name == XName.Get("input") && e.Attribute(XName.Get("name")) != null && e.Attribute(XName.Get("name")).Value == "wresult" select e; if (wresult.FirstOrDefault() != null) { // the logon token is in the SAML assertion element XDocument xDoc1 = XDocument.Parse(wresult.FirstOrDefault().Attribute(XName.Get("value")).Value, LoadOptions.PreserveWhitespace); var assertion = from e in xDoc1.Descendants() where e.Name == XName.Get("Assertion", saml) select e; samlAssertion = assertion.FirstOrDefault().ToString(); // for some reason the assertion string needs to be loaded into an XDocument // and written out for for the XML to be valid. Otherwise we get an invalid // XML error back from ADFSs XDocument doc1 = XDocument.Parse(samlAssertion); samlAssertion = doc1.ToString(SaveOptions.DisableFormatting); } if (verbose) { Console.WriteLine("[OK]"); } } catch (Exception e) { Console.WriteLine("[ERROR]:" + e.Message); throw new Exception("Problems with authentication or SAML token retrieval"); } return(samlAssertion); }