mirror of
https://git.sr.ht/~sircmpwn/tokidoki
synced 2025-12-15 21:14:16 +01:00
Implement IMAP auth provider
This commit is contained in:
parent
96ef5f9b2a
commit
5a641ceca1
7 changed files with 100 additions and 1 deletions
66
auth/imap.go
66
auth/imap.go
|
|
@ -0,0 +1,66 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/emersion/go-imap/client"
|
||||
"github.com/emersion/go-sasl"
|
||||
)
|
||||
|
||||
type IMAPProvider struct {
|
||||
addr string
|
||||
tls bool
|
||||
}
|
||||
|
||||
// Initializes a new IMAP auth provider with the given connection string.
|
||||
func NewIMAP(addr string, tls bool) AuthProvider {
|
||||
prov := &IMAPProvider{addr, tls}
|
||||
conn, err := prov.dial()
|
||||
if err != nil {
|
||||
log.Fatalf("Error dialing configured IMAP auth server: %s", err.Error())
|
||||
}
|
||||
conn.Close()
|
||||
return prov
|
||||
}
|
||||
|
||||
func (prov *IMAPProvider) Middleware() func(http.Handler) http.Handler {
|
||||
return func (next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
prov.doAuth(next, w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (prov *IMAPProvider) doAuth(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 IMAP credentials", charset="UTF-8"`)
|
||||
http.Error(w, "HTTP Basic auth is required", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
conn, err := prov.dial()
|
||||
if err != nil {
|
||||
http.Error(w, "Temporary authentication error, try again later", http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
auth := sasl.NewPlainClient("", user, pass)
|
||||
if err := conn.Authenticate(auth); err != nil {
|
||||
http.Error(w, "Invalid username or password", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (prov *IMAPProvider) dial() (*client.Client, error) {
|
||||
if prov.tls {
|
||||
return client.DialTLS(prov.addr, nil)
|
||||
} else {
|
||||
return client.Dial(prov.addr)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package auth
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Abstracts the authentication backend for the server.
|
||||
type AuthProvider interface {
|
||||
// Returns HTTP middleware for performing authentication.
|
||||
Middleware() func(http.Handler) http.Handler
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue