public async Task ShouldFailWhenCompleteChallengeWithoutAccount() { using (var client = new AcmeClient(WellKnownServers.LetsEncryptStaging)) { await Assert.ThrowsAsync <InvalidOperationException>( () => client.CompleteChallenge(new ChallengeEntity())); } }
public async Task ShouldFailWhenUpdateRegistrationWithoutAccount() { using (var client = new AcmeClient(WellKnownServers.LetsEncryptStaging)) { await Assert.ThrowsAsync <InvalidOperationException>( () => client.UpdateRegistration(new AcmeAccount())); } }
public async Task CanUpdateRegistration() { var accountKey = await Helper.LoadkeyV1(); var regLocation = new Uri("http://example.com/reg/1"); var mock = MockHttp(async req => { if (req.Method == HttpMethod.Post && req.RequestUri == regLocation) { var payload = await ParsePayload <RegistrationEntity>(req); Assert.Equal(ResourceTypes.Registration, payload.Resource); Assert.Equal(1, payload.Contact?.Count); Assert.Equal($"another-{email}", payload.Contact[0]); Assert.NotNull(payload.Agreement); var respJson = new { contact = payload.Contact, agreement = payload.Agreement, resource = ResourceTypes.Registration }; var resp = CreateResponse(respJson, HttpStatusCode.Created, regLocation); resp.Headers.Add("Link", $"<{tos}>; rel=\"terms-of-service\""); return(resp); } return(null); }); using (var http = new HttpClient(mock.Object)) using (var handler = new AcmeHttpHandler(server, http)) { using (var client = new AcmeClient(handler)) { client.Use(accountKey.Export()); var account = new AcmeAccount { Location = regLocation, Data = new RegistrationEntity { Resource = ResourceTypes.Registration, Contact = new[] { $"another-{email}" }, Agreement = tos } }; var result = await client.UpdateRegistration(account); Assert.Equal(ResourceTypes.Registration, result.Data.Resource); Assert.Equal(tos, account.Data.Agreement); Assert.Equal(regLocation, account.Location); } mock.As <IDisposable>().Verify(x => x.Dispose(), Times.Never()); } }
public async Task CanDeleteRegistration() { using (var client = new AcmeClient(WellKnownServers.LetsEncryptStaging)) { var reg = await client.NewRegistraton(); await client.DeleteRegistration(reg); } }
public async Task CanDeleteRegistration() { var accountKey = await Helper.LoadkeyV1(); var regLocation = new Uri("http://example.com/reg/1"); var mock = MockHttp(async req => { if (req.Method == HttpMethod.Post && req.RequestUri == regLocation) { var payload = await ParsePayload <RegistrationEntity>(req); Assert.Equal(ResourceTypes.Registration, payload.Resource); Assert.True(payload.Delete); var resp = CreateResponse(null, HttpStatusCode.OK, regLocation); resp.Headers.Add("Link", $"<{tos}>; rel=\"terms-of-service\""); return(resp); } return(null); }); using (var http = new HttpClient(mock.Object)) using (var handler = new AcmeHttpHandler(server, http)) { using (var client = new AcmeClient(handler)) { var account = new AcmeAccount { Location = regLocation, Data = new RegistrationEntity { Resource = ResourceTypes.Registration, Contact = new[] { $"another-{email}" }, Agreement = tos } }; try { await client.DeleteRegistration(account); Assert.False(true); } catch (InvalidOperationException) { } client.Use(accountKey.Export()); await client.DeleteRegistration(account); } mock.As <IDisposable>().Verify(x => x.Dispose(), Times.Never()); } }
public async Task CanChangeKey() { using (var client = new AcmeClient(WellKnownServers.LetsEncryptStaging)) { var reg = await client.NewRegistraton(); var newKey = new AccountKey().Export(); await client.ChangeKey(reg, newKey); await client.DeleteRegistration(reg); } }
public async Task CanHandlerxistingAuthorization() { var accountKey = await Helper.LoadkeyV1(); var authzUri = new Uri("http://example.com/new-authz"); var authzLoc = new Uri("http://example.com/authz/111"); var mock = MockHttp(async req => { if (req.Method == HttpMethod.Post && req.RequestUri == authzUri) { var payload = await ParsePayload <AuthorizationEntity>(req); return(CreateResponse(null, HttpStatusCode.SeeOther, authzLoc)); } if (req.Method == HttpMethod.Get && req.RequestUri == authzLoc) { return(CreateResponse(new AuthorizationEntity { Identifier = new AuthorizationIdentifier { Type = AuthorizationIdentifierTypes.Dns, Value = "www.example.com", }, Status = EntityStatus.Pending, }, HttpStatusCode.OK, authzLoc)); } return(null); }); using (var http = new HttpClient(mock.Object)) using (var handler = new AcmeHttpHandler(server, http)) { using (var client = new AcmeClient(handler)) { client.Use(accountKey.Export()); var authz = await client.NewAuthorization(new AuthorizationIdentifier { Type = AuthorizationIdentifierTypes.Dns, Value = "www.example.com" }); Assert.NotNull(authz); Assert.Equal(authzLoc, authz.Location); } mock.As <IDisposable>().Verify(x => x.Dispose(), Times.Never()); } }
public void CanCreateWithUri() { var uri = WellKnownServers.LetsEncryptStaging; using (var client = new AcmeClient(uri)) { var type = typeof(AcmeClient).GetTypeInfo(); var field = type.GetField("shouldDisposeHander", BindingFlags.NonPublic | BindingFlags.Instance); Assert.True((bool)field.GetValue(client)); Assert.NotNull(client.HttpHandler); Assert.Equal(uri, client.HttpHandler.ServerUri); } }
public static async Task <Uri> GetAcmeUriV1() { if (stagingServerV1 != null) { return(stagingServerV1); } var key = await Helper.LoadkeyV1(); foreach (var uri in StagingServersV1) { var httpSucceed = false; try { await http.Value.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead); httpSucceed = true; } catch { } if (httpSucceed) { using (var client = new AcmeClient(new AcmeHttpHandler(uri, http.Value))) { client.Use(key.Export()); try { var account = await client.NewRegistraton(); account.Data.Agreement = account.GetTermsOfServiceUri(); await client.UpdateRegistration(account); } catch { // account already exists } return(stagingServerV1 = uri); } } } throw new Exception("Staging server unavailable."); }
public async Task CanCreateRegistration() { var accountKey = await Helper.LoadkeyV1(); var regLocation = new Uri("http://example.com/reg/1"); var mock = MockHttp(async req => { if (req.Method == HttpMethod.Post && req.RequestUri == acmeDir.NewReg) { var payload = await ParsePayload <RegistrationEntity>(req); Assert.Equal(ResourceTypes.NewRegistration, payload.Resource); Assert.Equal(1, payload.Contact?.Count); Assert.Equal(email, payload.Contact[0]); var respJson = new { contact = payload.Contact, resource = ResourceTypes.Registration }; var resp = CreateResponse(respJson, HttpStatusCode.Created, regLocation); resp.Headers.Add("Link", $"<{tos}>; rel=\"terms-of-service\""); return(resp); } return(null); }); using (var http = new HttpClient(mock.Object)) using (var handler = new AcmeHttpHandler(server, http)) { using (var client = new AcmeClient(handler)) { client.Use(accountKey.Export()); var account = await client.NewRegistraton(email); Assert.Equal(ResourceTypes.Registration, account.Data.Resource); Assert.Null(account.Data.Agreement); Assert.Equal(regLocation, account.Location); Assert.Equal(tos, account.GetTermsOfServiceUri()); } mock.Protected().Verify("Dispose", Times.Never(), true); } }
public async Task CanNewRegistraton() { var accountKey = await Helper.LoadkeyV1(); var contacts = new string[] { "mailto:[email protected]" }; var regLocation = new Uri("http://example.com/reg/1"); var mock = MockHttp(async req => { if (req.Method == HttpMethod.Post && req.RequestUri == Helper.MockDirectoryV1.NewReg) { var payload = await ParsePayload <RegistrationEntity>(req); Assert.Equal(ResourceTypes.NewRegistration, payload.Resource); Assert.Equal(contacts.Clone(), payload.Contact); var respJson = new { contact = payload.Contact, agreement = payload.Agreement, resource = ResourceTypes.Registration }; var resp = CreateResponse(respJson, HttpStatusCode.Created, regLocation); resp.Headers.Add("Link", $"<{tos}>; rel=\"terms-of-service\""); return(resp); } return(null); }); using (var http = new HttpClient(mock.Object)) using (var handler = new AcmeHttpHandler(server, http)) { using (var client = new AcmeClient(handler)) { client.Use(accountKey.Export()); var result = await client.NewRegistraton(contacts); Assert.Equal(ResourceTypes.Registration, result.Data.Resource); Assert.Equal(regLocation, result.Location); } mock.As <IDisposable>().Verify(x => x.Dispose(), Times.Never()); } }
public async Task CanIssueSan() { var accountKey = await Helper.LoadkeyV1(); var csr = new CertificationRequestBuilder(); csr.AddName("C=CA, ST=Ontario, L=Toronto, O=Certes, OU=Dev, CN=www.certes-ci.dymetis.com"); csr.SubjectAlternativeNames.Add("mail.certes-ci.dymetis.com"); csr.SubjectAlternativeNames.Add("sso.certes-ci.dymetis.com"); var dirUri = await IntegrationHelper.GetAcmeUriV1(); using (var client = new AcmeClient(IntegrationHelper.GetAcmeHttpHandler(dirUri))) { client.Use(accountKey.Export()); await AuthorizeDns(client, "www.certes-ci.dymetis.com"); await AuthorizeDns(client, "mail.certes-ci.dymetis.com"); await AuthorizeDns(client, "sso.certes-ci.dymetis.com"); // should returns the valid ID var authz = await client.NewAuthorization(new AuthorizationIdentifier { Type = AuthorizationIdentifierTypes.Dns, Value = "www.certes-ci.dymetis.com", }); Assert.Equal(EntityStatus.Valid, authz.Data.Status); var authzByLoc = await client.GetAuthorization(authz.Location); Assert.Equal(authz.Data.Identifier.Value, authzByLoc.Data.Identifier.Value); var cert = await client.NewCertificate(csr); var pfx = cert.ToPfx(); pfx.AddTestCert(); pfx.Build("my.pfx", "abcd1234"); await client.RevokeCertificate(cert); } }
private static async Task AuthorizeDns(AcmeClient client, string name) { var authz = await client.NewAuthorization(new AuthorizationIdentifier { Type = AuthorizationIdentifierTypes.Dns, Value = name }); var httpChallengeInfo = authz.Data.Challenges .Where(c => c.Type == ChallengeTypes.Http01).First(); var httpChallenge = await client.CompleteChallenge(httpChallengeInfo); while (authz.Data.Status == EntityStatus.Pending) { // Wait for ACME server to validate the identifier await Task.Delay(1000); authz = await client.GetAuthorization(httpChallenge.Location); } }
public async Task CanIssueSan() { var csr = new CertificationRequestBuilder(); csr.AddName("CN=CA, ST=Ontario, L=Toronto, O=Certes, OU=Dev, CN=www.certes-ci.dymetis.com"); csr.SubjectAlternativeNames.Add("mail.certes-ci.dymetis.com"); csr.SubjectAlternativeNames.Add("sso.certes-ci.dymetis.com"); using (var client = new AcmeClient(WellKnownServers.LetsEncryptStaging)) { client.Use(Helper.Loadkey().Export()); await Task.WhenAll( AuthorizeDns(client, "www.certes-ci.dymetis.com"), AuthorizeDns(client, "mail.certes-ci.dymetis.com"), AuthorizeDns(client, "sso.certes-ci.dymetis.com")); var cert = await client.NewCertificate(csr); } }
public async Task RunAccountFlow(KeyAlgorithm algorithm) { var dirUri = await IntegrationHelper.GetAcmeUriV1(); var key = new AccountKey(algorithm); using (var client = new AcmeClient(IntegrationHelper.GetAcmeHttpHandler(dirUri))) { client.Use(key.Export()); var reg = await client.NewRegistraton(); reg.Data.Agreement = reg.GetTermsOfServiceUri(); await client.UpdateRegistration(reg); var newKey = new AccountKey().Export(); await client.ChangeKey(reg, newKey); await client.DeleteRegistration(reg); } }