Skip to content

Commit d003119

Browse files
committed
Add locking of mfa methods when pre-reqs arent met
1 parent 3c51ce8 commit d003119

File tree

12 files changed

+161
-145
lines changed

12 files changed

+161
-145
lines changed

adminui/frontend/src/api/types.ts

-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,6 @@ export interface LoginSettingsResponseDTO {
170170
default_mfa_method: string
171171
enabled_mfa_methods: string[]
172172

173-
domain: string
174173
issuer: string
175174

176175
oidc: OidcResponseDTO

adminui/frontend/src/pages/Settings.vue

+9-6
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,14 @@ function isAcmeValid(): boolean {
223223
function serverCanHaveTLS(domain: string): boolean {
224224
return isAcmeValid() && domain.length > 0
225225
}
226+
227+
function doesTunnelHaveDomain() {
228+
return webserversSettingsData.value.some((x) => x.server_name == 'tunnel' && x.domain.length > 0)
229+
}
230+
231+
function doesTunnelHaveTLS() {
232+
return webserversSettingsData.value.some((x) => x.server_name == 'tunnel' && x.tls)
233+
}
226234
</script>
227235

228236
<template>
@@ -338,6 +346,7 @@ function serverCanHaveTLS(domain: string): boolean {
338346
class="toggle toggle-primary"
339347
:value="method.method"
340348
v-model="loginSettingsData.enabled_mfa_methods"
349+
:disabled="!doesTunnelHaveDomain() && (method.method == 'oidc' || method.method == 'webauthn') || (!doesTunnelHaveTLS() && method.method == 'webauthn')"
341350
:checked="loginSettingsData.enabled_mfa_methods.indexOf(method.method) != -1"
342351
/>
343352
</label>
@@ -370,12 +379,6 @@ function serverCanHaveTLS(domain: string): boolean {
370379
</label>
371380
<input v-model="loginSettingsData.issuer" type="text" required class="input input-bordered w-full" />
372381
</div>
373-
<div class="form-control">
374-
<label class="label font-bold">
375-
<span class="label-text">Internal VPN Domain</span>
376-
</label>
377-
<input v-model="loginSettingsData.domain" type="text" required class="input input-bordered w-full" />
378-
</div>
379382
</div>
380383
</div>
381384

adminui/ui_webserver.go

+13-13
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@ func New(firewall *router.Firewall, errs chan<- error) (ui *AdminUI, err error)
6464
return nil, fmt.Errorf("admin ui failed to start as we could not get wag version: %s", err)
6565
}
6666

67-
if !config.Values.ManagementUI.OIDC.Enabled && !*config.Values.ManagementUI.Password.Enabled {
67+
if !config.Values.Webserver.Management.OIDC.Enabled && !*config.Values.Webserver.Management.Password.Enabled {
6868
return nil, errors.New("neither oidc or password authentication was enabled for the admin user interface, you wont be able to log in despite having it enabled")
6969
}
7070

71-
if config.Values.ManagementUI.OIDC.Enabled {
71+
if config.Values.Webserver.Management.OIDC.Enabled {
7272
key, err := utils.GenerateRandom(32)
7373
if err != nil {
7474
return nil, errors.New("failed to get random key: " + err.Error())
@@ -86,18 +86,18 @@ func New(firewall *router.Firewall, errs chan<- error) (ui *AdminUI, err error)
8686
rp.WithVerifierOpts(rp.WithIssuedAtOffset(5 * time.Second)),
8787
}
8888

89-
u, err := url.Parse(config.Values.ManagementUI.Domain)
89+
u, err := url.Parse(config.Values.Webserver.Management.Domain)
9090
if err != nil {
91-
return nil, fmt.Errorf("failed to parse admin url: %q, err: %s", config.Values.ManagementUI.Domain, err)
91+
return nil, fmt.Errorf("failed to parse admin url: %q, err: %s", config.Values.Webserver.Management.Domain, err)
9292
}
9393

9494
u.Path = path.Join(u.Path, "/login/oidc/callback")
9595
log.Println("[ADMINUI] OIDC callback: ", u.String())
96-
log.Println("[ADMINUI] Connecting to OIDC provider: ", config.Values.ManagementUI.OIDC.IssuerURL)
96+
log.Println("[ADMINUI] Connecting to OIDC provider: ", config.Values.Webserver.Management.OIDC.IssuerURL)
9797

9898
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
9999

100-
adminUI.oidcProvider, err = rp.NewRelyingPartyOIDC(ctx, config.Values.ManagementUI.OIDC.IssuerURL, config.Values.ManagementUI.OIDC.ClientID, config.Values.ManagementUI.OIDC.ClientSecret, u.String(), []string{"openid"}, options...)
100+
adminUI.oidcProvider, err = rp.NewRelyingPartyOIDC(ctx, config.Values.Webserver.Management.OIDC.IssuerURL, config.Values.Webserver.Management.OIDC.ClientID, config.Values.Webserver.Management.OIDC.ClientSecret, u.String(), []string{"openid"}, options...)
101101
cancel()
102102
if err != nil {
103103
return nil, fmt.Errorf("unable to connect to oidc provider for admin ui. err %s", err)
@@ -106,7 +106,7 @@ func New(firewall *router.Firewall, errs chan<- error) (ui *AdminUI, err error)
106106
log.Println("[ADMINUI] Connected to admin oidc provider!")
107107
}
108108

109-
if *config.Values.ManagementUI.Password.Enabled {
109+
if *config.Values.Webserver.Management.Password.Enabled {
110110

111111
admins, err := adminUI.ctrl.ListAdminUsers("")
112112
if err != nil {
@@ -172,7 +172,7 @@ func New(firewall *router.Firewall, errs chan<- error) (ui *AdminUI, err error)
172172
allRoutes.HandleFunc("GET /api/config", adminUI.uiConfig)
173173
allRoutes.HandleFunc("POST /api/refresh", adminUI.doAuthRefresh)
174174

175-
if config.Values.ManagementUI.OIDC.Enabled {
175+
if config.Values.Webserver.Management.OIDC.Enabled {
176176
allRoutes.HandleFunc("GET /login/oidc", func(w http.ResponseWriter, r *http.Request) {
177177
rp.AuthURLHandler(func() string {
178178
r, _ := utils.GenerateRandomHex(32)
@@ -286,15 +286,15 @@ func New(firewall *router.Firewall, errs chan<- error) (ui *AdminUI, err error)
286286
return nil, err
287287
}
288288

289-
log.Println("[ADMINUI] Started Managemnt UI listening:", config.Values.ManagementUI.ListenAddress)
289+
log.Println("[ADMINUI] Started Managemnt UI listening:", config.Values.Webserver.Management.ListenAddress)
290290

291291
return &adminUI, nil
292292
}
293293

294294
func (au *AdminUI) uiConfig(w http.ResponseWriter, r *http.Request) {
295295
m := ConfigResponseDTO{
296-
SSO: config.Values.ManagementUI.OIDC.Enabled,
297-
Password: *config.Values.ManagementUI.Password.Enabled,
296+
SSO: config.Values.Webserver.Management.OIDC.Enabled,
297+
Password: *config.Values.Webserver.Management.Password.Enabled,
298298
}
299299

300300
json.NewEncoder(w).Encode(m)
@@ -330,7 +330,7 @@ func (au *AdminUI) doAuthRefresh(w http.ResponseWriter, r *http.Request) {
330330

331331
func (au *AdminUI) doLogin(w http.ResponseWriter, r *http.Request) {
332332

333-
if !*config.Values.ManagementUI.Password.Enabled {
333+
if !*config.Values.Webserver.Management.Password.Enabled {
334334
http.NotFound(w, r)
335335
return
336336
}
@@ -428,7 +428,7 @@ func (au *AdminUI) Close() {
428428

429429
autotls.Do.Close(data.Management)
430430

431-
if config.Values.ManagementUI.Enabled {
431+
if config.Values.Webserver.Management.Enabled {
432432
log.Println("Stopped Management UI")
433433
}
434434

commands/start.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ func startWag(noIptables bool, cancel <-chan bool, errorChan chan<- error) func(
193193
return
194194
}
195195

196-
if config.Values.ManagementUI.Enabled {
196+
if config.Values.Webserver.Management.Enabled {
197197
adminUI, err = adminui.New(routerFw, errorChan)
198198
if err != nil {
199199
errorChan <- fmt.Errorf("unable to start management web server: %v", err)

internal/config/config.go

+59-56
Original file line numberDiff line numberDiff line change
@@ -52,70 +52,73 @@ type Config struct {
5252
CheckUpdates bool `json:",omitempty"`
5353
NumberProxies int
5454
Proxied bool
55-
ExposePorts []string `json:",omitempty"`
56-
NAT *bool `json:",omitempty"`
55+
56+
ExposePorts []string `json:",omitempty"`
57+
NAT *bool `json:",omitempty"`
5758

5859
MFATemplatesDirectory string `json:",omitempty"`
5960

60-
HelpMail string
61-
Lockout int
62-
ExternalAddress string
63-
MaxSessionLifetimeMinutes int
64-
SessionInactivityTimeoutMinutes int
61+
Webserver struct {
62+
Acme struct {
63+
Email string
64+
CAProvider string
65+
CloudflareDNSToken string
66+
}
6567

66-
DownloadConfigFileName string `json:",omitempty"`
68+
Public struct {
69+
webserverDetails
70+
DownloadConfigFileName string `json:",omitempty"`
71+
ExternalAddress string
72+
}
6773

68-
Acme struct {
69-
Email string
70-
CAProvider string
71-
CloudflareDNSToken string
72-
}
74+
Lockout int
7375

74-
ManagementUI struct {
75-
Enabled bool
76+
Tunnel struct {
77+
Port string
78+
Domain string
79+
TLS bool
7680

77-
webserverDetails
81+
HelpMail string
7882

79-
Password struct {
80-
Enabled *bool `json:",omitempty"`
81-
} `json:",omitempty"`
83+
MaxSessionLifetimeMinutes int
84+
SessionInactivityTimeoutMinutes int
8285

83-
OIDC struct {
84-
IssuerURL string
85-
ClientSecret string
86-
ClientID string
87-
Enabled bool
88-
} `json:",omitempty"`
89-
} `json:",omitempty"`
86+
DefaultMethod string `json:",omitempty"`
87+
Issuer string
88+
Methods []string `json:",omitempty"`
9089

91-
Webserver struct {
92-
Public webserverDetails
90+
OIDC struct {
91+
IssuerURL string
92+
ClientSecret string
93+
ClientID string
94+
GroupsClaimName string `json:",omitempty"`
95+
} `json:",omitempty"`
9396

94-
Tunnel struct {
95-
Port string
96-
Domain string
97-
TLS bool
97+
PAM struct {
98+
ServiceName string
99+
} `json:",omitempty"`
98100
}
99-
}
100101

101-
Clustering ClusteringDetails
102+
Management struct {
103+
webserverDetails
102104

103-
Authenticators struct {
104-
DefaultMethod string `json:",omitempty"`
105-
Issuer string
106-
Methods []string `json:",omitempty"`
105+
Enabled bool
107106

108-
OIDC struct {
109-
IssuerURL string
110-
ClientSecret string
111-
ClientID string
112-
GroupsClaimName string `json:",omitempty"`
113-
} `json:",omitempty"`
107+
Password struct {
108+
Enabled *bool `json:",omitempty"`
109+
} `json:",omitempty"`
114110

115-
PAM struct {
116-
ServiceName string
111+
OIDC struct {
112+
IssuerURL string
113+
ClientSecret string
114+
ClientID string
115+
Enabled bool
116+
} `json:",omitempty"`
117117
} `json:",omitempty"`
118118
}
119+
120+
Clustering ClusteringDetails
121+
119122
Wireguard struct {
120123
DevName string
121124
ListenPort int
@@ -157,8 +160,8 @@ func load(path string) (c Config, err error) {
157160
c.Socket = control.DefaultWagSocket
158161
}
159162

160-
if c.DownloadConfigFileName == "" {
161-
c.DownloadConfigFileName = "wg0.conf"
163+
if c.Webserver.Public.DownloadConfigFileName == "" {
164+
c.Webserver.Public.DownloadConfigFileName = "wg0.conf"
162165
}
163166

164167
if c.Proxied {
@@ -225,20 +228,20 @@ func load(path string) (c Config, err error) {
225228
*c.NAT = true
226229
}
227230

228-
err = validators.ValidExternalAddresses(c.ExternalAddress)
231+
err = validators.ValidExternalAddresses(c.Webserver.Public.ExternalAddress)
229232
if err != nil {
230233
return c, err
231234
}
232235

233-
if c.Lockout <= 0 {
236+
if c.Webserver.Lockout <= 0 {
234237
return c, errors.New("lockout policy unconfigured")
235238
}
236239

237-
if c.MaxSessionLifetimeMinutes == 0 {
240+
if c.Webserver.Tunnel.MaxSessionLifetimeMinutes == 0 {
238241
return c, errors.New("session max lifetime policy is not set (may be disabled by setting it to -1)")
239242
}
240243

241-
if c.SessionInactivityTimeoutMinutes == 0 {
244+
if c.Webserver.Tunnel.SessionInactivityTimeoutMinutes == 0 {
242245
return c, errors.New("session inactivity timeout policy is not set (may be disabled by setting it to -1)")
243246
}
244247

@@ -329,13 +332,13 @@ func load(path string) (c Config, err error) {
329332
}
330333
}
331334

332-
if len(c.Authenticators.Methods) == 1 {
333-
c.Authenticators.DefaultMethod = c.Authenticators.Methods[len(c.Authenticators.Methods)-1]
335+
if len(c.Webserver.Tunnel.Methods) == 1 {
336+
c.Webserver.Tunnel.DefaultMethod = c.Webserver.Tunnel.Methods[len(c.Webserver.Tunnel.Methods)-1]
334337
}
335338

336-
if c.ManagementUI.Password.Enabled == nil {
339+
if c.Webserver.Management.Password.Enabled == nil {
337340
enabled := true
338-
c.ManagementUI.Password.Enabled = &enabled
341+
c.Webserver.Management.Password.Enabled = &enabled
339342
}
340343

341344
return c, nil

internal/data/clustering.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,8 @@ func AddMember(name, etcPeerUrlAddress, newManagerAddressURL string) (joinToken
226226
copyValues.Acls = config.Acls{}
227227
copyValues.Acls.Groups = map[string][]string{}
228228

229-
copyValues.ManagementUI.Enabled = false
230-
copyValues.ManagementUI.ListenAddress = ""
229+
copyValues.Webserver.Management.Enabled = false
230+
copyValues.Webserver.Management.ListenAddress = ""
231231

232232
b, _ := json.Marshal(copyValues)
233233
token.SetAdditional("config.json", string(b))

0 commit comments

Comments
 (0)