public async Task TestWebPersistDelete() { var testObj = new BlobStorageAuthorizationChallengeProvider(ConfigurationManager.AppSettings[AppSettingsAuthConfig.authorizationChallengeBlobStorageAccount], "$web"); ACMESharp.ACME.HttpChallenge challenge = new ACMESharp.ACME.HttpChallenge("http", new HttpChallengeAnswer()) { FileContent = "test", FilePath = "/.well-known/acme-challenge/aBAasda234" }; await testObj.PersistsChallengeFile(challenge); await testObj.CleanupChallengeFile(challenge); }
public void TestHandleCreateAndCleanUpFiles() { var r = new Random(); var bn = new byte[10]; var bv = new byte[10]; r.NextBytes(bn); r.NextBytes(bv); var rn = BitConverter.ToString(bn); var rv = BitConverter.ToString(bv); var c = new HttpChallenge(AcmeProtocol.CHALLENGE_TYPE_HTTP, new HttpChallengeAnswer()) { Token = "FOOBAR", FileUrl = $"http://foobar.acmetesting.zyborg.io/utest/{rn}", FilePath = $"utest/{rn}", FileContent = rv, }; var awsParams = new AwsCommonParams(); awsParams.InitParams(_handlerParams); var p = GetProvider(); using (var h = p.GetHandler(c, _handlerParams)) { var sites = IisChallengeHandler.ListHttpWebSites(); Assert.IsNotNull(sites); var site = sites.First(x => x.SiteName == _handlerParams.WebSiteRef); Assert.IsNotNull(site); var fullPath = Environment.ExpandEnvironmentVariables( Path.Combine(site.SiteRoot, c.FilePath)); // Assert test file does not exist Assert.IsFalse(File.Exists(fullPath)); // Create the record... h.Handle(c); // ...and assert it does exist Assert.IsTrue(File.Exists(fullPath)); Assert.AreEqual(c.FileContent, File.ReadAllText(fullPath)); // Clean up the record... h.CleanUp(c); // ...and assert it does not exist once more Assert.IsFalse(File.Exists(fullPath)); } }
private void EditFile(HttpChallenge httpChallenge, bool delete) { var filePath = httpChallenge.FilePath; // We need to strip off any leading '/' in the path or // else it creates a path with an empty leading segment if (filePath.StartsWith("/")) filePath = filePath.Substring(1); using (var s3 = new Amazon.S3.AmazonS3Client( CommonParams.ResolveCredentials(), CommonParams.RegionEndpoint)) { if (delete) { var s3Requ = new Amazon.S3.Model.DeleteObjectRequest { BucketName = BucketName, Key = filePath, }; var s3Resp = s3.DeleteObject(s3Requ); } else { var s3Requ = new Amazon.S3.Model.PutObjectRequest { BucketName = BucketName, Key = filePath, ContentBody = httpChallenge.FileContent, ContentType = ContentType, CannedACL = S3CannedAcl, }; var s3Resp = s3.PutObject(s3Requ); } } }
private void EditFile(HttpChallenge httpChallenge, bool delete) { IisWebSiteBinding site = IisHelper.ResolveSingleSite(WebSiteRef, IisHelper.ListDistinctHttpWebSites()); var siteRoot = site.SiteRoot; if (!string.IsNullOrEmpty(OverrideSiteRoot)) siteRoot = OverrideSiteRoot; if (string.IsNullOrEmpty(siteRoot)) throw new InvalidOperationException("missing root path for resolve site") .With(nameof(IisWebSiteBinding.SiteId), site.SiteId) .With(nameof(IisWebSiteBinding.SiteName), site.SiteName); // IIS-configured Site Root can use env vars siteRoot = Environment.ExpandEnvironmentVariables(siteRoot); // Make sure we're using the canonical full path siteRoot = Path.GetFullPath(siteRoot); // We need to strip off any leading '/' in the path var filePath = httpChallenge.FilePath; if (filePath.StartsWith("/")) filePath = filePath.Substring(1); var fullFilePath = Path.Combine(siteRoot, filePath); var fullDirPath = Path.GetDirectoryName(fullFilePath); var fullConfigPath = Path.Combine(fullDirPath, "web.config"); // This meta-data file will be placed next to the actual // Challenge answer content file and it captures some details // that we need in order to properly clean up the handling of // this Challenge after it has been submitted var fullMetaPath = $"{fullFilePath}-acmesharp_meta"; // Check if user is running with elevated privs and warn if not if (!IisHelper.IsAdministrator()) { Console.Error.WriteLine("WARNING: You are not running with elelvated privileges."); Console.Error.WriteLine(" Write access may be denied to the destination."); } if (delete) { bool skipLocalWebConfig = SkipLocalWebConfig; List<string> dirsCreated = null; // First see if there's a meta file there to help us out if (File.Exists(fullMetaPath)) { var meta = JsonHelper.Load<IisChallengeHandlerMeta>( File.ReadAllText(fullMetaPath)); skipLocalWebConfig = meta.SkippedLocalWebConfig; dirsCreated = meta.DirsCreated; } // Get rid of the Challenge answer content file if (File.Exists(fullFilePath)) File.Delete(fullFilePath); // Get rid of web.config if necessary if (!skipLocalWebConfig && File.Exists(fullConfigPath)) File.Delete(fullConfigPath); // Get rid of the meta file so that we can clean up the dirs if (File.Exists(fullMetaPath)) File.Delete(fullMetaPath); // Walk up the tree if needed if (dirsCreated?.Count > 0) { dirsCreated.Reverse(); foreach (var dir in dirsCreated) { if (Directory.Exists(dir)) { if (Directory.GetFileSystemEntries(dir).Length == 0) { Directory.Delete(dir); } } } } } else { // Figure out which dirs we have to create so // we can capture and clean it up later on var meta = new IisChallengeHandlerMeta { WasAdmin = IisHelper.IsAdministrator(), SkippedLocalWebConfig = SkipLocalWebConfig, DirsCreated = new List<string>(), }; // In theory this ascending of the dir path should work // just fine, but just in case, this path segment counter // should gaurd against the possibility of an infinite loop var dirLimit = 100; var testDir = fullDirPath; while (!Directory.Exists(testDir)) { // Sanity check against an infinite loop if (--dirLimit <= 0) throw new Exception("Unexpected directory path segment count reached") .With(nameof(dirLimit), "100") .With(nameof(fullDirPath), fullDirPath) .With(nameof(testDir), testDir) .With($"first-{nameof(meta.DirsCreated)}", meta.DirsCreated[0]) .With($"last-{nameof(meta.DirsCreated)}", meta.DirsCreated[meta.DirsCreated.Count - 1]); if (Path.GetFullPath(testDir) == siteRoot) break; // Add to the top of the list meta.DirsCreated.Insert(0, testDir); // Move to the parent testDir = Path.GetDirectoryName(testDir); } foreach (var dir in meta.DirsCreated) Directory.CreateDirectory(dir); File.WriteAllText(fullFilePath, httpChallenge.FileContent); File.WriteAllText(fullMetaPath, JsonHelper.Save(meta)); if (!SkipLocalWebConfig) { var t = typeof(IisChallengeHandler); var r = $"{t.Namespace}.{t.Name}-WebConfig"; using (Stream rs = t.Assembly.GetManifestResourceStream(r)) { using (var fs = new FileStream(fullConfigPath, FileMode.Create)) { rs.CopyTo(fs); } } } } }
public void TestHandlerUploadAndCleanUpObject() { var r = new Random(); var bn = new byte[10]; var bv = new byte[10]; r.NextBytes(bn); r.NextBytes(bv); var rn = BitConverter.ToString(bn); var rv = BitConverter.ToString(bv); var c = new HttpChallenge(AcmeProtocol.CHALLENGE_TYPE_HTTP, new HttpChallengeAnswer()) { Token = "FOOBAR", FileUrl = $"http://foobar.acmetesting.zyborg.io/utest/{rn}", FilePath = $"/utest/{rn}", FileContent = rv, }; var awsParams = new AwsCommonParams(); awsParams.InitParams(_handlerParams); var p = GetProvider(); using (var h = p.GetHandler(c, _handlerParams)) { // Assert test file does not exist var s3Obj = AwsS3ChallengeHandler.GetFile(awsParams, _handlerParams.BucketName, c.FilePath); // Assert test record does *not* exist Assert.IsNull(s3Obj); // Create the record... h.Handle(c); // ...and assert it does exist s3Obj = AwsS3ChallengeHandler.GetFile(awsParams, _handlerParams.BucketName, c.FilePath); Assert.IsNotNull(s3Obj); using (var sr = new StreamReader(s3Obj.ResponseStream)) { var v = sr.ReadToEnd(); Assert.AreEqual(c.FileContent, v); } // Clean up the record... h.CleanUp(c); // ...and assert it does not exist once more s3Obj = AwsS3ChallengeHandler.GetFile(awsParams, _handlerParams.BucketName, c.FilePath); Assert.IsNull(s3Obj); } }