webui: add after-login redirection support

This commit is contained in:
Erin Shepherd 2023-02-08 12:37:23 +00:00
parent 4191566281
commit 933ed6d613
3 changed files with 52 additions and 2 deletions

View file

@ -120,6 +120,7 @@
</label>
</div>
<button class="w-100 btn btn-lg btn-primary" type="submit">Sign in</button>
{{if .Next}}<input type="hidden" name="next" value="{{.Next}}">{{end}}
{{.CSRFField}}
<!--<p class="mt-5 mb-3 text-muted">&copy; 20172022</p>-->
</form>

View file

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net/http"
"net/url"
"time"
"github.com/google/uuid"
@ -29,7 +30,7 @@ func getUserToken(ctx context.Context) openid.Token {
func requireLogin(w http.ResponseWriter, r *http.Request) bool {
tok := getUserToken(r.Context())
if tok == nil {
http.Redirect(w, r, "/login", http.StatusFound)
http.Redirect(w, r, "/login?next="+url.QueryEscape(r.URL.String()), http.StatusFound)
return false
}
return true

View file

@ -5,6 +5,8 @@ import (
"errors"
"html/template"
"net/http"
"net/url"
"strings"
"github.com/gorilla/csrf"
"go.e43.eu/authentricity/internal/models"
@ -36,12 +38,19 @@ func (fr loginFailureReason) Error() string {
}
func (s *Service) loginGet(w http.ResponseWriter, r *http.Request) {
L := zap.L()
tok := getUserToken(r.Context())
if tok != nil {
http.Redirect(w, r, "/", http.StatusFound)
return
}
if err := r.ParseForm(); err != nil {
L.Error("Error parsing form data", zap.Error(err))
s.renderError(w)
return
}
s.showLoginPage(w, r, "")
}
@ -83,7 +92,44 @@ func (s *Service) loginPost(w http.ResponseWriter, r *http.Request) {
cookie := s.buildTokenCookie(serialized, 86400)
http.SetCookie(w, &cookie)
http.Redirect(w, r, "/entity/"+user.UUID.String(), http.StatusFound)
nextURL, ok := s.getLoginNextURL(r)
if !ok {
nextURL = "/entity/" + user.UUID.String()
}
http.Redirect(w, r, nextURL, http.StatusFound)
}
func (s *Service) getLoginNextURL(r *http.Request) (string, bool) {
L := zap.L()
next := r.PostForm.Get("next")
if next == "" {
L.Debug("Ignoring next as empty or unset")
return "", false
}
nextURL, err := url.ParseRequestURI(next)
switch {
case err != nil:
L.Debug("Ignoring next as failed to parse",
zap.String("next", next), zap.Error(err))
return "", false
case nextURL.Scheme != "https":
L.Debug("Ignoring next as scheme not HTTPS",
zap.String("next", next))
case nextURL.Host != "" &&
nextURL.Host != s.cookieDomain &&
!strings.HasSuffix(nextURL.Host, "."+s.cookieDomain):
L.Debug("Ignoring next as not within cookie domain",
zap.String("next", next))
return "", false
}
// We re-stringify the URL as this reduces request smuggling type risks
return nextURL.String(), true
}
func (s *Service) tryLogin(ctx context.Context, username, password string) (*models.UserRecord, error) {
@ -134,10 +180,12 @@ func (s *Service) showLoginPage(w http.ResponseWriter, r *http.Request, message
ShowError bool
ErrorMessage string
CSRFField template.HTML
Next string
}{
ShowError: message != "",
ErrorMessage: message,
CSRFField: csrf.TemplateField(r),
Next: r.Form.Get("next"),
}
err := s.templates.ExecuteTemplate(w, "login.tmpl", params)