feat(auth): add username header

This commit is contained in:
Nicolas Carlier 2023-02-13 21:17:46 +00:00
parent 13194eb0ca
commit 2fb8e9aa84
5 changed files with 28 additions and 9 deletions

View File

@ -150,6 +150,14 @@ You have several ways to provide parameters to your webhook script:
Therefore the name can be altered. Therefore the name can be altered.
*ex: `CONTENT-TYPE` will become `content_type`.* *ex: `CONTENT-TYPE` will become `content_type`.*
Webhookd adds some additional parameters to the script:
- `hook_id`: hook ID (auto-increment)
- `hook_name`: hook name
- `hook_method`: HTTP request method
- `x_forwarded_for`: client IP
- `x_webauth_user`: username if authentication is enabled
*Example:* *Example:*
The script: The script:

View File

@ -4,7 +4,8 @@ import (
"net/http" "net/http"
) )
// Authenticator is a generic interface to validate an HTTP request // Authenticator is a generic interface to validate HTTP request credentials.
// It's returns the authentication result along with the principal (username) if it has one.
type Authenticator interface { type Authenticator interface {
Validate(r *http.Request) bool Validate(r *http.Request) (bool, *string)
} }

View File

@ -52,12 +52,12 @@ func NewHtpasswdFromFile(path string) (*HtpasswdFile, error) {
} }
// Validate HTTP request credentials // Validate HTTP request credentials
func (h *HtpasswdFile) Validate(r *http.Request) bool { func (h *HtpasswdFile) Validate(r *http.Request) (bool, *string) {
user, passwd, ok := r.BasicAuth() user, passwd, ok := r.BasicAuth()
if !ok { if ok && h.validateCredentials(user, passwd) {
return false return true, &user
} }
return h.validateCredentials(user, passwd) return false, nil
} }
func (h *HtpasswdFile) validateCredentials(user string, password string) bool { func (h *HtpasswdFile) validateCredentials(user string, password string) bool {

View File

@ -16,8 +16,12 @@ func TestValidateCredentials(t *testing.T) {
req, err := http.NewRequest("POST", "http://localhost:8080", nil) req, err := http.NewRequest("POST", "http://localhost:8080", nil)
assert.Nil(t, err, "") assert.Nil(t, err, "")
req.SetBasicAuth("foo", "bar") req.SetBasicAuth("foo", "bar")
assert.Equal(t, true, htpasswdFile.Validate(req), "credentials should be valid") ok, username := htpasswdFile.Validate(req)
assert.Equal(t, true, ok, "credentials should be valid")
assert.Equal(t, "foo", *username, "invalid username")
req.SetBasicAuth("foo", "bad") req.SetBasicAuth("foo", "bad")
assert.Equal(t, false, htpasswdFile.Validate(req), "credentials should not be valid") ok, username = htpasswdFile.Validate(req)
assert.Equal(t, false, ok, "credentials should be invalid")
assert.True(t, username == nil, "username should be nil")
} }

View File

@ -6,11 +6,17 @@ import (
"github.com/ncarlier/webhookd/pkg/auth" "github.com/ncarlier/webhookd/pkg/auth"
) )
const xWebAuthUser = "X-WebAuth-User"
// AuthN is a middleware to checks HTTP request credentials // AuthN is a middleware to checks HTTP request credentials
func AuthN(authenticator auth.Authenticator) Middleware { func AuthN(authenticator auth.Authenticator) Middleware {
return func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if authenticator.Validate(r) { w.Header().Del(xWebAuthUser)
if ok, username := authenticator.Validate(r); ok {
if username != nil {
w.Header().Set(xWebAuthUser, *username)
}
next.ServeHTTP(w, r) next.ServeHTTP(w, r)
return return
} }