Skip to content

Commit

Permalink
Start work on moving to hybrid embed or file ased mfa ui
Browse files Browse the repository at this point in the history
  • Loading branch information
NHAS committed May 1, 2023
1 parent 08f58a3 commit f8ef21f
Show file tree
Hide file tree
Showing 17 changed files with 81 additions and 67 deletions.
2 changes: 2 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ type Config struct {
ExposePorts []string `json:",omitempty"`
NAT *bool

MFATemplatesDirectory string `json:",omitempty"`

HelpMail string
Lockout int
ExternalAddress string
Expand Down
Binary file modified internal/router/bpf_bpfeb.o
Binary file not shown.
Binary file modified internal/router/bpf_bpfel.o
Binary file not shown.
17 changes: 14 additions & 3 deletions internal/webserver/authenticators/methods/oidc.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (o *Oidc) RegistrationAPI(w http.ResponseWriter, r *http.Request) {

if router.IsAuthed(clientTunnelIp.String()) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Write([]byte(resources.MfaSuccess))
resources.Render("success.html", w, nil)
return
}

Expand Down Expand Up @@ -132,7 +132,7 @@ func (o *Oidc) AuthorisationAPI(w http.ResponseWriter, r *http.Request) {

if router.IsAuthed(clientTunnelIp.String()) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Write([]byte(resources.MfaSuccess))
resources.Render("success.html", w, nil)
return
}

Expand Down Expand Up @@ -197,7 +197,18 @@ func (o *Oidc) AuthorisationAPI(w http.ResponseWriter, r *http.Request) {
}

w.WriteHeader(http.StatusUnauthorized)
renderTemplate(w, resources.OIDCMFATemplate, msg, rp.GetEndSessionEndpoint())

err := resources.Render("oidc_error.html", w, &resources.Msg{
HelpMail: config.Values().HelpMail,
NumMethods: len(authenticators.MFA),
Message: msg,
URL: rp.GetEndSessionEndpoint(),
})

if err != nil {
log.Println(user.Username, clientTunnelIp, "error rendering oidc_error.html: ", err)
}

return
}

Expand Down
14 changes: 10 additions & 4 deletions internal/webserver/authenticators/methods/totp.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (t *Totp) RegistrationAPI(w http.ResponseWriter, r *http.Request) {

if router.IsAuthed(clientTunnelIp.String()) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Write([]byte(resources.MfaSuccess))
resources.Render("success.html", w, nil)
return
}

Expand Down Expand Up @@ -144,7 +144,7 @@ func (t *Totp) AuthorisationAPI(w http.ResponseWriter, r *http.Request) {

if router.IsAuthed(clientTunnelIp.String()) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Write([]byte(resources.MfaSuccess))
resources.Render("success.html", w, nil)
return
}

Expand Down Expand Up @@ -208,13 +208,19 @@ func (t *Totp) AuthoriseFunc(w http.ResponseWriter, r *http.Request) authenticat
}

