Basic HTTP Auth (#163).

This commit is contained in:
jimafisk 2023-01-31 15:14:31 -05:00
parent 513e79832a
commit faeb8ae499
4 changed files with 125 additions and 4 deletions

View file

@ -25,12 +25,26 @@ func Handler(mainDomainSuffix, rawDomain string,
giteaClient *gitea.Client,
rawInfoPage string,
blacklistedPaths, allowedCorsDomains []string,
dnsLookupCache, canonicalDomainCache cache.SetGetKey,
dnsLookupCache, canonicalDomainCache, authCache cache.SetGetKey,
) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
log := log.With().Strs("Handler", []string{req.Host, req.RequestURI}).Logger()
ctx := context.New(w, req)
trimmedHost := ctx.TrimHostPort()
credentials := handleAuth(log, ctx, giteaClient,
mainDomainSuffix,
trimmedHost,
dnsLookupCache, authCache)
if len(credentials) > 0 {
authenticated := enforceBasicHTTPAuth(credentials, w, req)
if !authenticated {
return
}
}
ctx.RespWriter.Header().Set("Server", "CodebergPages/"+version.Version)
// Force new default from specification (since November 2020) - see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#strict-origin-when-cross-origin
@ -39,8 +53,6 @@ func Handler(mainDomainSuffix, rawDomain string,
// Enable browser caching for up to 10 minutes
ctx.RespWriter.Header().Set("Cache-Control", "public, max-age=600")
trimmedHost := ctx.TrimHostPort()
// Add HSTS for RawDomain and MainDomainSuffix
if hsts := getHSTSHeader(trimmedHost, mainDomainSuffix, rawDomain); hsts != "" {
ctx.RespWriter.Header().Set("Strict-Transport-Security", hsts)
@ -109,5 +121,44 @@ func Handler(mainDomainSuffix, rawDomain string,
pathElements,
dnsLookupCache, canonicalDomainCache)
}
}
}
func enforceBasicHTTPAuth(credentials []string, w http.ResponseWriter, req *http.Request) bool {
authorizedUsers := getAuthorizedUsers(credentials)
username, password, ok := req.BasicAuth()
if !ok {
w.Header().Add("WWW-Authenticate", `Basic realm="Give username and password"`)
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(`{"message": "No basic auth present"}`))
return false
}
if !isAuthorized(username, password, authorizedUsers) {
w.Header().Add("WWW-Authenticate", `Basic realm="Give username and password"`)
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte(`{"message": "Invalid username or password"}`))
return false
}
return true
}
func getAuthorizedUsers(credentials []string) map[string]string {
authorizedUsers := make(map[string]string)
for _, authLine := range credentials {
authLineParts := strings.Split(authLine, ",")
user := strings.TrimSpace(authLineParts[0])
password := strings.TrimSpace(authLineParts[1])
authorizedUsers[user] = password
}
return authorizedUsers
}
func isAuthorized(username, password string, credentials map[string]string) bool {
pass, ok := credentials[username]
if !ok {
return false
}
return password == pass
}

View file

@ -0,0 +1,33 @@
package handler
import (
"codeberg.org/codeberg/pages/server/cache"
"codeberg.org/codeberg/pages/server/context"
"codeberg.org/codeberg/pages/server/dns"
"codeberg.org/codeberg/pages/server/gitea"
"codeberg.org/codeberg/pages/server/upstream"
"github.com/rs/zerolog"
)
func handleAuth(log zerolog.Logger, ctx *context.Context, giteaClient *gitea.Client,
mainDomainSuffix string,
trimmedHost string,
dnsLookupCache, authCache cache.SetGetKey,
) []string {
// Get credentials for a given branch/repo/owner
targetOwner, targetRepo, targetBranch := dns.GetTargetFromDNS(trimmedHost, mainDomainSuffix, dnsLookupCache)
var credentials []string
canonicalLink := false
// Try to use the given repo on the given branch or the default branch
log.Debug().Msg("auth preparations, trying to get credentials")
if targetOpt, works := tryBranch(log, ctx, giteaClient, &upstream.Options{
TargetOwner: targetOwner,
TargetRepo: targetRepo,
TargetBranch: targetBranch,
}, canonicalLink); works {
credentials = targetOpt.CheckAuth(giteaClient, authCache)
}
return credentials
}