mirror of
https://github.com/goauthentik/authentik
synced 2026-04-27 09:57:31 +02:00
* outpost/proxyv2: handle PostgreSQL passwords with spaces and special characters
And modify / add some more tests and a bit of refactoring
* Potential fix for code scanning alert no. 268: Disabled TLS certificate check
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Signed-off-by: Dominic R <dominic@sdko.org>
* Revert "Potential fix for code scanning alert no. 268: Disabled TLS certificate check"
This reverts commit ead227a272.
* wip
* fix incorrect status code in error response
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
---------
Signed-off-by: Dominic R <dominic@sdko.org>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
121 lines
3.1 KiB
Go
121 lines
3.1 KiB
Go
package application
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/mitchellh/mapstructure"
|
|
"goauthentik.io/internal/outpost/proxyv2/constants"
|
|
"goauthentik.io/internal/outpost/proxyv2/types"
|
|
)
|
|
|
|
// checkAuth Get claims which are currently in session
|
|
// Returns an error if the session can't be loaded or the claims can't be parsed/type-cast
|
|
func (a *Application) checkAuth(rw http.ResponseWriter, r *http.Request) (*types.Claims, error) {
|
|
c := a.getClaimsFromSession(rw, r)
|
|
if c != nil {
|
|
return c, nil
|
|
}
|
|
|
|
if rw == nil {
|
|
return nil, fmt.Errorf("no response writer")
|
|
}
|
|
// Check TTL cache
|
|
c = a.getClaimsFromCache(r)
|
|
if c != nil {
|
|
return c, nil
|
|
}
|
|
// Check bearer token if set
|
|
bearer := a.checkAuthHeaderBearer(r)
|
|
if bearer != "" {
|
|
a.log.Trace("checking bearer token")
|
|
tc := a.attemptBearerAuth(bearer)
|
|
if tc != nil {
|
|
return a.saveAndCacheClaims(rw, r, tc.Claims)
|
|
}
|
|
a.log.Trace("no/invalid bearer token")
|
|
}
|
|
// Check basic auth if set
|
|
username, password, basicSet := r.BasicAuth()
|
|
if basicSet {
|
|
a.log.Trace("checking basic auth")
|
|
tc := a.attemptBasicAuth(username, password)
|
|
if tc != nil {
|
|
return a.saveAndCacheClaims(rw, r, *tc)
|
|
}
|
|
a.log.Trace("no/invalid basic auth")
|
|
}
|
|
|
|
return nil, fmt.Errorf("failed to get claims from session")
|
|
}
|
|
|
|
func (a *Application) getClaimsFromSession(rw http.ResponseWriter, r *http.Request) *types.Claims {
|
|
s, err := a.sessions.Get(r, a.SessionName())
|
|
if err != nil {
|
|
// err == user has no session/session is not valid
|
|
// Delete the stale session cookie if it exists
|
|
if rw != nil {
|
|
s.Options.MaxAge = -1
|
|
if saveErr := s.Save(r, rw); saveErr != nil {
|
|
a.log.WithError(saveErr).Warning("failed to delete stale session cookie")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
claims, ok := s.Values[constants.SessionClaims]
|
|
if claims == nil || !ok {
|
|
// no claims saved, reject
|
|
return nil
|
|
}
|
|
|
|
// Claims are always stored as types.Claims but may be deserialized differently:
|
|
// - Filesystem store (gob): preserves struct type as types.Claims
|
|
// - PostgreSQL store (JSON): deserializes as map[string]any
|
|
|
|
// Handle struct type (filesystem store)
|
|
if c, ok := claims.(types.Claims); ok {
|
|
return &c
|
|
}
|
|
|
|
// Handle map type (PostgreSQL store)
|
|
if claimsMap, ok := claims.(map[string]any); ok {
|
|
var c types.Claims
|
|
if err := mapstructure.Decode(claimsMap, &c); err != nil {
|
|
return nil
|
|
}
|
|
return &c
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *Application) getClaimsFromCache(r *http.Request) *types.Claims {
|
|
key := r.Header.Get(constants.HeaderAuthorization)
|
|
item := a.authHeaderCache.Get(key)
|
|
if item != nil && !item.IsExpired() {
|
|
v := item.Value()
|
|
return &v
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (a *Application) saveAndCacheClaims(rw http.ResponseWriter, r *http.Request, claims types.Claims) (*types.Claims, error) {
|
|
s, _ := a.sessions.Get(r, a.SessionName())
|
|
|
|
s.Values[constants.SessionClaims] = claims
|
|
err := s.Save(r, rw)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
key := r.Header.Get(constants.HeaderAuthorization)
|
|
item := a.authHeaderCache.Get(key)
|
|
// Don't set when the key is already found
|
|
if item == nil {
|
|
a.authHeaderCache.Set(key, claims, time.Second*60)
|
|
}
|
|
r.Header.Del(constants.HeaderAuthorization)
|
|
return &claims, nil
|
|
}
|