about summary refs log tree commit diff
path: root/nix/templates/goapp/frontend/src/handlers.go
diff options
context:
space:
mode:
Diffstat (limited to 'nix/templates/goapp/frontend/src/handlers.go')
-rw-r--r--nix/templates/goapp/frontend/src/handlers.go236
1 files changed, 236 insertions, 0 deletions
diff --git a/nix/templates/goapp/frontend/src/handlers.go b/nix/templates/goapp/frontend/src/handlers.go
new file mode 100644
index 0000000..8fdd325
--- /dev/null
+++ b/nix/templates/goapp/frontend/src/handlers.go
@@ -0,0 +1,236 @@
+package main
+
+import (
+	"fmt"
+	"html/template"
+	"log"
+	"net/http"
+
+	"github.com/coreos/go-oidc/v3/oidc"
+	"github.com/gorilla/sessions"
+	"golang.org/x/oauth2"
+)
+
+func indexHandler(w http.ResponseWriter, r *http.Request) {
+	session, err := globalState.sessions.Get(r, "session")
+	if err != nil {
+		log.Println("error getting the session")
+	}
+
+	tpl := indexTplData{
+		Error: r.FormValue("error"),
+	}
+
+	tpl.Breadcrumbs = []Breadcrumb{
+		{
+			Link{"a", "b"},
+			[]Link{
+				{"c", "d"},
+				{"e", "f"},
+			},
+		},
+		{
+			Link{"g", "h"},
+			[]Link{
+				{"i", "j"},
+				{"k", "l"},
+			},
+		},
+	}
+	tpl.NextLinks = []Link{
+		{"Login", "/login"},
+	}
+
+	if logged, ok := session.Values["logged"].(bool); ok && logged {
+		tpl.LoggedIn = true
+		tpl.Claims.IDToken = session.Values["id_token"].(Claims)
+		tpl.Claims.UserInfo = session.Values["userinfo"].(Claims)
+
+		if len(options.GroupsFilter) >= 1 {
+			for _, group := range tpl.Claims.UserInfo.Groups {
+				if isStringInSlice(group, options.GroupsFilter) {
+					tpl.Groups = append(tpl.Groups, filterText(group, options.Filters))
+				}
+			}
+		} else {
+			tpl.Groups = filterSliceOfText(tpl.Claims.UserInfo.Groups, options.Filters)
+		}
+
+		tpl.Claims.IDToken.PreferredUsername = filterText(tpl.Claims.IDToken.PreferredUsername, options.Filters)
+		tpl.Claims.UserInfo.PreferredUsername = filterText(tpl.Claims.UserInfo.PreferredUsername, options.Filters)
+		tpl.Claims.IDToken.Audience = filterSliceOfText(tpl.Claims.IDToken.Audience, options.Filters)
+		tpl.Claims.UserInfo.Audience = filterSliceOfText(tpl.Claims.UserInfo.Audience, options.Filters)
+		tpl.Claims.IDToken.Issuer = filterText(tpl.Claims.IDToken.Issuer, options.Filters)
+		tpl.Claims.UserInfo.Issuer = filterText(tpl.Claims.UserInfo.Issuer, options.Filters)
+		tpl.Claims.IDToken.Email = filterText(tpl.Claims.IDToken.Email, options.Filters)
+		tpl.Claims.UserInfo.Email = filterText(tpl.Claims.UserInfo.Email, options.Filters)
+		tpl.Claims.IDToken.Name = filterText(tpl.Claims.IDToken.Name, options.Filters)
+		tpl.Claims.UserInfo.Name = filterText(tpl.Claims.UserInfo.Name, options.Filters)
+		tpl.RawToken = rawTokens[tpl.Claims.IDToken.JWTIdentifier]
+		tpl.AuthorizeCodeURL = acURLs[tpl.Claims.IDToken.JWTIdentifier].String()
+	}
+
+	w.Header().Add("Content-Type", "text/html")
+
+	// get the template
+	t, err := template.New("index").Funcs(templateFuncMap).ParseGlob(fmt.Sprintf("%s/*.html", options.TemplatesPath))
+	if err != nil {
+		log.Printf("Error reading the template Path: %s/*.html", options.TemplatesPath)
+		log.Println(err)
+		w.WriteHeader(http.StatusInternalServerError)
+		w.Write([]byte("500 - Error reading template file"))
+		return
+	}
+
+	// exec!
+	err = t.ExecuteTemplate(w, "index", tpl)
+	if err != nil {
+		log.Println(err)
+	}
+}
+
+func loginHandler(w http.ResponseWriter, r *http.Request) {
+	log.Println("[ ] Getting the global session from the session cookie:")
+	session, err := globalState.sessions.Get(r, options.CookieName)
+	if err != nil {
+		log.Println("[ ] Error getting the cookie")
+		writeErr(w, nil, "error getting cookie", http.StatusInternalServerError)
+		return
+	}
+
+	log.Println("[ ] Setting the redirect URL")
+	session.Values["redirect-url"] = "/"
+
+	log.Println("[ ] Saving the session")
+	if err = session.Save(r, w); err != nil {
+		writeErr(w, err, "error saving session", http.StatusInternalServerError)
+		return
+	}
+
+	log.Printf("[ ] Redirecting to %s", oauth2Config.AuthCodeURL("random-string"))
+	http.Redirect(w, r, oauth2Config.AuthCodeURL("random-string-here"), http.StatusFound)
+}
+
+func logoutHandler(w http.ResponseWriter, r *http.Request) {
+	session, err := globalState.sessions.Get(r, options.CookieName)
+	if err != nil {
+		writeErr(w, err, "error getting cookie", http.StatusInternalServerError)
+		return
+	}
+
+	// wet the session
+	session.Values = make(map[interface{}]interface{})
+
+	if err = session.Save(r, w); err != nil {
+		writeErr(w, err, "error saving session", http.StatusInternalServerError)
+		return
+	}
+
+	http.Redirect(w, r, "/", http.StatusFound)
+}
+
+func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) {
+	log.Println("hit the oauth callback handler")
+	if req.FormValue("error") != "" {
+		log.Printf("got an error from the idp: %s", req.FormValue("error"))
+		http.Redirect(res, req, fmt.Sprintf("/error?%s", req.Form.Encode()), http.StatusFound)
+
+		return
+	}
+
+	var (
+		token      *oauth2.Token
+		idToken    *oidc.IDToken
+		err        error
+		idTokenRaw string
+		ok         bool
+	)
+
+	// The state should be checked here in production
+	if token, err = oauth2Config.Exchange(req.Context(), req.URL.Query().Get("code")); err != nil {
+		log.Println("Unable to exchange authorization code for tokens")
+		writeErr(res, err, "unable to exchange authorization code for tokens", http.StatusInternalServerError)
+		return
+	}
+
+	// Extract the ID Token from OAuth2 token.
+	if idTokenRaw, ok = token.Extra("id_token").(string); !ok {
+		log.Println("missing id token")
+		writeErr(res, nil, "missing id token", http.StatusInternalServerError)
+		return
+	}
+
+	// Parse and verify ID Token payload.
+	if idToken, err = verifier.Verify(req.Context(), idTokenRaw); err != nil {
+		log.Printf("unable to verify id token or token is invalid: %+v", idTokenRaw)
+		writeErr(res, err, "unable to verify id token or token is invalid", http.StatusInternalServerError)
+		return
+	}
+
+	// Extract custom claims
+	claimsIDToken := Claims{}
+
+	if err = idToken.Claims(&claimsIDToken); err != nil {
+		log.Printf("unable to decode id token claims: %+v", &claimsIDToken)
+		writeErr(res, err, "unable to decode id token claims", http.StatusInternalServerError)
+		return
+	}
+
+	var userinfo *oidc.UserInfo
+
+	if userinfo, err = provider.UserInfo(req.Context(), oauth2.StaticTokenSource(token)); err != nil {
+		log.Printf("unable to retreive userinfo claims")
+		writeErr(res, err, "unable to retrieve userinfo claims", http.StatusInternalServerError)
+		return
+	}
+
+	claimsUserInfo := Claims{}
+
+	if err = userinfo.Claims(&claimsUserInfo); err != nil {
+		log.Printf("unable to decode userinfo claims")
+		writeErr(res, err, "unable to decode userinfo claims", http.StatusInternalServerError)
+		return
+	}
+
+	var session *sessions.Session
+
+	if session, err = globalState.sessions.Get(req, options.CookieName); err != nil {
+		log.Printf("unable to get session from cookie")
+		writeErr(res, err, "unable to get session from cookie", http.StatusInternalServerError)
+		return
+	}
+
+	session.Values["id_token"] = claimsIDToken
+	session.Values["userinfo"] = claimsUserInfo
+	session.Values["logged"] = true
+	rawTokens[claimsIDToken.JWTIdentifier] = idTokenRaw
+	acURLs[claimsIDToken.JWTIdentifier] = req.URL
+
+	if err = session.Save(req, res); err != nil {
+		log.Printf("unable to save session")
+		writeErr(res, err, "unable to save session", http.StatusInternalServerError)
+		return
+	}
+
+	var redirectUrl string
+
+	if redirectUrl, ok = session.Values["redirect-url"].(string); ok {
+		log.Printf("all fine!")
+		http.Redirect(res, req, redirectUrl, http.StatusFound)
+		return
+	}
+
+	http.Redirect(res, req, "/", http.StatusFound)
+}
+
+func writeErr(w http.ResponseWriter, err error, msg string, statusCode int) {
+	switch {
+	case err == nil:
+		log.Println(msg)
+		http.Error(w, msg, statusCode)
+	default:
+		log.Println(msg)
+		log.Println(err)
+		http.Error(w, fmt.Errorf("%s: %w", msg, err).Error(), statusCode)
+	}
+}