@@ -40,9 +40,10 @@ var SignatureHeaders = []string{
40
40
41
41
// Errors
42
42
var (
43
- ErrLifetimeExpired = errors .New ("user lifetime expired" )
44
- ErrUserNotAuthorized = errors .New ("user not authorized" )
45
- ErrWrongIdentityProvider = errors .New ("user authenticated with wrong identity provider" )
43
+ ErrLifetimeExpired = errors .New ("user lifetime expired" )
44
+ ErrUserNotAuthorized = errors .New ("user not authorized" )
45
+ ErrWrongIdentityProvider = errors .New ("user authenticated with wrong identity provider" )
46
+ ErrUnauthorizedUpstreamRequested = errors .New ("user session authorized with different upstream" )
46
47
)
47
48
48
49
type ErrOAuthProxyMisconfigured struct {
@@ -591,6 +592,13 @@ func (p *OAuthProxy) OAuthCallback(rw http.ResponseWriter, req *http.Request) {
591
592
logger .WithRemoteAddress (remoteAddr ).WithUser (session .Email ).WithInGroups (session .Groups ).Info (
592
593
fmt .Sprintf ("oauth callback: user validated " ))
593
594
595
+ // We add the request host into the session to allow us to validate that each request has
596
+ // been authorized for the upstream it's requesting.
597
+ // e.g. if a request is authenticated while trying to reach 'foo' upstream, it should not
598
+ // automatically be seen as authorized with 'bar' upstream. Each upstream may set different
599
+ // validators, so the request should be reauthenticated.
600
+ session .AuthorizedUpstream = req .Host
601
+
594
602
// We store the session in a cookie and redirect the user back to the application
595
603
err = p .sessionStore .SaveSession (rw , req , session )
596
604
if err != nil {
@@ -655,6 +663,12 @@ func (p *OAuthProxy) Proxy(rw http.ResponseWriter, req *http.Request) {
655
663
// the user has a stale sesssion.
656
664
p .OAuthStart (rw , req , tags )
657
665
return
666
+ case ErrUnauthorizedUpstreamRequested :
667
+ // The users session has been authorised for use with a different upstream than the one
668
+ // that is being requested, so we trigger the start of the oauth flow.
669
+ // This exists primarily to implement some form of grace period while this additional session
670
+ // check is being introduced.
671
+ p .OAuthStart (rw , req , tags )
658
672
case sessions .ErrInvalidSession :
659
673
// The user session is invalid and we can't decode it.
660
674
// This can happen for a variety of reasons but the most common non-malicious
@@ -720,6 +734,15 @@ func (p *OAuthProxy) Authenticate(rw http.ResponseWriter, req *http.Request) (er
720
734
return ErrWrongIdentityProvider
721
735
}
722
736
737
+ // check that the user has been authorized against the requested upstream
738
+ // this is primarily to combat against a user authorizing with one upstream and attempting to use
739
+ // the session cookie for a different upstream.
740
+ if req .Host != session .AuthorizedUpstream {
741
+ logger .WithProxyHost (req .Host ).WithAuthorizedUpstream (session .AuthorizedUpstream ).WithUser (session .Email ).Warn (
742
+ "session authorized against different upstream; restarting authentication" )
743
+ return ErrUnauthorizedUpstreamRequested
744
+ }
745
+
723
746
// Lifetime period is the entire duration in which the session is valid.
724
747
// This should be set to something like 14 to 30 days.
725
748
if session .LifetimePeriodExpired () {
0 commit comments