Support for Digest Auth. Little "hacky" due to Bug (?) in Mono (for Android)
This commit is contained in:
		| @@ -119,13 +119,6 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 		internal static void ConfigureWebClient(WebClient wc) | ||||
| 		{ | ||||
| 			// Not implemented and ignored in Mono < 2.10 | ||||
| 			try | ||||
| 			{ | ||||
| 				wc.CachePolicy = new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore); | ||||
| 			} | ||||
| 			catch(NotImplementedException) { } | ||||
| 			catch(Exception) { Debug.Assert(false); } | ||||
|  | ||||
| 			try | ||||
| 			{ | ||||
| @@ -189,22 +182,50 @@ namespace KeePassLib.Serialization | ||||
| 				ValidateServerCertificate; | ||||
| 		} | ||||
|  | ||||
| 		private static IOWebClient CreateWebClient(IOConnectionInfo ioc) | ||||
| 		private static IOWebClient CreateWebClient(IOConnectionInfo ioc, bool digestAuth) | ||||
| 		{ | ||||
| 			PrepareWebAccess(); | ||||
|  | ||||
| 			IOWebClient wc = new IOWebClient(); | ||||
| 			ConfigureWebClient(wc); | ||||
|  | ||||
| 			if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0)) | ||||
| 			if ((ioc.UserName.Length > 0) || (ioc.Password.Length > 0)) | ||||
| 			{ | ||||
| 				//set the credentials without a cache (in case the cache below fails: | ||||
| 				wc.Credentials = new NetworkCredential(ioc.UserName, ioc.Password); | ||||
|  | ||||
| 				if (digestAuth) | ||||
| 				{ | ||||
| 					//try to use the credential cache to access with Digest support: | ||||
| 					try | ||||
| 					{ | ||||
| 						var credentialCache = new CredentialCache();  | ||||
|  | ||||
| 						credentialCache.Add( | ||||
| 						                    new Uri(new Uri(ioc.Path).GetLeftPart(UriPartial.Authority)), | ||||
| 						                    "Digest", | ||||
| 						                    new NetworkCredential(ioc.UserName, ioc.Password) | ||||
| 						);  | ||||
|  | ||||
| 						 | ||||
| 						wc.Credentials = credentialCache; | ||||
| 					} catch (NotImplementedException e) | ||||
| 					{  | ||||
| 						Android.Util.Log.Debug("DEBUG", e.ToString()); | ||||
| 					} catch (Exception e) | ||||
| 					{  | ||||
| 						Android.Util.Log.Debug("DEBUG", e.ToString()); | ||||
| 						Debug.Assert(false);  | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			else if(NativeLib.IsUnix()) // Mono requires credentials | ||||
| 				wc.Credentials = new NetworkCredential("anonymous", string.Empty); | ||||
|  | ||||
| 			return wc; | ||||
| 		} | ||||
|  | ||||
| 		private static WebRequest CreateWebRequest(IOConnectionInfo ioc) | ||||
| 		private static WebRequest CreateWebRequest(IOConnectionInfo ioc, bool digestAuth) | ||||
| 		{ | ||||
| 			PrepareWebAccess(); | ||||
|  | ||||
| @@ -212,7 +233,21 @@ namespace KeePassLib.Serialization | ||||
| 			ConfigureWebRequest(req); | ||||
|  | ||||
| 			if((ioc.UserName.Length > 0) || (ioc.Password.Length > 0)) | ||||
| 			{ | ||||
| 				req.Credentials = new NetworkCredential(ioc.UserName, ioc.Password); | ||||
|  | ||||
| 				if (digestAuth) | ||||
| 				{ | ||||
| 					var credentialCache = new CredentialCache();  | ||||
| 					credentialCache.Add(  | ||||
| 					                    new Uri(new Uri(ioc.Path).GetLeftPart(UriPartial.Authority)), // request url's host | ||||
| 					                    "Digest",  // authentication type  | ||||
| 					                    new NetworkCredential(ioc.UserName, ioc.Password) // credentials  | ||||
| 					                    );  | ||||
| 					 | ||||
| 					req.Credentials = credentialCache; | ||||
| 				} | ||||
| 			} | ||||
| 			else if(NativeLib.IsUnix()) // Mono requires credentials | ||||
| 				req.Credentials = new NetworkCredential("anonymous", string.Empty); | ||||
|  | ||||
| @@ -221,15 +256,27 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 		public static Stream OpenRead(IOConnectionInfo ioc) | ||||
| 		{ | ||||
| 			if(StrUtil.IsDataUri(ioc.Path)) | ||||
| 			if (StrUtil.IsDataUri(ioc.Path)) | ||||
| 			{ | ||||
| 				byte[] pbData = StrUtil.DataUriToData(ioc.Path); | ||||
| 				if(pbData != null) return new MemoryStream(pbData, false); | ||||
| 				if (pbData != null) | ||||
| 					return new MemoryStream(pbData, false); | ||||
| 			} | ||||
|  | ||||
| 			if(ioc.IsLocalFile()) return OpenReadLocal(ioc); | ||||
| 			if (ioc.IsLocalFile()) | ||||
| 				return OpenReadLocal(ioc); | ||||
|  | ||||
| 			try | ||||
| 			{  | ||||
| 				return CreateWebClient(ioc, false).OpenRead(new Uri(ioc.Path)); | ||||
| 			} catch (WebException ex) | ||||
| 			{ | ||||
| 				if ((ex.Response is HttpWebResponse) && (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.Unauthorized)) | ||||
| 					return CreateWebClient(ioc, true).OpenRead(new Uri(ioc.Path)); | ||||
| 				else | ||||
| 					throw ex; | ||||
| 			} | ||||
|  | ||||
| 			return CreateWebClient(ioc).OpenRead(new Uri(ioc.Path)); | ||||
| 		} | ||||
| #else | ||||
| 		public static Stream OpenRead(IOConnectionInfo ioc) | ||||
| @@ -248,20 +295,20 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 		class UploadOnCloseMemoryStream: MemoryStream | ||||
| 		{ | ||||
| 			System.Net.WebClient webClient; | ||||
| 			IOConnectionInfo ioc; | ||||
| 			string method; | ||||
| 			Uri destinationFilePath; | ||||
| 			 | ||||
| 			public UploadOnCloseMemoryStream(System.Net.WebClient _webClient, string _method, Uri _destinationFilePath) | ||||
| 			public UploadOnCloseMemoryStream(IOConnectionInfo _ioc, string _method, Uri _destinationFilePath) | ||||
| 			{ | ||||
| 				this.webClient = _webClient; | ||||
| 				ioc = _ioc; | ||||
| 				this.method = _method; | ||||
| 				this.destinationFilePath = _destinationFilePath; | ||||
| 			} | ||||
|  | ||||
| 			public UploadOnCloseMemoryStream(System.Net.WebClient _webClient, Uri _destinationFilePath) | ||||
| 			public UploadOnCloseMemoryStream(IOConnectionInfo _ioc, Uri _destinationFilePath) | ||||
| 			{ | ||||
| 				this.webClient = _webClient; | ||||
| 				this.ioc = _ioc; | ||||
| 				this.method = null; | ||||
| 				this.destinationFilePath = _destinationFilePath; | ||||
| 			} | ||||
| @@ -269,6 +316,21 @@ namespace KeePassLib.Serialization | ||||
| 			public override void Close() | ||||
| 			{ | ||||
| 				base.Close(); | ||||
| 				try | ||||
| 				{ | ||||
| 					uploadData(IOConnection.CreateWebClient(ioc, false)); | ||||
| 				} catch (WebException ex) | ||||
| 				{ | ||||
| 					if ((ex.Response is HttpWebResponse) && (((HttpWebResponse) ex.Response).StatusCode == HttpStatusCode.Unauthorized)) | ||||
| 						uploadData(IOConnection.CreateWebClient(ioc, true)); | ||||
| 					else | ||||
| 						throw ex; | ||||
| 				} | ||||
| 				 | ||||
| 			} | ||||
|  | ||||
| 			void uploadData(WebClient webClient) | ||||
| 			{ | ||||
| 				if (method != null) | ||||
| 				{ | ||||
| 					webClient.UploadData(destinationFilePath, method, this.ToArray()); | ||||
| @@ -276,7 +338,6 @@ namespace KeePassLib.Serialization | ||||
| 				{ | ||||
| 					webClient.UploadData(destinationFilePath, this.ToArray()); | ||||
| 				} | ||||
| 				 | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| @@ -293,9 +354,9 @@ namespace KeePassLib.Serialization | ||||
| 			if(NativeLib.IsUnix() && (uri.Scheme.Equals(Uri.UriSchemeHttp, | ||||
| 				StrUtil.CaseIgnoreCmp) || uri.Scheme.Equals(Uri.UriSchemeHttps, | ||||
| 				StrUtil.CaseIgnoreCmp))) | ||||
| 				return new UploadOnCloseMemoryStream(CreateWebClient(ioc), WebRequestMethods.Http.Put, uri); | ||||
| 				return new UploadOnCloseMemoryStream(ioc, WebRequestMethods.Http.Put, uri); | ||||
|  | ||||
| 			return new UploadOnCloseMemoryStream(CreateWebClient(ioc), uri); | ||||
| 			return new UploadOnCloseMemoryStream(ioc, uri); | ||||
| 		} | ||||
| #else | ||||
| 		public static Stream OpenWrite(IOConnectionInfo ioc) | ||||
| @@ -352,25 +413,45 @@ namespace KeePassLib.Serialization | ||||
| 			return true; | ||||
| 		} | ||||
|  | ||||
| 		delegate void DoWithRequest(WebRequest req); | ||||
|  | ||||
|  | ||||
| 		static void RepeatWithDigestOnFail(IOConnectionInfo ioc, DoWithRequest f) | ||||
| 		{ | ||||
| 			WebRequest req = CreateWebRequest(ioc, false); | ||||
| 			try{ | ||||
| 				f(req); | ||||
| 			} | ||||
| 			catch (WebException ex) | ||||
| 			{ | ||||
| 				if ((ex.Response is HttpWebResponse) && (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.Unauthorized)) | ||||
| 				{ | ||||
| 					req = CreateWebRequest(ioc, true); | ||||
| 					f(req); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		public static void DeleteFile(IOConnectionInfo ioc) | ||||
| 		{ | ||||
| 			if(ioc.IsLocalFile()) { File.Delete(ioc.Path); return; } | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| 			WebRequest req = CreateWebRequest(ioc); | ||||
| 			if(req != null) | ||||
| 			{ | ||||
| 				if(req is HttpWebRequest) req.Method = "DELETE"; | ||||
| 				else if(req is FtpWebRequest) req.Method = WebRequestMethods.Ftp.DeleteFile; | ||||
| 				else if(req is FileWebRequest) | ||||
| 			RepeatWithDigestOnFail(ioc, (WebRequest req) => { | ||||
| 				if(req != null) | ||||
| 				{ | ||||
| 					File.Delete(UrlUtil.FileUrlToPath(ioc.Path)); | ||||
| 					return; | ||||
| 				} | ||||
| 				else req.Method = WrmDeleteFile; | ||||
| 					if(req is HttpWebRequest) req.Method = "DELETE"; | ||||
| 					else if(req is FtpWebRequest) req.Method = WebRequestMethods.Ftp.DeleteFile; | ||||
| 					else if(req is FileWebRequest) | ||||
| 					{ | ||||
| 						File.Delete(UrlUtil.FileUrlToPath(ioc.Path)); | ||||
| 						return; | ||||
| 					} | ||||
| 					else req.Method = WrmDeleteFile; | ||||
|  | ||||
| 				DisposeResponse(req.GetResponse(), true); | ||||
| 			} | ||||
| 					DisposeResponse(req.GetResponse(), true); | ||||
| 				} | ||||
| 			}); | ||||
| #endif | ||||
| 		} | ||||
|  | ||||
| @@ -388,8 +469,7 @@ namespace KeePassLib.Serialization | ||||
| 			if(iocFrom.IsLocalFile()) { File.Move(iocFrom.Path, iocTo.Path); return; } | ||||
|  | ||||
| #if !KeePassLibSD | ||||
| 			WebRequest req = CreateWebRequest(iocFrom); | ||||
| 			if(req != null) | ||||
| 			RepeatWithDigestOnFail(iocFrom, (WebRequest req)=> { if(req != null) | ||||
| 			{ | ||||
| 				if(req is HttpWebRequest) | ||||
| 				{ | ||||
| @@ -415,6 +495,8 @@ namespace KeePassLib.Serialization | ||||
|  | ||||
| 				DisposeResponse(req.GetResponse(), true); | ||||
| 			} | ||||
| 			}); | ||||
| 			 | ||||
| #endif | ||||
|  | ||||
| 			// using(Stream sIn = IOConnection.OpenRead(iocFrom)) | ||||
| @@ -435,9 +517,11 @@ namespace KeePassLib.Serialization | ||||
| 		{ | ||||
| 			try | ||||
| 			{ | ||||
| 				WebRequest req = CreateWebRequest(ioc); | ||||
| 				req.Method = strMethod; | ||||
| 				DisposeResponse(req.GetResponse(), true); | ||||
| 				RepeatWithDigestOnFail(ioc, (WebRequest req)=> { | ||||
| 					req.Method = strMethod; | ||||
| 					DisposeResponse(req.GetResponse(), true); | ||||
| 			 | ||||
| 				}); | ||||
| 			} | ||||
| 			catch(Exception) { return false; } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 PhilippC
					PhilippC