github.com/greenpau/go-authcrunch@v1.1.4/pkg/authn/handle_http_logout.go (about) 1 // Copyright 2022 Paul Greenberg greenpau@outlook.com 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package authn 16 17 import ( 18 "context" 19 "github.com/greenpau/go-authcrunch/pkg/redirects" 20 "github.com/greenpau/go-authcrunch/pkg/requests" 21 "github.com/greenpau/go-authcrunch/pkg/user" 22 addrutil "github.com/greenpau/go-authcrunch/pkg/util/addr" 23 "go.uber.org/zap" 24 "net/http" 25 "net/url" 26 "strings" 27 ) 28 29 func (p *Portal) deleteAuthCookies(w http.ResponseWriter, r *http.Request) { 30 for tokenName := range p.validator.GetAuthCookies() { 31 w.Header().Add("Set-Cookie", p.cookie.GetDeleteCookie(addrutil.GetSourceHost(r), tokenName)) 32 } 33 } 34 35 func (p *Portal) handleHTTPLogout(ctx context.Context, w http.ResponseWriter, r *http.Request, rr *requests.Request, parsedUser *user.User) error { 36 p.disableClientCache(w) 37 p.injectRedirectURL(ctx, w, r, rr) 38 h := addrutil.GetSourceHost(r) 39 for tokenName := range p.validator.GetAuthCookies() { 40 w.Header().Add("Set-Cookie", p.cookie.GetDeleteCookie(h, tokenName)) 41 } 42 w.Header().Add("Set-Cookie", p.cookie.GetDeleteCookie(h, p.cookie.Referer)) 43 w.Header().Add("Set-Cookie", p.cookie.GetDeleteCookie(h, p.cookie.SessionID)) 44 45 if parsedUser != nil && parsedUser.Claims != nil { 46 p.logger.Debug( 47 "user logout", 48 zap.String("session_id", rr.Upstream.SessionID), 49 zap.String("request_id", rr.ID), 50 zap.Any("user", parsedUser.Claims), 51 ) 52 if strings.Contains(parsedUser.Claims.Issuer, "/oauth2/") { 53 return p.handleHTTPRedirect(ctx, w, r, rr, extractRealmLogout(parsedUser.Claims.Issuer, "oauth2")) 54 } 55 // The user is authenticated. Find whether there is redirect_uri present in Query. 56 if redirects.HasRedirectURI(r.URL) && (len(p.config.TrustedLogoutRedirectURIConfigs) > 0) { 57 p.logger.Debug( 58 "user logout with redirect", 59 zap.String("session_id", rr.Upstream.SessionID), 60 zap.String("request_id", rr.ID), 61 zap.Any("user", parsedUser.Claims), 62 ) 63 redirectURI := redirects.GetRedirectURI(r.URL) 64 if redirectURI != nil { 65 if redirects.Match(redirectURI, p.config.TrustedLogoutRedirectURIConfigs) { 66 p.logger.Debug( 67 "found trusted logout redirect uri", 68 zap.String("session_id", rr.Upstream.SessionID), 69 zap.String("request_id", rr.ID), 70 zap.String("redirect_uri", redirects.GetRawRedirectURI(r.URL)), 71 ) 72 return p.handleHTTPRedirectExternal(ctx, w, r, rr, redirects.GetRawRedirectURI(r.URL)) 73 } 74 } 75 } 76 } else { 77 p.logger.Debug( 78 "user logout", 79 zap.String("session_id", rr.Upstream.SessionID), 80 zap.String("request_id", rr.ID), 81 ) 82 } 83 84 return p.handleHTTPRedirect(ctx, w, r, rr, "/login") 85 } 86 87 func (p *Portal) handleHTTPLogoutWithLocalRedirect(ctx context.Context, w http.ResponseWriter, r *http.Request, rr *requests.Request) error { 88 var refererExists bool 89 p.disableClientCache(w) 90 p.injectRedirectURL(ctx, w, r, rr) 91 h := addrutil.GetSourceHost(r) 92 for tokenName := range p.validator.GetAuthCookies() { 93 w.Header().Add("Set-Cookie", p.cookie.GetDeleteCookie(h, tokenName)) 94 } 95 if rr.Response.RedirectURL == "" { 96 w.Header().Add("Set-Cookie", p.cookie.GetDeleteCookie(h, p.cookie.Referer)) 97 } 98 w.Header().Add("Set-Cookie", p.cookie.GetDeleteCookie(h, p.cookie.SessionID)) 99 // The redirect_url query parameter exists. 100 if rr.Response.RedirectURL != "" { 101 return p.handleHTTPRedirect(ctx, w, r, rr, "/login?redirect_url="+rr.Response.RedirectURL) 102 } 103 // Find whether the redirect cookie exists. If so, do not inject redirect URL. 104 if cookie, err := r.Cookie(p.cookie.Referer); err == nil { 105 v, err := url.Parse(cookie.Value) 106 if err == nil && v.String() != "" { 107 refererExists = true 108 } 109 } 110 if !refererExists { 111 w.Header().Add("Set-Cookie", p.cookie.GetDeleteCookie(h, p.cookie.Referer)) 112 return p.handleHTTPRedirect(ctx, w, r, rr, "/login?redirect_url="+r.RequestURI) 113 } 114 return p.handleHTTPRedirect(ctx, w, r, rr, "/login") 115 } 116 117 func extractRealmLogout(s, sp string) string { 118 var ready bool 119 for _, k := range strings.Split(s, "/") { 120 if k == sp { 121 ready = true 122 continue 123 } 124 if ready { 125 return "/" + strings.Join([]string{sp, k, "logout"}, "/") 126 } 127 } 128 return "/logout" 129 }