func (t *Totp) MFAPromptUI(w http.ResponseWriter, r *http.Request, username, ip string) {
if err := renderTemplate(w, resources.TotpMFAPromptTmpl, "", ""); err != nil {
if err := resources.Render("prompt_mfa_totp.html", w, &resources.Msg{
HelpMail: config.Values().HelpMail,
NumMethods: len(authenticators.MFA),
}); err != nil {
log.Println(username, ip, "unable to render totp prompt template: ", err)
}
}

func (t *Totp) RegistrationUI(w http.ResponseWriter, r *http.Request, username, ip string) {
if err := renderTemplate(w, resources.TotpMFATemplate, "", ""); err != nil {
if err := resources.Render("register_mfa_totp.html", w, &resources.Msg{
HelpMail: config.Values().HelpMail,
NumMethods: len(authenticators.MFA),
}); err != nil {
log.Println(username, ip, "unable to render totp mfa template: ", err)
}
}
Expand Down
16 changes: 12 additions & 4 deletions internal/webserver/authenticators/methods/webauthn.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (wa *Webauthn) RegistrationAPI(w http.ResponseWriter, r *http.Request) {

if router.IsAuthed(clientTunnelIp.String()) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Write([]byte(resources.MfaSuccess))
resources.Render("success.html", w, nil)
return
}

Expand Down Expand Up @@ -171,7 +171,7 @@ func (wa *Webauthn) AuthorisationAPI(w http.ResponseWriter, r *http.Request) {

if router.IsAuthed(clientTunnelIp.String()) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Write([]byte(resources.MfaSuccess))
resources.Render("success.html", w, nil)
return
}

Expand Down Expand Up @@ -291,13 +291,21 @@ func (wa *Webauthn) AuthorisationAPI(w http.ResponseWriter, r *http.Request) {
}

func (wa *Webauthn) MFAPromptUI(w http.ResponseWriter, r *http.Request, username, ip string) {
if err := renderTemplate(w, resources.WebauthnMFAPromptTmpl, "", ""); err != nil {

if err := resources.Render("prompt_mfa_webauthn.html", w, &resources.Msg{
HelpMail: config.Values().HelpMail,
NumMethods: len(authenticators.MFA),
}); err != nil {
log.Println(username, ip, "unable to render weauthn prompt template: ", err)
}
}

func (wa *Webauthn) RegistrationUI(w http.ResponseWriter, r *http.Request, username, ip string) {
if err := renderTemplate(w, resources.WebauthnMFATemplate, "", ""); err != nil {

if err := resources.Render("register_mfa_webauthn.html", w, &resources.Msg{
HelpMail: config.Values().HelpMail,
NumMethods: len(authenticators.MFA),
}); err != nil {
log.Println(username, ip, "unable to render weauthn prompt template: ", err)
}
}
Expand Down
73 changes: 25 additions & 48 deletions internal/webserver/resources/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ package resources
import (
"embed"
"html/template"
"strings"
)
"io"

//go:embed interface.tmpl
var interfaceTemplate string
"github.com/NHAS/wag/internal/config"
)

type Interface struct {
ClientPrivateKey string
Expand All @@ -27,11 +26,6 @@ type Msg struct {
NumMethods int
}

var InterfaceTemplate *template.Template = template.Must(template.New("").Funcs(template.FuncMap{
"StringsJoin": strings.Join,
"Unescape": func(s string) template.HTML { return template.HTML(s) },
}).Parse(interfaceTemplate))

type Menu struct {
MFAMethods []MenuEntry
LastElement int
Expand All @@ -41,50 +35,33 @@ type MenuEntry struct {
Path, FriendlyName string
}

//go:embed register_mfa.html
var mfaRegistrationMenu string

var MFARegistrationMenu *template.Template = template.Must(template.New("").Parse(mfaRegistrationMenu))

//go:embed oidc_error.html
var oidcError string

var OIDCMFATemplate *template.Template = template.Must(template.New("").Parse(oidcError))

//go:embed register_mfa_totp.html
var totpRegistration string

var TotpMFATemplate *template.Template = template.Must(template.New("").Parse(totpRegistration))

//go:embed register_mfa_webauthn.html
var webauthnRegistration string

var WebauthnMFATemplate *template.Template = template.Must(template.New("").Parse(webauthnRegistration))

//go:embed prompt_mfa_totp.html
var totpPrompt string

var TotpMFAPromptTmpl *template.Template = template.Must(template.New("").Parse(totpPrompt))

//go:embed prompt_mfa_webauthn.html
var webauthnPrompt string

var WebauthnMFAPromptTmpl *template.Template = template.Must(template.New("").Parse(webauthnPrompt))

//go:embed qrcode_registration.html
var qrcodeRegistrationDisplayTmplt string

type QrCodeRegistrationDisplay struct {
ImageData template.URL
Username string
}

var DisplayRegistrationAsQRCodeTmpl *template.Template = template.Must(template.New("").Parse(qrcodeRegistrationDisplayTmplt))

// Not a template
//
//go:embed success.html
var MfaSuccess string
//go:embed templates/*
var embeddedUI embed.FS

//go:embed static
var Static embed.FS

// var InterfaceTemplate *template.Template = template.Must(template.New("").Funcs(template.FuncMap{
// "StringsJoin": strings.Join,
// "Unescape": func(s string) template.HTML { return template.HTML(s) },
// }).Parse(interfaceTemplate))

func Render(page string, out io.Writer, data interface{}) error {
return RenderWithFuncs(page, out, data, nil)
}

func RenderWithFuncs(page string, out io.Writer, data interface{}, templateFuncs template.FuncMap) error {
var currentTemplate *template.Template
if len(config.Values().MFATemplatesDirectory) != 0 {
currentTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFiles(page))
} else {
currentTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFS(embeddedUI, page))
}

return currentTemplate.Execute(out, data)
}
File renamed without changes.
File renamed without changes.
26 changes: 18 additions & 8 deletions internal/webserver/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ func index(w http.ResponseWriter, r *http.Request) {

if router.IsAuthed(clientTunnelIp.String()) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Write([]byte(resources.MfaSuccess))
resources.Render("success.html", w, nil)

return
}

Expand Down Expand Up @@ -184,7 +185,8 @@ func registerMFA(w http.ResponseWriter, r *http.Request) {

if router.IsAuthed(clientTunnelIp.String()) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Write([]byte(resources.MfaSuccess))
resources.Render("success.html", w, nil)

return
}

Expand Down Expand Up @@ -227,7 +229,7 @@ func registerMFA(w http.ResponseWriter, r *http.Request) {

menu.LastElement = len(menu.MFAMethods) - 1

err = resources.MFARegistrationMenu.Execute(w, &menu)
err = resources.Render("register_mfa.html", w, &menu)
if err != nil {
log.Println(user.Username, clientTunnelIp, "unable to build template:", err)
http.Error(w, "Server error", 500)
Expand Down Expand Up @@ -256,7 +258,8 @@ func authorise(w http.ResponseWriter, r *http.Request) {

if router.IsAuthed(clientTunnelIp.String()) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
w.Write([]byte(resources.MfaSuccess))
resources.Render("success.html", w, nil)

return
}

Expand Down Expand Up @@ -424,7 +427,7 @@ func registerDevice(w http.ResponseWriter, r *http.Request) {
return
}

i := resources.Interface{
wireguardInterface := resources.Interface{
ClientPrivateKey: keyStr,
ClientAddress: address,
ServerAddress: fmt.Sprintf("%s:%d", config.Values().ExternalAddress, wgPort),
Expand All @@ -438,7 +441,10 @@ func registerDevice(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")

var config bytes.Buffer
err = resources.InterfaceTemplate.Execute(&config, &i)
err = resources.RenderWithFuncs("interface.tmpl", &config, &wireguardInterface, template.FuncMap{
"StringsJoin": strings.Join,
"Unescape": func(s string) template.HTML { return template.HTML(s) },
})
if err != nil {
log.Println(username, remoteAddr, "failed to execute template to generate wireguard config:", err)
http.Error(w, "Server Error", 500)
Expand Down Expand Up @@ -472,7 +478,7 @@ func registerDevice(w http.ResponseWriter, r *http.Request) {
Username: username,
}

err = resources.DisplayRegistrationAsQRCodeTmpl.Execute(w, &qr)
err = resources.Render("qrcode_registration.html", w, &qr)
if err != nil {
log.Println(username, remoteAddr, "failed to execute template to show qr code wireguard config:", err)
http.Error(w, "Server Error", 500)
Expand All @@ -481,7 +487,11 @@ func registerDevice(w http.ResponseWriter, r *http.Request) {

} else {
w.Header().Set("Content-Disposition", "attachment; filename=wg0.conf")
err = resources.InterfaceTemplate.Execute(w, &i)

err = resources.RenderWithFuncs("interface.tmpl", w, &wireguardInterface, template.FuncMap{
"StringsJoin": strings.Join,
"Unescape": func(s string) template.HTML { return template.HTML(s) },
})
if err != nil {
log.Println(username, remoteAddr, "failed to execute template to generate wireguard config:", err)
http.Error(w, "Server Error", 500)
Expand Down

0 comments on commit f8ef21f

Please sign in to comment.