public async Task WildCardCertificateRequest() { var restApi = new AcmeRestApi(ProtoacmeContants.LETSENCRYPT_STAGING_ENDPOINT); var client = new ProtoacmeClient(restApi); //1. Create a new account. var newAccountInfo = new AcmeCreateAccount(); newAccountInfo.Contact.Add("mailto:[email protected]"); newAccountInfo.Contact.Add("mailto:[email protected]"); newAccountInfo.TermsOfServiceAgreed = true; var account = await client.Account.CreateAsync(newAccountInfo); //2. Request the wildcard cert. AcmeCertificateRequest certRequest = new AcmeCertificateRequest(); certRequest.Identifiers.Add(new DnsCertificateIdentifier() { Value = wildCardDns }); var promise = await client.Certificate.RequestCertificateAsync(account, certRequest); //3. Get Challenges var challenge = await client.Challenge.GetChallengesAsync(account, promise, ChallengeType.Dns); //4. Save Challenge Information challenge[0].SaveToFile(@"c:\temp\dns_challenge.txt"); //5. Save account and additional info for future request. account.SaveToFile(@"c:\temp\account.dat"); promise.SaveToFile(@"c:\temp\promise.dat"); challenge.SaveToFile(@"c:\temp\challenge.dat"); }
public async Task StandardCertificateRequest() { var restApi = new AcmeRestApi(ProtoacmeContants.LETSENCRYPT_STAGING_ENDPOINT); var client = new ProtoacmeClient(restApi); //1. Create a new account. var newAccountInfo = new AcmeCreateAccount(); newAccountInfo.Contact.Add("mailto:[email protected]"); newAccountInfo.TermsOfServiceAgreed = true; var account = await client.Account.CreateAsync(newAccountInfo); //2. Request a certificate. AcmeCertificateRequest certRequest = new AcmeCertificateRequest(); foreach (var dns in dnsNames) { certRequest.Identifiers.Add(new DnsCertificateIdentifier() { Value = dns }); } var certPromise = await client.Certificate.RequestCertificateAsync(account, certRequest); //3. Get challenge var challenges = await client.Challenge.GetChallengesAsync(account, certPromise, ChallengeType.Http); //4. Save Challenge and Account for next step. SaveAccountAndChallengeData(account, challenges, certPromise); }
/// <summary> /// Updates an existing accounts contacts /// </summary> /// <param name="directory">Directory object.</param> /// <param name="nonce">Nonce</param> /// <param name="account">Must be existing account.</param> /// <returns>Return api response with status.</returns> public async Task <AcmeApiResponse> UpdateAccountAsync(AcmeDirectory directory, string nonce, AcmeAccount account) { if (directory == null) { throw new ArgumentNullException("directory"); } if (string.IsNullOrEmpty(directory.NewAccount)) { throw new ArgumentException("directory is missing Account url."); } if (string.IsNullOrEmpty(nonce)) { throw new ArgumentNullException("nonce"); } if (account == null) { throw new ArgumentNullException("account"); } AcmeCreateAccount upd = new AcmeCreateAccount() { Contact = account.Contact, TermsOfServiceAgreed = true }; JwsContainer <AcmeCreateAccount> jwsObject = new JwsContainer <AcmeCreateAccount>(account.SecurityInfo, nonce, account.KID, account.KID, upd); string jwsToken = jwsObject.SerializeSignedToken(); var apiResp = await SendPostData( url : _letsEncryptEndpoint.AppendUrl(ProtoacmeContants.LETSENCRYPT_ACCOUNT_FRAGMENT).AppendUrl(account.Id.ToString()), data : jwsToken); string apiRespString = await apiResp.Content?.ReadAsStringAsync(); if (apiResp.StatusCode != HttpStatusCode.OK) { return(ErrorResponse(apiRespString)); } if (!apiResp.Headers.TryGetValues(ProtoacmeContants.HEADER_NONCE, out IEnumerable <string> nonces)) { return(ErrorResponse <AcmeAccount>("Missing Replay-Nonce Header on CreateAccount (UPDATE) Response.")); } return(new AcmeApiResponse() { Status = AcmeApiResponseStatus.Success, Nonce = nonces.FirstOrDefault() }); }
/// <summary> /// Create a new account. /// </summary> /// <param name="accountDetails">Information for new account.</param> /// <returns>Returns a serializable account object.</returns> public async Task <AcmeAccount> CreateAsync(AcmeCreateAccount accountDetails) { var directory = await _directoryCache.GetAsync(); var nonce = await _nonceCache.GetAsync(); var response = await _acmeApi.CreateAccountAsync(directory, nonce, accountDetails); if (response.Status == AcmeApiResponseStatus.Error) { throw new AcmeProtocolException(response.Message); } _nonceCache.Update(response.Nonce); return(response.Data); }
public async Task CreateAccount_ShouldReturnExpectedNewAccount() { //ARRANGE var acmeApiMock = new Mock <IAcmeRestApi>(); var directoryCacheMock = new Mock <ICachedRepository <AcmeDirectory> >(); var nonceCacheMock = new Mock <ICachedRepository <string> >(); AcmeCreateAccount inputAccount = TestHelpers.CreateAccount; AcmeApiResponse <AcmeAccount> accountResponse = TestHelpers.AcmeAccountResponse; acmeApiMock.Setup(method => method.CreateAccountAsync(It.IsAny <AcmeDirectory>(), It.IsAny <string>(), It.IsAny <AcmeCreateAccount>())) .ReturnsAsync(accountResponse); AcmeAccountService srv = new AcmeAccountService(acmeApiMock.Object, directoryCacheMock.Object, nonceCacheMock.Object); //ACT var expected = await srv.CreateAsync(inputAccount); //ASSERT expected.ShouldBe(accountResponse.Data); }
public async Task CreateAccount_ShouldUpdateLastNonce() { //ARRANGE var acmeApiMock = new Mock <IAcmeRestApi>(); var directoryCacheMock = new Mock <ICachedRepository <AcmeDirectory> >(); var nonceCacheMock = new Mock <ICachedRepository <string> >(); AcmeCreateAccount inputAccount = TestHelpers.CreateAccount; AcmeApiResponse <AcmeAccount> accountResponse = TestHelpers.AcmeAccountResponse; acmeApiMock.Setup(method => method.CreateAccountAsync(It.IsAny <AcmeDirectory>(), It.IsAny <string>(), It.IsAny <AcmeCreateAccount>())) .ReturnsAsync(accountResponse); AcmeAccountService srv = new AcmeAccountService(acmeApiMock.Object, directoryCacheMock.Object, nonceCacheMock.Object); //ACT await srv.CreateAsync(inputAccount); //ASSERT nonceCacheMock.Verify(method => method.Update(accountResponse.Nonce), Times.Once()); }
/// <summary> /// Creates a new account. /// </summary> /// <param name="directory">Directory object.</param> /// <param name="nonce">Nonce</param> /// <param name="account">Information for new account.</param> /// <returns>Returns a serializable account object. Wrapped by a response object.</returns> /// <remarks>It is best to serialize and save the account object so it can be retrieved later and used for renewing domains.</remarks> public async Task <AcmeApiResponse <AcmeAccount> > CreateAccountAsync(AcmeDirectory directory, string nonce, AcmeCreateAccount account) { if (directory == null) { throw new ArgumentNullException("directory"); } if (string.IsNullOrEmpty(directory.NewAccount)) { throw new ArgumentException("directory is missing Account url."); } if (string.IsNullOrEmpty(nonce)) { throw new ArgumentNullException("nonce"); } if (account == null) { throw new ArgumentNullException("account"); } RSACryptoServiceProvider cryptoProvider = new RSACryptoServiceProvider(2048); RSAParameters rsaPrams = cryptoProvider.ExportParameters(true); JwsContainer <AcmeCreateAccount> jwsObject = new JwsContainer <AcmeCreateAccount>(rsaPrams, nonce, directory.NewAccount, account); string jwsToken = jwsObject.SerializeSignedToken(); var apiResp = await SendPostData( url : directory.NewAccount, data : jwsToken); string apiRespString = await apiResp.Content?.ReadAsStringAsync(); if (apiResp.StatusCode != HttpStatusCode.Created) { return(ErrorResponse <AcmeAccount>(apiRespString)); } if (!apiResp.Headers.TryGetValues(ProtoacmeContants.HEADER_LOCATION, out IEnumerable <string> locations)) { return(ErrorResponse <AcmeAccount>("Missing Location Header on CreateAccount Response.")); } if (!apiResp.Headers.TryGetValues(ProtoacmeContants.HEADER_NONCE, out IEnumerable <string> nonces)) { return(ErrorResponse <AcmeAccount>("Missing Replay-Nonce Header on CreateAccount Response.")); } Dictionary <string, object> oResp = JsonConvert.DeserializeObject <Dictionary <string, object> >(apiRespString); var loc = locations.FirstOrDefault(); var id = int.Parse((new Uri(loc)).Segments.Last()); return(new AcmeApiResponse <AcmeAccount>() { Status = AcmeApiResponseStatus.Success, Nonce = nonces.FirstOrDefault(), Data = new AcmeAccount() { Id = id, KID = loc, SecurityInfo = rsaPrams, Contact = account.Contact } }); }