inwx: Two-Factor-Authentication (#1176)

This commit is contained in:
Ludovic Fernandez 2020-05-31 15:18:43 +02:00 committed by GitHub
parent 47ed092fca
commit 1a82effaaa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 77 additions and 17 deletions

View file

@ -941,6 +941,7 @@ func displayDNSHelp(name string) error {
ew.writeln(` - "INWX_POLLING_INTERVAL": Time between DNS propagation check`)
ew.writeln(` - "INWX_PROPAGATION_TIMEOUT": Maximum waiting time for DNS propagation`)
ew.writeln(` - "INWX_SANDBOX": Activate the sandbox (boolean)`)
ew.writeln(` - "INWX_SHARED_SECRET": shared secret related to 2FA`)
ew.writeln(` - "INWX_TTL": The TTL of the TXT record used for the DNS challenge`)
ew.writeln()

View file

@ -18,9 +18,19 @@ Configuration for [INWX](https://www.inwx.de/en).
- Code: `inwx`
{{% notice note %}}
_Please contribute by adding a CLI example._
{{% /notice %}}
Here is an example bash command using the INWX provider:
```bash
INWX_USERNAME=xxxxxxxxxx \
INWX_PASSWORD=yyyyyyyyyy \
lego --dns inwx --domains my.domain.com --email my@email.com run
# 2FA
INWX_USERNAME=xxxxxxxxxx \
INWX_PASSWORD=yyyyyyyyyy \
INWX_SHARED_SECRET=zzzzzzzzzz \
lego --dns inwx --domains my.domain.com --email my@email.com run
```
@ -43,6 +53,7 @@ More information [here](/lego/dns/#configuration-and-credentials).
| `INWX_POLLING_INTERVAL` | Time between DNS propagation check |
| `INWX_PROPAGATION_TIMEOUT` | Maximum waiting time for DNS propagation |
| `INWX_SANDBOX` | Activate the sandbox (boolean) |
| `INWX_SHARED_SECRET` | shared secret related to 2FA |
| `INWX_TTL` | The TTL of the TXT record used for the DNS challenge |
The environment variable names can be suffixed by `_FILE` to reference a file instead of a value.

3
go.mod
View file

@ -30,10 +30,11 @@ require (
github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04
github.com/nrdcg/auroradns v1.0.1
github.com/nrdcg/dnspod-go v0.4.0
github.com/nrdcg/goinwx v0.6.1
github.com/nrdcg/goinwx v0.7.0
github.com/nrdcg/namesilo v0.2.1
github.com/oracle/oci-go-sdk v7.0.0+incompatible
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014
github.com/pquerna/otp v1.2.0
github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2
github.com/sacloud/libsacloud v1.26.1
github.com/stretchr/testify v1.5.1

16
go.sum
View file

@ -70,6 +70,8 @@ github.com/aws/aws-sdk-go v1.30.20/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZve
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/cenkalti/backoff/v4 v4.0.0 h1:6VeaLF9aI+MAUQ95106HwWzYZgJJpZ4stumjj6RFYAU=
github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
github.com/census-instrumentation/opencensus-proto v0.2.0 h1:LzQXZOgg4CQfE6bFvXGM30YZL1WW/M337pXml+GrcZ4=
@ -202,8 +204,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181 h1:TrxPzApUukas24OMMVDUMlCs1XCExJtnGaDEiIAR4oQ=
github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b h1:DzHy0GlWeF0KAglaTMY7Q+khIFoG8toHP+wLFBVBQJc=
github.com/kolo/xmlrpc v0.0.0-20200310150728-e0350524596b/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -231,8 +233,8 @@ github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.3.1 h1:cCBH2gTD2K0OtLlv/Y5H01VQCqmlDxz30kS5Y5bqfLA=
github.com/mitchellh/mapstructure v1.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -249,8 +251,8 @@ github.com/nrdcg/auroradns v1.0.1 h1:m/kBq83Xvy3cU261MOknd8BdnOk12q4lAWM+kOdsC2Y
github.com/nrdcg/auroradns v1.0.1/go.mod h1:y4pc0i9QXYlFCWrhWrUSIETnZgrf4KuwjDIWmmXo3JI=
github.com/nrdcg/dnspod-go v0.4.0 h1:c/jn1mLZNKF3/osJ6mz3QPxTudvPArXTjpkmYj0uK6U=
github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
github.com/nrdcg/goinwx v0.6.1 h1:AJnjoWPELyCtofhGcmzzcEMFd9YdF2JB/LgutWsWt/s=
github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ=
github.com/nrdcg/goinwx v0.7.0 h1:j6JlOp0nNwtvaP09TvKqc9pktjH81nOad0+Gx9S1t9U=
github.com/nrdcg/goinwx v0.7.0/go.mod h1:4tKJOCi/1lTxuw9/yB2Ez0aojwtUCSkckjc22eALpqE=
github.com/nrdcg/namesilo v0.2.1 h1:kLjCjsufdW/IlC+iSfAqj0iQGgKjlbUUeDJio5Y6eMg=
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
@ -270,6 +272,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok=
github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=

View file

@ -10,6 +10,7 @@ import (
"github.com/go-acme/lego/v3/log"
"github.com/go-acme/lego/v3/platform/config/env"
"github.com/nrdcg/goinwx"
"github.com/pquerna/otp/totp"
)
// Environment variables names.
@ -18,6 +19,7 @@ const (
EnvUsername = envNamespace + "USERNAME"
EnvPassword = envNamespace + "PASSWORD"
EnvSharedSecret = envNamespace + "SHARED_SECRET"
EnvSandbox = envNamespace + "SANDBOX"
EnvTTL = envNamespace + "TTL"
@ -29,6 +31,7 @@ const (
type Config struct {
Username string
Password string
SharedSecret string
Sandbox bool
PropagationTimeout time.Duration
PollingInterval time.Duration
@ -53,7 +56,7 @@ type DNSProvider struct {
// NewDNSProvider returns a DNSProvider instance configured for Dyn DNS.
// Credentials must be passed in the environment variables:
// INWX_USERNAME and INWX_PASSWORD.
// INWX_USERNAME, INWX_PASSWORD, and INWX_SHARED_SECRET.
func NewDNSProvider() (*DNSProvider, error) {
values, err := env.Get(EnvUsername, EnvPassword)
if err != nil {
@ -63,6 +66,7 @@ func NewDNSProvider() (*DNSProvider, error) {
config := NewDefaultConfig()
config.Username = values[EnvUsername]
config.Password = values[EnvPassword]
config.SharedSecret = env.GetOrFile(EnvSharedSecret)
return NewDNSProviderConfig(config)
}
@ -95,7 +99,7 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
return fmt.Errorf("inwx: %w", err)
}
err = d.client.Account.Login()
info, err := d.client.Account.Login()
if err != nil {
return fmt.Errorf("inwx: %w", err)
}
@ -107,6 +111,11 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
}
}()
err = d.twoFactorAuth(info)
if err != nil {
return fmt.Errorf("inwx: %w", err)
}
var request = &goinwx.NameserverRecordRequest{
Domain: dns01.UnFqdn(authZone),
Name: dns01.UnFqdn(fqdn),
@ -140,7 +149,7 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
return fmt.Errorf("inwx: %w", err)
}
err = d.client.Account.Login()
info, err := d.client.Account.Login()
if err != nil {
return fmt.Errorf("inwx: %w", err)
}
@ -152,6 +161,11 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
}
}()
err = d.twoFactorAuth(info)
if err != nil {
return fmt.Errorf("inwx: %w", err)
}
response, err := d.client.Nameservers.Info(&goinwx.NameserverInfoRequest{
Domain: dns01.UnFqdn(authZone),
Name: dns01.UnFqdn(fqdn),
@ -177,3 +191,20 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval
}
func (d *DNSProvider) twoFactorAuth(info *goinwx.LoginResponse) error {
if info.TFA != "GOOGLE-AUTH" {
return nil
}
if d.config.SharedSecret == "" {
return errors.New("two factor authentication but no shared secret is given")
}
tan, err := totp.GenerateCode(d.config.SharedSecret, time.Now())
if err != nil {
return err
}
return d.client.Account.Unlock(tan)
}

View file

@ -4,13 +4,24 @@ URL = "https://www.inwx.de/en"
Code = "inwx"
Since = "v2.0.0"
Example = ''''''
Example = '''
INWX_USERNAME=xxxxxxxxxx \
INWX_PASSWORD=yyyyyyyyyy \
lego --dns inwx --domains my.domain.com --email my@email.com run
# 2FA
INWX_USERNAME=xxxxxxxxxx \
INWX_PASSWORD=yyyyyyyyyy \
INWX_SHARED_SECRET=zzzzzzzzzz \
lego --dns inwx --domains my.domain.com --email my@email.com run
'''
[Configuration]
[Configuration.Credentials]
INWX_USERNAME = "Username"
INWX_PASSWORD = "Password"
[Configuration.Additional]
INWX_SHARED_SECRET = "shared secret related to 2FA"
INWX_POLLING_INTERVAL = "Time between DNS propagation check"
INWX_PROPAGATION_TIMEOUT = "Maximum waiting time for DNS propagation"
INWX_TTL = "The TTL of the TXT record used for the DNS challenge"

View file

@ -12,6 +12,7 @@ const envDomain = envNamespace + "DOMAIN"
var envTest = tester.NewEnvTest(
EnvUsername,
EnvPassword,
EnvSharedSecret,
EnvSandbox,
EnvTTL).
WithDomain(envDomain).