forked from TrueCloudLab/lego
inwx: Two-Factor-Authentication (#1176)
This commit is contained in:
parent
47ed092fca
commit
1a82effaaa
7 changed files with 77 additions and 17 deletions
|
@ -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()
|
||||
|
|
|
@ -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
3
go.mod
|
@ -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
16
go.sum
|
@ -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=
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -12,6 +12,7 @@ const envDomain = envNamespace + "DOMAIN"
|
|||
var envTest = tester.NewEnvTest(
|
||||
EnvUsername,
|
||||
EnvPassword,
|
||||
EnvSharedSecret,
|
||||
EnvSandbox,
|
||||
EnvTTL).
|
||||
WithDomain(envDomain).
|
||||
|
|
Loading…
Reference in a new issue