~sircmpwn/tokidoki-devel

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
1

[PATCH] auth: add PAM support

Details
Message ID
<20220910171315.59618-1-contact@emersion.fr>
DKIM signature
missing
Download raw message
Patch: +99 -1
Handy for small local installations.

Disabled by default because it adds a dependency on the PAM
library.
---
 README.md        |  1 +
 auth/pam.go      | 79 ++++++++++++++++++++++++++++++++++++++++++++++++
 auth/pam_stub.go | 11 +++++++
 auth/url.go      |  2 ++
 go.mod           |  5 ++-
 go.sum           |  2 ++
 6 files changed, 99 insertions(+), 1 deletion(-)
 create mode 100644 auth/pam.go
 create mode 100644 auth/pam_stub.go

diff --git a/README.md b/README.md
index 9481bf48155b..1b8c75b91f85 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ It currently provides:
Authentication:

* IMAP (working)
* PAM (working, enabled via the `pam` build tag)

Storage:

diff --git a/auth/pam.go b/auth/pam.go
new file mode 100644
index 000000000000..bd94e1280b0b
--- /dev/null
+++ b/auth/pam.go
@@ -0,0 +1,79 @@
//go:build pam

package auth

import (
	"fmt"
	"net/http"

	"github.com/msteinert/pam"

	"git.sr.ht/~sircmpwn/tokidoki/debug"
)

type pamProvider struct{}

func NewPAM() (AuthProvider, error) {
	return pamProvider{}, nil
}

func (pamProvider) Middleware() func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			pamAuth(next, w, r)
		})
	}
}

func pamAuth(next http.Handler, w http.ResponseWriter, r *http.Request) {
	user, pass, ok := r.BasicAuth()
	if !ok {
		w.Header().Add("WWW-Authenticate", `Basic realm="Please provide your system credentials", charset="UTF-8"`)
		http.Error(w, "HTTP Basic auth is required", http.StatusUnauthorized)
		return
	}

	t, err := pam.StartFunc("login", user, func(s pam.Style, msg string) (string, error) {
		debug.Printf("%v %v", s, msg)
		switch s {
		case pam.PromptEchoOff:
			return pass, nil
		case pam.PromptEchoOn, pam.ErrorMsg, pam.TextInfo:
			return "", nil
		default:
			return "", fmt.Errorf("unsupported PAM conversation style: %v", s)
		}
	})
	if err != nil {
		debug.Printf("Failed to start PAM conversation: %v", err)
		http.Error(w, "Temporary authentication error, try again later", http.StatusServiceUnavailable)
		return
	}

	if err := t.Authenticate(0); err != nil {
		debug.Printf("Auth error: %v", err)
		http.Error(w, "Invalid username or password", http.StatusUnauthorized)
		return
	}

	if err := t.AcctMgmt(0); err != nil {
		debug.Printf("Account unavailable: %v", err)
		http.Error(w, "Account unavailable", http.StatusUnauthorized)
		return
	}

	user, err = t.GetItem(pam.User)
	if err != nil {
		debug.Printf("Failed to get PAM username: %v", err)
		http.Error(w, "Temporary authentication error, try again later", http.StatusServiceUnavailable)
		return
	}

	authCtx := AuthContext{
		AuthMethod: "pam",
		UserName:   user,
	}
	ctx := NewContext(r.Context(), &authCtx)
	r = r.WithContext(ctx)
	next.ServeHTTP(w, r)
}
diff --git a/auth/pam_stub.go b/auth/pam_stub.go
new file mode 100644
index 000000000000..c11a36785f05
--- /dev/null
+++ b/auth/pam_stub.go
@@ -0,0 +1,11 @@
//go:build !pam

package auth

import (
	"errors"
)

func NewPAM() (AuthProvider, error) {
	return nil, errors.New("PAM support is disabled")
}
diff --git a/auth/url.go b/auth/url.go
index 1f0fc0f435fc..6c1a99feaf73 100644
--- a/auth/url.go
+++ b/auth/url.go
@@ -16,6 +16,8 @@ func NewFromURL(authURL string) (AuthProvider, error) {
		return NewIMAP(u.Host, false), nil
	case "imaps":
		return NewIMAP(u.Host, true), nil
	case "pam":
		return NewPAM()
	default:
		return nil, fmt.Errorf("no auth provider found for %s:// URL", u.Scheme)
	}
diff --git a/go.mod b/go.mod
index e8c86aa09725..83db2104c561 100644
--- a/go.mod
+++ b/go.mod
@@ -11,4 +11,7 @@ require (
	github.com/go-chi/chi/v5 v5.0.7
)

require golang.org/x/text v0.3.7 // indirect
require (
	github.com/msteinert/pam v1.0.0 // indirect
	golang.org/x/text v0.3.7 // indirect
)
diff --git a/go.sum b/go.sum
index 8601ce7eeca2..9fe49cb225f3 100644
--- a/go.sum
+++ b/go.sum
@@ -14,6 +14,8 @@ github.com/emersion/go-webdav v0.3.2-0.20220603063605-db966a275c93 h1:NNvUjFHONR
github.com/emersion/go-webdav v0.3.2-0.20220603063605-db966a275c93/go.mod h1:uSM1VveeKtogBVWaYccTksToczooJ0rrVGNsgnDsr4Q=
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/msteinert/pam v1.0.0 h1:4XoXKtMCH3+e6GIkW41uxm6B37eYqci/DH3gzSq7ocg=
github.com/msteinert/pam v1.0.0/go.mod h1:M4FPeAW8g2ITO68W8gACDz13NDJyOQM9IQsQhrR6TOI=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=

base-commit: 228384530e2b08f22cfb84c62694278067ca5133
-- 
2.37.3
Details
Message ID
<10c11a7e-57b9-a00b-6fcc-f206754da011@bitfehler.net>
In-Reply-To
<20220910171315.59618-1-contact@emersion.fr> (view parent)
DKIM signature
missing
Download raw message
Nice! Applied, thanks a lot.
Reply to thread Export thread (mbox)