/// <summary>converts a form response stream to a TokenCollection, /// by parsing the contents of the stream for newlines and equal signs /// the input stream is assumed to be an ascii encoded form resonse /// </summary> /// <param name="inputStream">the stream to read and parse</param> /// <returns> the resulting TokenCollection </returns> static public TokenCollection ParseStreamInTokenCollection(Stream inputStream) { // get the body and parse it ASCIIEncoding encoder = new ASCIIEncoding(); StreamReader readStream = new StreamReader(inputStream, encoder); String body = readStream.ReadToEnd(); readStream.Close(); Tracing.TraceMsg("got the following body back: " + body); // all we are interested is the token, so we break the string in parts TokenCollection tokens = new TokenCollection(body, '=', true, 2); return(tokens); }
///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// /// <summary>Event chaining. We catch this by the baseFeedParsers, which /// would not do anything with the gathered data. We pass the event up /// to the user; if the user doesn't discard it, we add the entry to our /// collection</summary> /// <param name="sender"> the object which send the event</param> /// <param name="e">FeedParserEventArguments, holds the feed entry</param> /// <returns> </returns> ////////////////////////////////////////////////////////////////////// protected void OnNewExtensionElement(object sender, ExtensionElementEventArgs e) { // by default, if our event chain is not hooked, the underlying parser will add it Tracing.TraceCall("received new extension element notification"); Tracing.Assert(e != null, "e should not be null"); if (e == null) { throw new ArgumentNullException("e"); } if (this.NewExtensionElement != null) { Tracing.TraceMsg("\t calling event dispatcher"); this.NewExtensionElement(sender, e); } }
///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// /// <summary>Event chaining. We catch this by the baseFeedParsers, which /// would not do anything with the gathered data. We pass the event up /// to the user; if the user doesn't discard it, we add the entry to our /// collection</summary> /// <param name="sender"> the object which send the event</param> /// <param name="e">FeedParserEventArguments, holds the feed entry</param> /// <returns> </returns> ////////////////////////////////////////////////////////////////////// protected void OnParsedNewEntry(object sender, FeedParserEventArgs e) { // by default, if our event chain is not hooked, add it to the collection Tracing.TraceCall("received new item notification"); Tracing.Assert(e != null, "e should not be null"); if (e == null) { throw new ArgumentNullException("e"); } if (this.NewAtomEntry != null) { Tracing.TraceMsg("\t calling event dispatcher"); this.NewAtomEntry(this, e); } // now check the return if (!e.DiscardEntry) { if (!e.CreatingEntry) { if (e.Entry != null) { // add it to the collection Tracing.TraceMsg("\t new AtomEntry found, adding to collection"); e.Entry.Service = this.Service; this.Entries.Add(e.Entry); } else if (e.Feed != null) { // parsed a feed, set ourselves to it... Tracing.TraceMsg("\t Feed parsed found, parsing is done..."); } } else { IVersionAware v = e.Entry as IVersionAware; if (v != null) { v.ProtocolMajor = this.ProtocolMajor; v.ProtocolMinor = this.ProtocolMinor; } } } if (e.DoneParsing) { this.BaseUriChanged(this.ImpliedBase); } }
/// <summary>checks if this is a namespace /// declaration that we already added</summary> /// <param name="node">XmlNode to check</param> /// <returns>true if this node should be skipped </returns> protected override bool SkipNode(XmlNode node) { if (base.SkipNode(node)) { return(true); } Tracing.TraceMsg("in skipnode for node: " + node.Name + "--" + node.Value); if (this.BatchData != null) { if (node.NodeType == XmlNodeType.Attribute && node.Name.StartsWith("xmlns") && (String.Compare(node.Value, BaseNameTable.gBatchNamespace) == 0)) { return(true); } } return(false); }
////////////////////////////////////////////////////////////////////// /// <summary>Retrieves information about the AuthSub token. /// If the <code>key</code> is non-null, the token will be used securely /// and the request to revoke the token will be signed. /// </summary> /// <param name="protocol">the protocol to use to communicate with the server</param> /// <param name="domain">the domain at which the authentication server exists</param> /// <param name="token">tthe AuthSub token for which to receive information </param> /// <param name="key">the private key to sign the request</param> /// <returns>the token information in the form of a Dictionary from the name of the /// attribute to the value of the attribute</returns> ////////////////////////////////////////////////////////////////////// public static Dictionary <String, String> GetTokenInfo(String protocol, String domain, String token, AsymmetricAlgorithm key) { HttpWebResponse response; try { string tokenInfoUrl = GetTokenInfoUrl(protocol, domain); Uri uri = new Uri(tokenInfoUrl); HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest; string header = formAuthorizationHeader(token, key, uri, "GET"); request.Headers.Add(header); response = request.GetResponse() as HttpWebResponse; } catch (WebException e) { Tracing.TraceMsg("GetTokenInfo failed " + e.Status); throw new GDataRequestException("Execution of GetTokenInfo", e); } if (response != null) { int code = (int)response.StatusCode; if (code != 200) { throw new GDataRequestException("Execution of revokeToken request returned unexpected result: " + code, response); } TokenCollection tokens = Utilities.ParseStreamInTokenCollection(response.GetResponseStream()); if (tokens != null) { return(tokens.CreateDictionary()); } } return(null); }
//end of public static String exchangeForSessionToken(String onetimeUseToken, PrivateKey key) ////////////////////////////////////////////////////////////////////// /// <summary> /// Exchanges the one time use token returned in the URL for a session /// token. If the key is non-null, the token will be used securely, /// and the request will be signed /// </summary> /// <param name="protocol">the protocol to use to communicate with the /// server</param> /// <param name="domain">the domain at which the authentication server /// exists</param> /// <param name="onetimeUseToken">the token send by google in the URL</param> /// <param name="key">the private key used to sign</param> /// <returns>the session token</returns> ////////////////////////////////////////////////////////////////////// public static string exchangeForSessionToken(string protocol, string domain, string onetimeUseToken, AsymmetricAlgorithm key) { HttpWebResponse response = null; string authSubToken = null; try { string sessionUrl = getSessionTokenUrl(protocol, domain); Uri uri = new Uri(sessionUrl); HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest; string header = formAuthorizationHeader(onetimeUseToken, key, uri, "GET"); request.Headers.Add(header); response = request.GetResponse() as HttpWebResponse; } catch (WebException e) { Tracing.TraceMsg("exchangeForSessionToken failed " + e.Status); throw new GDataRequestException("Execution of exchangeForSessionToken", e); } if (response != null) { int code = (int)response.StatusCode; if (code != 200) { throw new GDataRequestException("Execution of exchangeForSessionToken request returned unexpected result: " + code, response); } // get the body and parse it authSubToken = Utilities.ParseValueFormStream(response.GetResponseStream(), GoogleAuthentication.AuthSubToken); } Tracing.Assert(authSubToken != null, "did not find an auth token in exchangeForSessionToken"); return(authSubToken); }
/// <summary> /// Parses the inner state of the element /// </summary> /// <param name="e">The extension element that should be added to this entry</param> /// <param name="parser">The AtomFeedParser that called this</param> public virtual void Parse(ExtensionElementEventArgs e, AtomFeedParser parser) { if (e == null) { throw new ArgumentNullException("e"); } Tracing.TraceMsg("Entering Parse on AbstractEntry"); XmlNode node = e.ExtensionElement; if (this.ExtensionFactories != null && this.ExtensionFactories.Count > 0) { Tracing.TraceMsg("Entring default Parsing for AbstractEntry"); IExtensionElementFactory f = FindExtensionFactory(node.LocalName, node.NamespaceURI); if (f != null) { this.ExtensionElements.Add(f.CreateInstance(node, parser)); e.DiscardEntry = true; } } }
//end of private static string generateULONGRnd() ////////////////////////////////////////////////////////////////////// /// <summary>signs the data with the given key</summary> /// <param name="dataToSign">the data to sign </param> /// <param name="key">the private key to used </param> /// <returns> the signed data</returns> ////////////////////////////////////////////////////////////////////// private static byte[] sign(string dataToSign, AsymmetricAlgorithm key) { byte[] data = new ASCIIEncoding().GetBytes(dataToSign); try { RSACryptoServiceProvider providerRSA = key as RSACryptoServiceProvider; if (providerRSA != null) { return(providerRSA.SignData(data, new SHA1CryptoServiceProvider())); } DSACryptoServiceProvider providerDSA = key as DSACryptoServiceProvider; if (providerDSA != null) { return(providerDSA.SignData(data)); } } catch (CryptographicException e) { Tracing.TraceMsg(e.Message); } return(null); }
/// <summary>public WebResponse Insert(Uri insertUri, Stream entryStream, ICredentials credentials)</summary> /// <param name="feed">the feed this entry should be inserted into</param> /// <param name="entry">the entry to be inserted</param> /// <returns> the inserted entry</returns> AtomEntry IService.Insert(AtomFeed feed, AtomEntry entry) { Tracing.Assert(feed != null, "feed should not be null"); if (feed == null) { throw new ArgumentNullException("feed"); } Tracing.Assert(entry != null, "entry should not be null"); if (entry == null) { throw new ArgumentNullException("entry"); } if (feed.ReadOnly) { throw new GDataRequestException("Can not update a read-only feed"); } Tracing.TraceMsg("Post URI is: " + feed.Post); Uri target = new Uri(feed.Post); return(Insert(target, entry)); }
///<summary>Deletes an Atom entry when given a Uri</summary> ///<param name="uriTarget">The target Uri to call http delete against</param> ///<param name="eTag">The eTag of the item to delete. This parameter is used for strong /// concurrency support in protocol version 2 and up</param> public void Delete(Uri uriTarget, string eTag) { Tracing.Assert(uriTarget != null, "uri should not be null"); if (uriTarget == null) { throw new ArgumentNullException("uriTarget"); } Tracing.TraceMsg("Deleting entry: " + uriTarget.ToString()); IGDataRequest request = RequestFactory.CreateRequest(GDataRequestType.Delete, uriTarget); ISupportsEtag eTarget = request as ISupportsEtag; if (eTarget != null && eTag != null) { eTarget.Etag = eTag; } request.Credentials = Credentials; request.Execute(); IDisposable disp = request as IDisposable; disp.Dispose(); }
/// <summary> /// event on the Feed to handle extension elements during parsing /// </summary> /// <param name="e">the event arguments</param> /// <param name="parser">the parser that caused this</param> protected virtual void HandleExtensionElements(ExtensionElementEventArgs e, AtomFeedParser parser) { Tracing.TraceMsg("Entering HandleExtensionElements on AbstractFeed"); XmlNode node = e.ExtensionElement; if (this.ExtensionFactories != null && this.ExtensionFactories.Count > 0) { Tracing.TraceMsg("Entring default Parsing for AbstractFeed"); foreach (IExtensionElementFactory f in this.ExtensionFactories) { Tracing.TraceMsg("Found extension Factories"); if (String.Compare(node.NamespaceURI, f.XmlNameSpace, true, CultureInfo.InvariantCulture) == 0) { if (String.Compare(node.LocalName, f.XmlName, true, CultureInfo.InvariantCulture) == 0) { e.Base.ExtensionElements.Add(f.CreateInstance(node, parser)); e.DiscardEntry = true; break; } } } } return; }
/// <summary>saves the inner state of the element</summary> /// <param name="writer">the xmlWriter to save into </param> protected override void SaveInnerXml(XmlWriter writer) { // saving title Tracing.TraceMsg("Entering save inner XML on AtomEntry"); if (this.batchData != null) { this.batchData.Save(writer); } if (this.title != null) { Tracing.TraceMsg("Saving Title: " + this.Title.Text); this.Title.SaveToXml(writer); } if (this.id != null) { this.Id.SaveToXml(writer); } foreach (AtomLink link in this.Links) { link.SaveToXml(writer); } foreach (AtomPerson person in this.Authors) { person.SaveToXml(writer); } foreach (AtomPerson person in this.Contributors) { person.SaveToXml(writer); } foreach (AtomCategory category in this.Categories) { category.SaveToXml(writer); } if (this.rights != null) { this.Rights.SaveToXml(writer); } if (this.summary != null) { this.Summary.SaveToXml(writer); } if (this.content != null) { this.Content.SaveToXml(writer); } if (this.source != null) { this.Source.SaveToXml(writer); } WriteLocalDateTimeElement(writer, AtomParserNameTable.XmlUpdatedElement, this.Updated); WriteLocalDateTimeElement(writer, AtomParserNameTable.XmlPublishedElement, this.Published); }
/// <summary>Executes the request and prepares the response stream. Also /// does error checking</summary> public virtual void Execute() { try { EnsureWebRequest(); // if we ever handed out a stream, we want to close it before doing the real excecution if (this.requestStream != null) { this.requestStream.Close(); } Tracing.TraceCall("calling the real execution over the webresponse"); LogRequest(this.webRequest); this.webResponse = this.webRequest.GetResponse(); } catch (WebException e) { Tracing.TraceCall("GDataRequest::Execute failed: " + this.targetUri.ToString()); GDataRequestException gde = new GDataRequestException("Execution of request failed: " + this.targetUri.ToString(), e); throw gde; } if (this.webResponse != null) { this.responseStream = this.webResponse.GetResponseStream(); } LogResponse(this.webResponse); if (this.webResponse is HttpWebResponse) { HttpWebResponse response = this.webResponse as HttpWebResponse; HttpWebRequest request = this.webRequest as HttpWebRequest; this.useGZip = (string.Compare(response.ContentEncoding, "gzip", true, CultureInfo.InvariantCulture) == 0); if (this.useGZip) { this.responseStream = new GZipStream(this.responseStream, CompressionMode.Decompress); } Tracing.Assert(response != null, "The response should not be NULL"); Tracing.Assert(request != null, "The request should not be NULL"); int code = (int)response.StatusCode; Tracing.TraceMsg("Returned ContentType is: " + (response.ContentType == null ? "None" : response.ContentType) + " from URI : " + request.RequestUri.ToString());; Tracing.TraceMsg("Returned StatusCode is: " + response.StatusCode + code); if (response.StatusCode == HttpStatusCode.Forbidden) { // that could imply that we need to reauthenticate Tracing.TraceMsg("need to reauthenticate"); throw new GDataForbiddenException("Execution of request returned HttpStatusCode.Forbidden: " + this.targetUri.ToString() + response.StatusCode.ToString(), this.webResponse); } if (response.StatusCode == HttpStatusCode.Conflict) { // a put went bad due to a version conflict throw new GDataVersionConflictException("Execution of request returned HttpStatusCode.Conflict: " + this.targetUri.ToString() + response.StatusCode.ToString(), this.webResponse); } if ((this.IfModifiedSince != DateTime.MinValue || this.Etag != null) && response.StatusCode == HttpStatusCode.NotModified) { // Throw an exception for conditional GET throw new GDataNotModifiedException("Content not modified: " + this.targetUri.ToString(), this.webResponse); } if (response.StatusCode == HttpStatusCode.Redirect || response.StatusCode == HttpStatusCode.Found || response.StatusCode == HttpStatusCode.RedirectKeepVerb) { Tracing.TraceMsg("throwing for redirect"); throw new GDataRedirectException("Execution resulted in a redirect from " + this.targetUri.ToString(), this.webResponse); } if (code > 299) { // treat everything else over 300 as errors throw new GDataRequestException("Execution of request returned unexpected result: " + this.targetUri.ToString() + response.StatusCode.ToString(), this.webResponse); } this.contentLength = response.ContentLength; // if we got an etag back, remember it this.eTag = response.Headers[GDataRequestFactory.EtagHeader]; response = null; request = null; } }
static public void TraceInfo(string msg) { Tracing.TraceMsg(msg); }
/// <summary>Executes the request and prepares the response stream. Also /// does error checking</summary> /// <param name="retryCounter">indicates the n-th time this is run</param> protected void Execute(int retryCounter) { Tracing.TraceCall("GoogleAuth: Execution called"); try { CopyRequestData(); base.Execute(); if (this.Response is HttpWebResponse) { HttpWebResponse response = this.Response as HttpWebResponse; this.responseVersion = new VersionInformation(response.Headers[GDataGAuthRequestFactory.GDataVersion]); } } catch (GDataForbiddenException) { Tracing.TraceMsg("need to reauthenticate, got a forbidden back"); // do it again, once, reset AuthToken first and streams first Reset(); this.factory.GAuthToken = null; CopyRequestData(); base.Execute(); } catch (GDataRedirectException re) { // we got a redirect. Tracing.TraceMsg("Got a redirect to: " + re.Location); // only reset the base, the auth cookie is still valid // and cookies are stored in the factory if (this.factory.StrictRedirect) { HttpWebRequest http = this.Request as HttpWebRequest; if (http != null) { // only redirect for GET, else throw if (http.Method != HttpMethods.Get) { throw; } } } // verify that there is a non empty location string if (re.Location.Trim().Length == 0) { throw; } Reset(); this.TargetUri = new Uri(re.Location); CopyRequestData(); base.Execute(); } catch (GDataRequestException re) { HttpWebResponse webResponse = re.Response as HttpWebResponse; if (webResponse != null && webResponse.StatusCode != HttpStatusCode.InternalServerError) { Tracing.TraceMsg("Not a server error. Possibly a Bad request or forbidden resource."); Tracing.TraceMsg("We don't want to retry non 500 errors."); throw; } if (retryCounter > this.factory.NumberOfRetries) { Tracing.TraceMsg("Number of retries exceeded"); throw; } Tracing.TraceMsg("Let's retry this"); // only reset the base, the auth cookie is still valid // and cookies are stored in the factory Reset(); this.Execute(retryCounter + 1); } catch (Exception e) { Tracing.TraceCall("*** EXCEPTION " + e.GetType().Name + " CAUGHT ***"); throw; } finally { if (this.requestCopy != null) { this.requestCopy.Close(); this.requestCopy = null; } } }
/// <summary>goes to the Google auth service, and gets a new auth token</summary> /// <returns>the auth token, or NULL if none received</returns> public static string QueryClientLoginToken(GDataCredentials gc, string serviceName, string applicationName, bool fUseKeepAlive, IWebProxy proxyServer, Uri clientLoginHandler) { Tracing.Assert(gc != null, "Do not call QueryAuthToken with no network credentials"); if (gc == null) { throw new System.ArgumentNullException("nc", "No credentials supplied"); } HttpWebRequest authRequest = WebRequest.Create(clientLoginHandler) as HttpWebRequest; authRequest.KeepAlive = fUseKeepAlive; if (proxyServer != null) { authRequest.Proxy = proxyServer; } string accountType = GoogleAuthentication.AccountType; if (!String.IsNullOrEmpty(gc.AccountType)) { accountType += gc.AccountType; } else { accountType += GoogleAuthentication.AccountTypeDefault; } WebResponse authResponse = null; HttpWebResponse response = null; string authToken = null; try { authRequest.ContentType = HttpFormPost.Encoding; authRequest.Method = HttpMethods.Post; ASCIIEncoding encoder = new ASCIIEncoding(); string user = gc.Username == null ? "" : gc.Username; string pwd = gc.getPassword() == null ? "" : gc.getPassword(); // now enter the data in the stream string postData = GoogleAuthentication.Email + "=" + Utilities.UriEncodeUnsafe(user) + "&"; postData += GoogleAuthentication.Password + "=" + Utilities.UriEncodeUnsafe(pwd) + "&"; postData += GoogleAuthentication.Source + "=" + Utilities.UriEncodeUnsafe(applicationName) + "&"; postData += GoogleAuthentication.Service + "=" + Utilities.UriEncodeUnsafe(serviceName) + "&"; if (gc.CaptchaAnswer != null) { postData += GoogleAuthentication.CaptchaAnswer + "=" + Utilities.UriEncodeUnsafe(gc.CaptchaAnswer) + "&"; } if (gc.CaptchaToken != null) { postData += GoogleAuthentication.CaptchaToken + "=" + Utilities.UriEncodeUnsafe(gc.CaptchaToken) + "&"; } postData += accountType; byte[] encodedData = encoder.GetBytes(postData); authRequest.ContentLength = encodedData.Length; Stream requestStream = authRequest.GetRequestStream(); requestStream.Write(encodedData, 0, encodedData.Length); requestStream.Close(); authResponse = authRequest.GetResponse(); response = authResponse as HttpWebResponse; } catch (WebException e) { response = e.Response as HttpWebResponse; if (response == null) { Tracing.TraceMsg("QueryAuthtoken failed " + e.Status + " " + e.Message); throw; } } if (response != null) { // check the content type, it must be text if (!response.ContentType.StartsWith(HttpFormPost.ReturnContentType)) { throw new GDataRequestException("Execution of authentication request returned unexpected content type: " + response.ContentType, response); } TokenCollection tokens = Utilities.ParseStreamInTokenCollection(response.GetResponseStream()); authToken = Utilities.FindToken(tokens, GoogleAuthentication.AuthToken); if (authToken == null) { throw Utilities.getAuthException(tokens, response); } // failsafe. if getAuthException did not catch an error... int code = (int)response.StatusCode; if (code != 200) { throw new GDataRequestException("Execution of authentication request returned unexpected result: " + code, response); } } Tracing.Assert(authToken != null, "did not find an auth token in QueryAuthToken"); if (authResponse != null) { authResponse.Close(); } return(authToken); }