mirror of
https://github.com/pomerium/pomerium.git
synced 2025-06-11 07:12:59 +02:00
Simplified, and de-duplicated many of the configuration settings. Removed configuration settings that could be deduced from other settings. Added some basic documentation. Removed the (duplicate?) user email domain validation check in proxy. Removed the ClientID middleware check. Added a shared key option to be used as a PSK instead of using the IDPs ClientID and ClientSecret. Removed the CookieSecure setting as we only support secure. Added a letsencrypt script to generate a wildcard certificate. Removed the argument in proxy's constructor that allowed arbitrary fucntions to be passed in as validators. Updated proxy's authenticator client to match the server implementation of just using a PSK. Moved debug-mode logging into the log package. Removed unused approval prompt setting. Fixed a bug where identity provider urls were hardcoded. Removed a bunch of unit tests. There have been so many changes many of these tests don't make sense and will need to be re-thought.
145 lines
3.6 KiB
Go
145 lines
3.6 KiB
Go
package log // import "github.com/pomerium/pomerium/internal/log"
|
|
|
|
import (
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Used to stash the authenticated user in the response for access when logging requests.
|
|
const loggingUserHeader = "SSO-Authenticated-User"
|
|
const gapMetaDataHeader = "GAP-Auth"
|
|
|
|
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP status
|
|
// code and body size
|
|
type responseLogger struct {
|
|
w http.ResponseWriter
|
|
status int
|
|
size int
|
|
proxyHost string
|
|
authInfo string
|
|
}
|
|
|
|
func (l *responseLogger) Header() http.Header {
|
|
return l.w.Header()
|
|
}
|
|
|
|
func (l *responseLogger) extractUser() {
|
|
authInfo := l.w.Header().Get(loggingUserHeader)
|
|
if authInfo != "" {
|
|
l.authInfo = authInfo
|
|
l.w.Header().Del(loggingUserHeader)
|
|
}
|
|
}
|
|
|
|
func (l *responseLogger) ExtractGAPMetadata() {
|
|
authInfo := l.w.Header().Get(gapMetaDataHeader)
|
|
if authInfo != "" {
|
|
l.authInfo = authInfo
|
|
|
|
l.w.Header().Del(gapMetaDataHeader)
|
|
}
|
|
}
|
|
|
|
func (l *responseLogger) Write(b []byte) (int, error) {
|
|
if l.status == 0 {
|
|
// The status will be StatusOK if WriteHeader has not been called yet
|
|
l.status = http.StatusOK
|
|
}
|
|
l.extractUser()
|
|
l.ExtractGAPMetadata()
|
|
|
|
size, err := l.w.Write(b)
|
|
l.size += size
|
|
return size, err
|
|
}
|
|
|
|
func (l *responseLogger) WriteHeader(s int) {
|
|
l.extractUser()
|
|
l.ExtractGAPMetadata()
|
|
|
|
l.w.WriteHeader(s)
|
|
l.status = s
|
|
}
|
|
|
|
func (l *responseLogger) Status() int {
|
|
return l.status
|
|
}
|
|
|
|
func (l *responseLogger) Size() int {
|
|
return l.size
|
|
}
|
|
|
|
func (l *responseLogger) Flush() {
|
|
f := l.w.(http.Flusher)
|
|
f.Flush()
|
|
}
|
|
|
|
// loggingHandler is the http.Handler implementation for LoggingHandlerTo and its friends
|
|
type loggingHandler struct {
|
|
handler http.Handler
|
|
}
|
|
|
|
// NewLoggingHandler returns a new loggingHandler that wraps a handler, and writer.
|
|
func NewLoggingHandler(h http.Handler) http.Handler {
|
|
return loggingHandler{
|
|
handler: h,
|
|
}
|
|
}
|
|
|
|
func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|
t := time.Now()
|
|
url := *req.URL
|
|
logger := &responseLogger{w: w, proxyHost: getProxyHost(req)}
|
|
h.handler.ServeHTTP(logger, req)
|
|
requestDuration := time.Since(t)
|
|
|
|
logRequest(logger.proxyHost, logger.authInfo, req, url, requestDuration, logger.Status())
|
|
}
|
|
|
|
// logRequest logs information about a request
|
|
func logRequest(proxyHost, username string, req *http.Request, url url.URL, requestDuration time.Duration, status int) {
|
|
uri := req.Host + url.RequestURI()
|
|
Info().
|
|
Int("http-status", status).
|
|
Str("request-method", req.Method).
|
|
Str("request-uri", uri).
|
|
Str("proxy-host", proxyHost).
|
|
// Str("user-agent", req.Header.Get("User-Agent")).
|
|
Str("remote-address", getRemoteAddr(req)).
|
|
Dur("duration", requestDuration).
|
|
Str("user", username).
|
|
Msg("request")
|
|
|
|
}
|
|
|
|
// getRemoteAddr returns the client IP address from a request. If present, the
|
|
// X-Forwarded-For header is assumed to be set by a load balancer, and its
|
|
// rightmost entry (the client IP that connected to the LB) is returned.
|
|
func getRemoteAddr(req *http.Request) string {
|
|
addr := req.RemoteAddr
|
|
forwardedHeader := req.Header.Get("X-Forwarded-For")
|
|
if forwardedHeader != "" {
|
|
forwardedList := strings.Split(forwardedHeader, ",")
|
|
forwardedAddr := strings.TrimSpace(forwardedList[len(forwardedList)-1])
|
|
if forwardedAddr != "" {
|
|
addr = forwardedAddr
|
|
}
|
|
}
|
|
return addr
|
|
}
|
|
|
|
// getProxyHost attempts to get the proxy host from the redirect_uri parameter
|
|
func getProxyHost(req *http.Request) string {
|
|
err := req.ParseForm()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
redirect := req.Form.Get("redirect_uri")
|
|
redirectURL, err := url.Parse(redirect)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return redirectURL.Host
|
|
}
|