implement oidc singl sign on cookie refresher

This commit is contained in:
Erikson Bahr 2024-01-31 16:59:52 -03:00
parent fe7fb31f05
commit ac2d04686f
No known key found for this signature in database
GPG Key ID: 18A31B1438D87934
6 changed files with 72 additions and 2 deletions

2
.gitignore vendored
View File

@ -41,3 +41,5 @@ _testmain.go
# vi Dockerfile.dev
# docker build -f Dockerfile.dev .
Dockerfile.dev
obj

View File

@ -393,6 +393,9 @@ func buildSessionChain(opts *options.Options, provider providers.Provider, sessi
ValidateSession: provider.ValidateSession,
}))
x := opts.Providers[0]
chain = chain.Append(middleware.NewCookieRefresh(&middleware.CookieRefreshOptions{IssuerURL: x.OIDCConfig.IssuerURL}))
return chain
}

View File

@ -31,8 +31,9 @@ type SessionState struct {
IntrospectClaims string `msgpack:"ic,omitempty"`
// Internal helpers, not serialized
Clock clock.Clock `msgpack:"-"`
Lock Lock `msgpack:"-"`
Clock clock.Clock `msgpack:"-"`
Lock Lock `msgpack:"-"`
SessionJustRefreshed bool `msgpack:"-"`
}
func (s *SessionState) ObtainLock(ctx context.Context, expiration time.Duration) error {

View File

@ -0,0 +1,60 @@
package middleware
import (
"fmt"
"net/http"
"github.com/justinas/alice"
middlewareapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/middleware"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
)
type CookieRefreshOptions struct {
IssuerURL string
}
func NewCookieRefresh(opts *CookieRefreshOptions) alice.Constructor {
cr := &cookieRefresh{
HttpClient: &http.Client{},
IssuerURL: opts.IssuerURL,
}
return cr.refreshCookie
}
type cookieRefresh struct {
HttpClient *http.Client
IssuerURL string
}
func (cr *cookieRefresh) refreshCookie(next http.Handler) http.Handler {
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
scope := middlewareapi.GetRequestScope(req)
if scope.Session == nil || !scope.Session.SessionJustRefreshed {
next.ServeHTTP(rw, req)
return
}
cookie, err := req.Cookie("hsdpamcookie")
if err != nil {
logger.Errorf("SSO Cookie Refresher - Could find 'hsdpamcookie' cookie in the request: %v", err)
return
}
resp := requests.New(fmt.Sprintf("%s/session/refresh", cr.IssuerURL)).
WithContext(req.Context()).
WithMethod("GET").
SetHeader("api-version", "1").
SetHeader("Cookie", fmt.Sprintf("hsdpamcookie=%s", cookie.Value)).
Do()
if resp.StatusCode() != http.StatusNoContent {
bodyString := string(resp.Body())
logger.Errorf("SSO Cookie Refresher - Could not refresh the 'hsdpamcookie' cookie due to status and content: %v - %v", resp.StatusCode(), bodyString)
return
} else {
logger.Print("SSO Cookie Refresher - Cookie 'hsdpamcookie' refreshed")
}
next.ServeHTTP(rw, req)
})
}

View File

@ -48,6 +48,9 @@ type StoredSessionLoaderOptions struct {
// If the sesssion is older than `RefreshPeriod` but the provider doesn't
// refresh it, we must re-validate using this validation.
ValidateSession func(context.Context, *sessionsapi.SessionState) bool
// Callback that is called when a session is refreshed
OnSessionRefreshed *func(context.Context, *http.Request, *sessionsapi.SessionState)
}
// NewStoredSessionLoader creates a new storedSessionLoader which loads

View File

@ -159,6 +159,7 @@ func (p *OIDCProvider) RefreshSession(ctx context.Context, s *sessions.SessionSt
if err != nil {
return false, fmt.Errorf("unable to redeem refresh token: %v", err)
}
s.SessionJustRefreshed = true
return true, nil
}