Commit b1c0a012 authored by ale's avatar ale

Simplify login handler by isolating session init logic

And standardize on a single structure for the gorilla session
map, using the 'data' key for our gob-encoded objects.
parent 10365b59
...@@ -200,7 +200,7 @@ func (h *Server) loginCallback(w http.ResponseWriter, req *http.Request, usernam ...@@ -200,7 +200,7 @@ func (h *Server) loginCallback(w http.ResponseWriter, req *http.Request, usernam
// Create cookie-based session for the authenticated user. // Create cookie-based session for the authenticated user.
session := newAuthSession(h.authSessionLifetime, username, userinfo) session := newAuthSession(h.authSessionLifetime, username, userinfo)
httpSession, _ := h.authSessionStore.Get(req, authSessionKey) // nolint httpSession, _ := h.authSessionStore.Get(req, authSessionKey) // nolint
httpSession.Values["auth"] = session httpSession.Values["data"] = session
return httpSession.Save(req, w) return httpSession.Save(req, w)
} }
...@@ -211,12 +211,13 @@ func (h *Server) withAuth(f func(http.ResponseWriter, *http.Request, *authSessio ...@@ -211,12 +211,13 @@ func (h *Server) withAuth(f func(http.ResponseWriter, *http.Request, *authSessio
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
session, ok := httpSession.Values["auth"].(*authSession) session, ok := httpSession.Values["data"].(*authSession)
if ok && session != nil && session.Valid() { if ok && session.Valid() {
f(w, req, session) f(w, req, session)
return return
} }
httpSession.Options.MaxAge = -1 httpSession.Options.MaxAge = -1
delete(httpSession.Values, "data")
if err := httpSession.Save(req, w); err != nil { if err := httpSession.Save(req, w); err != nil {
log.Printf("error saving session: %v", err) log.Printf("error saving session: %v", err)
} }
...@@ -224,9 +225,9 @@ func (h *Server) withAuth(f func(http.ResponseWriter, *http.Request, *authSessio ...@@ -224,9 +225,9 @@ func (h *Server) withAuth(f func(http.ResponseWriter, *http.Request, *authSessio
}) })
} }
// Homepage handler. Authorizes an authenticated user to a service by // Token signing handler. Authorizes an authenticated user to a service by
// signing a token with the user's identity. The client is redirected // signing a token with the user's identity. The client is redirected back to
// back to the service, with the signed token. // the original service, with the signed token.
func (h *Server) handleHomepage(w http.ResponseWriter, req *http.Request, session *authSession) { func (h *Server) handleHomepage(w http.ResponseWriter, req *http.Request, session *authSession) {
// Extract the authorization request parameters from the HTTP // Extract the authorization request parameters from the HTTP
// request. // request.
......
...@@ -105,21 +105,43 @@ func newLoginHandler(okHandler loginCallbackFunc, devMgr *device.Manager, authCl ...@@ -105,21 +105,43 @@ func newLoginHandler(okHandler loginCallbackFunc, devMgr *device.Manager, authCl
} }
} }
func (l *loginHandler) fetchOrInitSession(req *http.Request) (*sessions.Session, *loginSession, error) {
// Either fetch the current session or create a new blank one.
httpSession, err := l.loginSessionStore.Get(req, loginSessionKey)
if err != nil {
return nil, nil, err
}
session, ok := httpSession.Values["data"].(*loginSession)
if !ok || !session.Valid() {
session = newLoginSession()
// Initialize session. The only parameter is 'r', the target
// redirect location. Enforce relative redirect URL (no host
// should be specified).
session.Redir = req.FormValue("r")
if session.Redir == "" {
return nil, nil, errors.New("empty login redirect target")
}
if !strings.HasPrefix(session.Redir, "/") || strings.HasPrefix(session.Redir, "//") {
return nil, nil, errors.New("bad login redirect target")
}
httpSession.Values["data"] = session
}
return httpSession, session, nil
}
// The login session controls the flow of the client - it's just a way // The login session controls the flow of the client - it's just a way
// to ensure that every step is authorized as part of the login // to ensure that every step is authorized as part of the login
// sequence. // sequence.
func (l *loginHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { func (l *loginHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Either fetch the current session or create a new blank one. httpSession, session, err := l.fetchOrInitSession(req)
httpSession, err := l.loginSessionStore.Get(req, loginSessionKey)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) log.Printf("login session init error: %v", err)
http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
session, ok := httpSession.Values["ls"].(*loginSession)
if !ok || session == nil || !session.Valid() {
session = newLoginSession()
httpSession.Values["ls"] = session
}
// Dispatch the current state to its handler. Handlers will // Dispatch the current state to its handler. Handlers will
// handle the current request and either 1) validate the // handle the current request and either 1) validate the
...@@ -142,6 +164,7 @@ func (l *loginHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { ...@@ -142,6 +164,7 @@ func (l *loginHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// the login callback, before redirecting to the // the login callback, before redirecting to the
// original URL. // original URL.
httpSession.Options.MaxAge = -1 httpSession.Options.MaxAge = -1
delete(httpSession.Values, "data")
if err := httpSession.Save(req, w); err != nil { if err := httpSession.Save(req, w); err != nil {
log.Printf("login error saving session: %v", err) log.Printf("login error saving session: %v", err)
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
...@@ -188,14 +211,6 @@ func (l *loginHandler) handlePassword(w http.ResponseWriter, req *http.Request, ...@@ -188,14 +211,6 @@ func (l *loginHandler) handlePassword(w http.ResponseWriter, req *http.Request,
username := req.FormValue("username") username := req.FormValue("username")
password := req.FormValue("password") password := req.FormValue("password")
if req.Method == "GET" && session.Redir == "" {
session.Redir = req.FormValue("r")
// Enforce relative redirect URL (no host specified).
if session.Redir == "" || !strings.HasPrefix(session.Redir, "/") {
return loginStateNone, nil, errors.New("bad request")
}
}
// If the request is a POST, attempt login with username/password. // If the request is a POST, attempt login with username/password.
env := map[string]interface{}{ env := map[string]interface{}{
"Error": false, "Error": false,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment