Add OAuth 2.0 backend
This commit is contained in:
parent
cca1d579db
commit
ebb5aede92
87
auth/oauth2.go
Normal file
87
auth/oauth2.go
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"git.sr.ht/~emersion/go-oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OAuth2Provider struct {
|
||||||
|
metadata *oauth2.ServerMetadata
|
||||||
|
clientID string
|
||||||
|
clientSecret string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initializes a new OAuth 2.0 auth provider with the given connection string.
|
||||||
|
func NewOAuth2(endpoint, clientID, clientSecret string) (AuthProvider, error) {
|
||||||
|
metadata, err := oauth2.DiscoverServerMetadata(context.Background(), endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch OAuth 2.0 server metadata: %v", err)
|
||||||
|
}
|
||||||
|
return &OAuth2Provider{
|
||||||
|
metadata: metadata,
|
||||||
|
clientID: clientID,
|
||||||
|
clientSecret: clientSecret,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (prov *OAuth2Provider) 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 *OAuth2Provider) doAuth(next http.Handler,
|
||||||
|
w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
auth := r.Header.Get("Authorization")
|
||||||
|
authScheme, creds, _ := strings.Cut(auth, " ")
|
||||||
|
var username, accessToken string
|
||||||
|
switch strings.ToLower(authScheme) {
|
||||||
|
case "bearer":
|
||||||
|
accessToken = creds
|
||||||
|
case "basic":
|
||||||
|
username, accessToken, _ = r.BasicAuth()
|
||||||
|
default:
|
||||||
|
w.Header().Add("WWW-Authenticate", `Bearer, Basic realm="Please provide an OAuth access token", charset="UTF-8"`)
|
||||||
|
http.Error(w, "HTTP auth is required", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client := oauth2.Client{
|
||||||
|
Server: prov.metadata,
|
||||||
|
ClientID: prov.clientID,
|
||||||
|
ClientSecret: prov.clientSecret,
|
||||||
|
}
|
||||||
|
resp, err := client.Introspect(r.Context(), accessToken)
|
||||||
|
if err != nil || !resp.Active {
|
||||||
|
log.Debug().Err(err).Msg("auth error")
|
||||||
|
http.Error(w, "Invalid access token", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if username != "" && username != resp.Username {
|
||||||
|
http.Error(w, "Invalid username", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Username == "" {
|
||||||
|
http.Error(w, "OAuth 2.0 server did not send username", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
authCtx := AuthContext{
|
||||||
|
AuthMethod: "oauth2",
|
||||||
|
UserName: resp.Username,
|
||||||
|
}
|
||||||
|
ctx := NewContext(r.Context(), &authCtx)
|
||||||
|
r = r.WithContext(ctx)
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
}
|
@ -26,6 +26,14 @@ func NewFromURL(authURL string) (AuthProvider, error) {
|
|||||||
return NewHtpasswd(path)
|
return NewHtpasswd(path)
|
||||||
case "null":
|
case "null":
|
||||||
return NewNull()
|
return NewNull()
|
||||||
|
case "http", "https":
|
||||||
|
if u.User == nil {
|
||||||
|
return nil, fmt.Errorf("missing client ID for OAuth 2.0")
|
||||||
|
}
|
||||||
|
clientID := u.User.Username()
|
||||||
|
clientSecret, _ := u.User.Password()
|
||||||
|
u.User = nil
|
||||||
|
return NewOAuth2(u.String(), clientID, clientSecret)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("no auth provider found for %s:// URL", u.Scheme)
|
return nil, fmt.Errorf("no auth provider found for %s:// URL", u.Scheme)
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,13 @@ URL: *pam://* (no parameters)
|
|||||||
_Note:_ The PAM auth backend must be enabled at build time, as PAM may not be
|
_Note:_ The PAM auth backend must be enabled at build time, as PAM may not be
|
||||||
available on all platforms.
|
available on all platforms.
|
||||||
|
|
||||||
|
## OAuth 2.0
|
||||||
|
|
||||||
|
The OAuth 2.0 auth backend delegates authentication to the provided OAuth 2.0
|
||||||
|
server.
|
||||||
|
|
||||||
|
URL: *https://*_client_id_*:*_client_secret_*@*_host_
|
||||||
|
|
||||||
## Static file (htpasswd)
|
## Static file (htpasswd)
|
||||||
|
|
||||||
The static file auth backend relies on the file format popularized by Apache and
|
The static file auth backend relies on the file format popularized by Apache and
|
||||||
|
1
go.mod
1
go.mod
@ -3,6 +3,7 @@ module git.sr.ht/~sircmpwn/tokidoki
|
|||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
git.sr.ht/~emersion/go-oauth2 v0.0.0-20240217160856-2e0d6e20b088
|
||||||
github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f
|
github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f
|
||||||
github.com/emersion/go-imap v1.2.1
|
github.com/emersion/go-imap v1.2.1
|
||||||
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43
|
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43
|
||||||
|
2
go.sum
2
go.sum
@ -1,3 +1,5 @@
|
|||||||
|
git.sr.ht/~emersion/go-oauth2 v0.0.0-20240217160856-2e0d6e20b088 h1:KuPliLD8CQM1WbCHdjHR6mhadIzLaAJCNENmvB1y9gs=
|
||||||
|
git.sr.ht/~emersion/go-oauth2 v0.0.0-20240217160856-2e0d6e20b088/go.mod h1:VHj0jSCLIkrfEwmOvJ4+ykpoVbD/YLN7BM523oKKBHc=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f h1:feGUUxxvOtWVOhTko8Cbmp33a+tU0IMZxMEmnkoAISQ=
|
github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f h1:feGUUxxvOtWVOhTko8Cbmp33a+tU0IMZxMEmnkoAISQ=
|
||||||
github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f/go.mod h1:2MKFUgfNMULRxqZkadG1Vh44we3y5gJAtTBlVsx1BKQ=
|
github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f/go.mod h1:2MKFUgfNMULRxqZkadG1Vh44we3y5gJAtTBlVsx1BKQ=
|
||||||
|
Loading…
Reference in New Issue
Block a user