From 42a7cde1ac9e7c8a04f4f21877bb2c89a5428d77 Mon Sep 17 00:00:00 2001 From: ale <ale@incal.net> Date: Sun, 18 Feb 2018 13:13:57 +0000 Subject: [PATCH] Test Javascript-based logout Using CORS-enabled requests in the background. --- httpsso/handler.go | 2 + server/bindata.go | 123 ++++++++++++++++++++++++++++++----- server/http.go | 1 + server/static/css/signin.css | 13 ++++ server/static/js/logout.js | 37 +++++++++++ server/templates/logout.html | 24 ++++++- server/templates/page.html | 5 +- 7 files changed, 185 insertions(+), 20 deletions(-) create mode 100644 server/static/js/logout.js diff --git a/httpsso/handler.go b/httpsso/handler.go index 7d42db8..26bb143 100644 --- a/httpsso/handler.go +++ b/httpsso/handler.go @@ -130,6 +130,8 @@ func (s *SSOWrapper) handleLogout(w http.ResponseWriter, req *http.Request, sess } w.Header().Set("Content-Type", "text/plain") + w.Header().Set("Access-Control-Allow-Origin", strings.TrimRight(s.serverURL, "/")) + w.Header().Set("Access-Control-Allow-Credentials", "true") io.WriteString(w, "OK") } diff --git a/server/bindata.go b/server/bindata.go index 0dbb789..4c4d717 100644 --- a/server/bindata.go +++ b/server/bindata.go @@ -4,6 +4,7 @@ // static/css/signin.css // static/js/bootstrap-4.0.0-beta.min.js // static/js/jquery-3.2.1.min.js +// static/js/logout.js // static/js/popper-1.11.0.min.js // static/js/u2f-api.js // static/js/u2f.js @@ -73,7 +74,7 @@ func staticCssBootstrapMinCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "static/css/bootstrap.min.css", size: 124962, mode: os.FileMode(420), modTime: time.Unix(1509120975, 0)} + info := bindataFileInfo{name: "static/css/bootstrap.min.css", size: 124962, mode: os.FileMode(436), modTime: time.Unix(1510996183, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -120,6 +121,19 @@ var _staticCssSigninCss = []byte(`body { font-weight: bold; color: red; } + +/* logout page */ +.logout-status { + font-weight: bold; +} +.logout-status-ok { + background-color: green; + color: white; +} +.logout-status-error { + background-color: red; + color: white; +} `) func staticCssSigninCssBytes() ([]byte, error) { @@ -132,7 +146,7 @@ func staticCssSigninCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "static/css/signin.css", size: 802, mode: os.FileMode(420), modTime: time.Unix(1511166680, 0)} + info := bindataFileInfo{name: "static/css/signin.css", size: 992, mode: os.FileMode(436), modTime: time.Unix(1518958548, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -154,7 +168,7 @@ func staticJsBootstrap400BetaMinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "static/js/bootstrap-4.0.0-beta.min.js", size: 51143, mode: os.FileMode(420), modTime: time.Unix(1509120962, 0)} + info := bindataFileInfo{name: "static/js/bootstrap-4.0.0-beta.min.js", size: 51143, mode: os.FileMode(436), modTime: time.Unix(1510996183, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -175,7 +189,61 @@ func staticJsJquery321MinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "static/js/jquery-3.2.1.min.js", size: 86659, mode: os.FileMode(420), modTime: time.Unix(1509120962, 0)} + info := bindataFileInfo{name: "static/js/jquery-3.2.1.min.js", size: 86659, mode: os.FileMode(436), modTime: time.Unix(1510996183, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _staticJsLogoutJs = []byte(`var idlogout = {}; + +idlogout.get_services = function() { + return JSON.parse($('#services').attr('data_values')); +}; + +idlogout.logout_service = function(service) { + var logout_url = service.url + 'sso_logout'; + console.log('logging out of ' + service.name); + $.ajax({ + type: 'GET', + url: logout_url, + contentType: 'text/plain', + xhrFields: { + withCredentials: true + }, + success: function() { + $('#status_'+service.idx).class('logout-status-ok').text('OK'); + console.log('successful logout for ' + service.name); + }, + error: function() { + $('#status_'+service.idx).class('logout-status-error').text('ERROR'); + console.log('error logging out of ' + service.name); + } + }); +}; + +idlogout.logout = function() { + var services = idlogout.get_services(); + $.each(services, func(index, arg) { + idlogout.logout_service(arg); + }); +}; + +$(function() { + idlogout.logout(); +}); +`) + +func staticJsLogoutJsBytes() ([]byte, error) { + return _staticJsLogoutJs, nil +} + +func staticJsLogoutJs() (*asset, error) { + bytes, err := staticJsLogoutJsBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "static/js/logout.js", size: 1013, mode: os.FileMode(436), modTime: time.Unix(1518958930, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -197,7 +265,7 @@ func staticJsPopper1110MinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "static/js/popper-1.11.0.min.js", size: 19033, mode: os.FileMode(420), modTime: time.Unix(1509120962, 0)} + info := bindataFileInfo{name: "static/js/popper-1.11.0.min.js", size: 19033, mode: os.FileMode(436), modTime: time.Unix(1510996183, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -962,7 +1030,7 @@ func staticJsU2fApiJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "static/js/u2f-api.js", size: 20880, mode: os.FileMode(420), modTime: time.Unix(1509120962, 0)} + info := bindataFileInfo{name: "static/js/u2f-api.js", size: 20880, mode: os.FileMode(436), modTime: time.Unix(1510996183, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1031,7 +1099,7 @@ func staticJsU2fJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "static/js/u2f.js", size: 1281, mode: os.FileMode(420), modTime: time.Unix(1509260310, 0)} + info := bindataFileInfo{name: "static/js/u2f.js", size: 1281, mode: os.FileMode(436), modTime: time.Unix(1510996183, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1069,7 +1137,7 @@ func templatesLogin_otpHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/login_otp.html", size: 529, mode: os.FileMode(420), modTime: time.Unix(1509218738, 0)} + info := bindataFileInfo{name: "templates/login_otp.html", size: 529, mode: os.FileMode(436), modTime: time.Unix(1510996183, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1129,7 +1197,7 @@ func templatesLogin_passwordHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/login_password.html", size: 1074, mode: os.FileMode(420), modTime: time.Unix(1509218731, 0)} + info := bindataFileInfo{name: "templates/login_password.html", size: 1074, mode: os.FileMode(436), modTime: time.Unix(1510996183, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1169,7 +1237,7 @@ func templatesLogin_u2fHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/login_u2f.html", size: 498, mode: os.FileMode(420), modTime: time.Unix(1509260387, 0)} + info := bindataFileInfo{name: "templates/login_u2f.html", size: 498, mode: os.FileMode(436), modTime: time.Unix(1510996183, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1180,18 +1248,36 @@ var _templatesLogoutHtml = []byte(`{{template "header" .}} <div class="form-signin"> <h1 class="form-signin-heading>">Sign Out</h1> + <noscript> + <p> + It seems that Javascript is disabled. + </p> + + <p> + We can try to log you out using third-party cookies, but if + you have a privacy extension that disables that, you will + need to <b>QUIT YOUR BROWSER COMPLETELY</b> to sign yourself + out of the current session! + </p> + </noscript> + <p> Signing you out from all services... </p> <ul> - {{range .Services}} + {{range $i, $svc := .Services}} <li> - <img src="{{.URL}}" class="logout-img"> {{.Name}} + <noscript> + <img src="{{$svc.URL}}"> + </noscript> + <div class="logout-status" id="status_{{$i}}">...</div> {{$svc.Name}} </li> {{end}} </ul> - + + <div id="#services" data_values="[{{range $i, $svc := .Services}}{{if gt $i 0}},{{end}}{%22idx%22:{{$i}},%22name%22:%22{{$svc.Name}}%22,%22url%22:%22{{$svc.URL}}%22}{{end}}]"></div> + </div> {{else}} <form class="form-signin" action="/logout" method="post"> @@ -1227,7 +1313,7 @@ func templatesLogoutHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/logout.html", size: 820, mode: os.FileMode(420), modTime: time.Unix(1511166680, 0)} + info := bindataFileInfo{name: "templates/logout.html", size: 1503, mode: os.FileMode(436), modTime: time.Unix(1518959579, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1239,7 +1325,7 @@ var _templatesPageHtml = []byte(`{{define "header"}}<!DOCTYPE html> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> {{if .U2FSignRequest}}<meta name="u2f_request" value="{{json .U2FSignRequest}}">{{end}} <link rel="stylesheet" href="/static/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M"> - <link rel="stylesheet" href="/static/css/signin.css" integrity="sha384-cd2kbbMX+cYhUlp/Xc7Mu9yBphBGNEvZpeIltWsgUMlkt1kNO3hytQQeTglDcMF/"> + <link rel="stylesheet" href="/static/css/signin.css" integrity="sha384-Qj/laxKROb+o3N4XlayJF2LOuybTRxjeOP+DEeYYEwQUiVtNjaMdgnPbN5ffI/Ub"> <title>Sign In</title> </head> @@ -1256,6 +1342,9 @@ var _templatesPageHtml = []byte(`{{define "header"}}<!DOCTYPE html> {{if .U2FSignRequest}} <script type="text/javascript" src="/static/js/u2f-api.js" integrity="sha384-9ChevE6pp8ArGK03HgolnFjZbF3webZQtYkwcabzbcI28Lx1/2x2j2fbaAWD4cgR"></script> <script type="text/javascript" src="/static/js/u2f.js" integrity="sha384-vd6lytRvVm189G5gr34wlOvN672vVBceTZqV+lTSeec0DBLc0GlWLyKDHc6mrIZS"></script> +{{end}} +{{if .IncludeLogoutScripts}} + <script type="text/javascript" src="/static/js/logout.js" integrity="sha384-kRP1MtnGgO2BwMmtNODaqnREJyxzsGanV92uEKCf54ilYWxtHSNNYuw3YiCQ+ElP"></script> {{end}} </body> </html> @@ -1272,7 +1361,7 @@ func templatesPageHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "templates/page.html", size: 1493, mode: os.FileMode(420), modTime: time.Unix(1511337830, 0)} + info := bindataFileInfo{name: "templates/page.html", size: 1686, mode: os.FileMode(436), modTime: time.Unix(1518959588, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1333,6 +1422,7 @@ var _bindata = map[string]func() (*asset, error){ "static/css/signin.css": staticCssSigninCss, "static/js/bootstrap-4.0.0-beta.min.js": staticJsBootstrap400BetaMinJs, "static/js/jquery-3.2.1.min.js": staticJsJquery321MinJs, + "static/js/logout.js": staticJsLogoutJs, "static/js/popper-1.11.0.min.js": staticJsPopper1110MinJs, "static/js/u2f-api.js": staticJsU2fApiJs, "static/js/u2f.js": staticJsU2fJs, @@ -1391,6 +1481,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ "js": &bintree{nil, map[string]*bintree{ "bootstrap-4.0.0-beta.min.js": &bintree{staticJsBootstrap400BetaMinJs, map[string]*bintree{}}, "jquery-3.2.1.min.js": &bintree{staticJsJquery321MinJs, map[string]*bintree{}}, + "logout.js": &bintree{staticJsLogoutJs, map[string]*bintree{}}, "popper-1.11.0.min.js": &bintree{staticJsPopper1110MinJs, map[string]*bintree{}}, "u2f-api.js": &bintree{staticJsU2fApiJs, map[string]*bintree{}}, "u2f.js": &bintree{staticJsU2fJs, map[string]*bintree{}}, diff --git a/server/http.go b/server/http.go index cd4936c..efd91d6 100644 --- a/server/http.go +++ b/server/http.go @@ -254,6 +254,7 @@ func (h *Server) handleLogout(w http.ResponseWriter, req *http.Request, session } if req.Method == "POST" { data["IsPOST"] = true + data["IncludeLogoutScripts"] = true // Clear the local session. httpSession, _ := h.authSessionStore.Get(req, authSessionKey) diff --git a/server/static/css/signin.css b/server/static/css/signin.css index 8fc5332..f949ff7 100644 --- a/server/static/css/signin.css +++ b/server/static/css/signin.css @@ -40,3 +40,16 @@ body { font-weight: bold; color: red; } + +/* logout page */ +.logout-status { + font-weight: bold; +} +.logout-status-ok { + background-color: green; + color: white; +} +.logout-status-error { + background-color: red; + color: white; +} diff --git a/server/static/js/logout.js b/server/static/js/logout.js new file mode 100644 index 0000000..ca1bbef --- /dev/null +++ b/server/static/js/logout.js @@ -0,0 +1,37 @@ +var idlogout = {}; + +idlogout.get_services = function() { + return JSON.parse($('#services').attr('data_values')); +}; + +idlogout.logout_service = function(service) { + var logout_url = service.url + 'sso_logout'; + console.log('logging out of ' + service.name); + $.ajax({ + type: 'GET', + url: logout_url, + contentType: 'text/plain', + xhrFields: { + withCredentials: true + }, + success: function() { + $('#status_'+service.idx).class('logout-status-ok').text('OK'); + console.log('successful logout for ' + service.name); + }, + error: function() { + $('#status_'+service.idx).class('logout-status-error').text('ERROR'); + console.log('error logging out of ' + service.name); + } + }); +}; + +idlogout.logout = function() { + var services = idlogout.get_services(); + $.each(services, func(index, arg) { + idlogout.logout_service(arg); + }); +}; + +$(function() { + idlogout.logout(); +}); diff --git a/server/templates/logout.html b/server/templates/logout.html index 7a08280..a36c602 100644 --- a/server/templates/logout.html +++ b/server/templates/logout.html @@ -4,18 +4,36 @@ <div class="form-signin"> <h1 class="form-signin-heading>">Sign Out</h1> + <noscript> + <p> + It seems that Javascript is disabled. + </p> + + <p> + We can try to log you out using third-party cookies, but if + you have a privacy extension that disables that, you will + need to <b>QUIT YOUR BROWSER COMPLETELY</b> to sign yourself + out of the current session! + </p> + </noscript> + <p> Signing you out from all services... </p> <ul> - {{range .Services}} + {{range $i, $svc := .Services}} <li> - <img src="{{.URL}}" class="logout-img"> {{.Name}} + <noscript> + <img src="{{$svc.URL}}"> + </noscript> + <div class="logout-status" id="status_{{$i}}">...</div> {{$svc.Name}} </li> {{end}} </ul> - + + <div id="#services" data_values="[{{range $i, $svc := .Services}}{{if gt $i 0}},{{end}}{%22idx%22:{{$i}},%22name%22:%22{{$svc.Name}}%22,%22url%22:%22{{$svc.URL}}%22}{{end}}]"></div> + </div> {{else}} <form class="form-signin" action="/logout" method="post"> diff --git a/server/templates/page.html b/server/templates/page.html index e16b0f6..336b45d 100644 --- a/server/templates/page.html +++ b/server/templates/page.html @@ -5,7 +5,7 @@ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> {{if .U2FSignRequest}}<meta name="u2f_request" value="{{json .U2FSignRequest}}">{{end}} <link rel="stylesheet" href="/static/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M"> - <link rel="stylesheet" href="/static/css/signin.css" integrity="sha384-cd2kbbMX+cYhUlp/Xc7Mu9yBphBGNEvZpeIltWsgUMlkt1kNO3hytQQeTglDcMF/"> + <link rel="stylesheet" href="/static/css/signin.css" integrity="sha384-Qj/laxKROb+o3N4XlayJF2LOuybTRxjeOP+DEeYYEwQUiVtNjaMdgnPbN5ffI/Ub"> <title>Sign In</title> </head> @@ -22,6 +22,9 @@ {{if .U2FSignRequest}} <script type="text/javascript" src="/static/js/u2f-api.js" integrity="sha384-9ChevE6pp8ArGK03HgolnFjZbF3webZQtYkwcabzbcI28Lx1/2x2j2fbaAWD4cgR"></script> <script type="text/javascript" src="/static/js/u2f.js" integrity="sha384-vd6lytRvVm189G5gr34wlOvN672vVBceTZqV+lTSeec0DBLc0GlWLyKDHc6mrIZS"></script> +{{end}} +{{if .IncludeLogoutScripts}} + <script type="text/javascript" src="/static/js/logout.js" integrity="sha384-kRP1MtnGgO2BwMmtNODaqnREJyxzsGanV92uEKCf54ilYWxtHSNNYuw3YiCQ+ElP"></script> {{end}} </body> </html> -- GitLab