github.com/argoproj/argo-cd@v1.8.7/server/logout/logout.go (about) 1 package logout 2 3 import ( 4 "fmt" 5 "net/http" 6 "regexp" 7 "strings" 8 9 "github.com/dgrijalva/jwt-go/v4" 10 11 "github.com/argoproj/argo-cd/common" 12 "github.com/argoproj/argo-cd/pkg/client/clientset/versioned" 13 "github.com/argoproj/argo-cd/util/session" 14 "github.com/argoproj/argo-cd/util/settings" 15 16 jwtutil "github.com/argoproj/argo-cd/util/jwt" 17 ) 18 19 //NewHandler creates handler serving to do api/logout endpoint 20 func NewHandler(appClientset versioned.Interface, settingsMrg *settings.SettingsManager, sessionMgr *session.SessionManager, rootPath, namespace string) *Handler { 21 return &Handler{ 22 appClientset: appClientset, 23 namespace: namespace, 24 settingsMgr: settingsMrg, 25 rootPath: rootPath, 26 verifyToken: sessionMgr.VerifyToken, 27 } 28 } 29 30 type Handler struct { 31 namespace string 32 appClientset versioned.Interface 33 settingsMgr *settings.SettingsManager 34 rootPath string 35 verifyToken func(tokenString string) (jwt.Claims, error) 36 } 37 38 var ( 39 tokenPattern = regexp.MustCompile(`{{token}}`) 40 logoutRedirectURLPattern = regexp.MustCompile(`{{logoutRedirectURL}}`) 41 ) 42 43 func constructLogoutURL(logoutURL, token, logoutRedirectURL string) string { 44 constructedLogoutURL := tokenPattern.ReplaceAllString(logoutURL, token) 45 return logoutRedirectURLPattern.ReplaceAllString(constructedLogoutURL, logoutRedirectURL) 46 } 47 48 // ServeHTTP is the logout handler for ArgoCD and constructs OIDC logout URL and redirects to it for OIDC issued sessions, 49 // and redirects user to '/login' for argocd issued sessions 50 func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 51 var tokenString string 52 var oidcConfig *settings.OIDCConfig 53 54 argoCDSettings, err := h.settingsMgr.GetSettings() 55 if err != nil { 56 w.WriteHeader(http.StatusInternalServerError) 57 http.Error(w, "Failed to retrieve argoCD settings: "+fmt.Sprintf("%s", err), http.StatusInternalServerError) 58 return 59 } 60 61 logoutRedirectURL := strings.TrimRight(strings.TrimLeft(argoCDSettings.URL, "/"), "/") + strings.TrimRight(strings.TrimLeft(h.rootPath, "/"), "/") 62 63 argocdCookie, err := r.Cookie(common.AuthCookieName) 64 if err != nil { 65 w.WriteHeader(http.StatusBadRequest) 66 http.Error(w, "Failed to retrieve ArgoCD auth token: "+fmt.Sprintf("%s", err), http.StatusBadRequest) 67 return 68 } 69 70 tokenString = argocdCookie.Value 71 72 argocdCookie.Value = "" 73 argocdCookie.Path = fmt.Sprintf("/%s", strings.TrimRight(strings.TrimLeft(h.rootPath, "/"), "/")) 74 w.Header().Set("Set-Cookie", argocdCookie.String()) 75 76 claims, err := h.verifyToken(tokenString) 77 if err != nil { 78 http.Redirect(w, r, logoutRedirectURL, http.StatusSeeOther) 79 return 80 } 81 82 mapClaims, err := jwtutil.MapClaims(claims) 83 if err != nil { 84 http.Redirect(w, r, logoutRedirectURL, http.StatusSeeOther) 85 return 86 } 87 88 issuer := jwtutil.StringField(mapClaims, "iss") 89 90 if argoCDSettings.OIDCConfig() == nil || argoCDSettings.OIDCConfig().LogoutURL == "" || issuer == session.SessionManagerClaimsIssuer { 91 http.Redirect(w, r, logoutRedirectURL, http.StatusSeeOther) 92 } else { 93 oidcConfig = argoCDSettings.OIDCConfig() 94 logoutURL := constructLogoutURL(oidcConfig.LogoutURL, tokenString, logoutRedirectURL) 95 http.Redirect(w, r, logoutURL, http.StatusSeeOther) 96 } 97 }