Merge branch 'lordelph-master'

# Conflicts:
#	src/Data/Authorization.php
This commit is contained in:
peterbakker
2020-03-18 19:57:43 +01:00
4 changed files with 111 additions and 0 deletions

View File

@@ -117,6 +117,53 @@ foreach ($authorizations as $authorization) {
The code above will first perform a self test and, if successful, will do 15 attempts to ask LetsEncrypt to validate the challenge (with 1 second intervals) and
retrieve an updated status (it might take Lets Encrypt a few seconds to validate the challenge).
### Alternative ownership validation via DNS
You can also use DNS validation - to do this, you will need access to an API for your DNS
provider to create TXT records for the target domains.
```php
//store a map of domain=>TXT record we can use to wait with
$dnsRecords[];
foreach ($authorizations as $authorization) {
$challenge = $authorization->getDnsChallenge();
$txtRecord = $authorization->getTxtRecord($challenge);
$domain=$authorization->getDomain();
$validationDomain='_acme-challenge.'.$domain;
//remember the record we're about to set
$dnsRecords[$validationDomain] = $txtRecord;
//set TXT record for $validationDomain to $txtRecord value
//--
//-- you need to add code for your DNS provider here
//--
}
```
A helper is included which will allow you to wait until you can see the
DNS changes before asking Let's Encrypt to validate it, e.g.
```php
//wait up to 60 seconds for all our DNS updates to propagate
if (!Helper::waitForDNS($dnsRecords, 60)) {
throw new \Exception('Unable to verify TXT record update');
}
```
Once this passes we can ask Let's Encrypt to do the same...
```php
foreach ($authorizations as $authorization) {
$ok = $client->validate($authorization->getDnsChallenge(), 15);
}
```
### Get the certificate
Now to know if we can request a certificate for the order, test if the order is ready as follows:

View File

@@ -55,6 +55,11 @@ class Client
*/
const VALIDATION_HTTP = 'http-01';
/**
* DNS validation
*/
const VALIDATION_DNS = 'dns-01';
/**
* @var string
*/

View File

@@ -3,6 +3,7 @@
namespace Afosto\Acme\Data;
use Afosto\Acme\Client;
use Afosto\Acme\Helper;
class Authorization
{
@@ -93,6 +94,20 @@ class Authorization
return false;
}
/**
* @return Challenge|bool
*/
public function getDnsChallenge()
{
foreach ($this->getChallenges() as $challenge) {
if ($challenge->getType() == Client::VALIDATION_DNS) {
return $challenge;
}
}
return false;
}
/**
* Return File object for the given challenge
* @return File|bool
@@ -105,4 +120,15 @@ class Authorization
}
return false;
}
/**
* @param Challenge $challenge
* @return string containing TXT record for DNS challenge
*/
public function getTxtRecord(Challenge $challenge)
{
$raw=$challenge->getToken() . '.' . $this->digest;
$hash=hash('sha256', $raw, true);
return Helper::toSafeString($hash);
}
}

View File

@@ -140,4 +140,37 @@ class Helper
return $accountDetails;
}
/**
* Wait until a set of DNS records return specific TXT record values
*
* @param array mapping domain to desired TXT record value
* @param $txtRecord
* @param int $maxSeconds to wait
* @return bool true if record found, false otherwise
*/
public static function waitForDNS(array $records, $maxSeconds=60)
{
$waitUntil = time() + $maxSeconds;
do {
//validate all remaining records..
foreach($records as $domain=>$txtRecord) {
$record=dns_get_record($domain, DNS_TXT);
if (isset($record[0]['txt']) && ($record[0]['txt']===$txtRecord)) {
unset($records[$domain]);
}
}
//did we find them all?
if (empty($records)) {
return true;
}
//otherwise still domains to check...have a short sleep
sleep(1);
} while(time() < $waitUntil);
return false;
}
}