diff options
-rw-r--r-- | nix/hosts/corrino/secrets/goapp_oidc_secret.age | bin | 395 -> 395 bytes | |||
-rw-r--r-- | nix/hosts/corrino/secrets/goapp_oidc_session_key.age | 8 | ||||
-rw-r--r-- | nix/hosts/corrino/www/goapp.emile.space.nix | 53 | ||||
-rw-r--r-- | nix/modules/goapp-frontend/default.nix | 2 | ||||
-rw-r--r-- | nix/templates/goapp/frontend/src/handlers.go | 65 | ||||
-rw-r--r-- | nix/templates/goapp/frontend/src/init.go | 9 | ||||
-rw-r--r-- | nix/templates/goapp/frontend/templates/index.html | 2 |
7 files changed, 92 insertions, 47 deletions
diff --git a/nix/hosts/corrino/secrets/goapp_oidc_secret.age b/nix/hosts/corrino/secrets/goapp_oidc_secret.age index a842003..ca96981 100644 --- a/nix/hosts/corrino/secrets/goapp_oidc_secret.age +++ b/nix/hosts/corrino/secrets/goapp_oidc_secret.age Binary files differdiff --git a/nix/hosts/corrino/secrets/goapp_oidc_session_key.age b/nix/hosts/corrino/secrets/goapp_oidc_session_key.age new file mode 100644 index 0000000..938f97f --- /dev/null +++ b/nix/hosts/corrino/secrets/goapp_oidc_session_key.age @@ -0,0 +1,8 @@ +age-encryption.org/v1 +-> ssh-ed25519 gvwQ2Q BAvDdIEUEgmo963+9Wd5VLJgrp3MBISvWR3+27bfJW8 +NOEj2ObYe/cM2CaqzmbgexSEUNZIEo1ZmvlamJaSOjo +-> ssh-ed25519 m8VklA d/hwd3rGkPD3GDdlOP2XUsi687VH+tfKrAsKnImk+kI +gFAyyMZT5DK7da7YXOf/5gUd4Bi9cEe3ddMKUMuctMU +--- 9tVE+AAvptrlMZe5+UGJGzH9usnxa+ZICbikcRT0PYI +g!X+/šØ0P ;™*{ª«V p!¶êÙ4£sÌöãa ÎI+À/\Iœ‚Ô–,Äéo½p‡Î웘DP7"ŠíØÀ¦ä;p·„PÀpÍ +%ÈcÒUÚœ8 \ No newline at end of file diff --git a/nix/hosts/corrino/www/goapp.emile.space.nix b/nix/hosts/corrino/www/goapp.emile.space.nix index 4a486aa..361e95a 100644 --- a/nix/hosts/corrino/www/goapp.emile.space.nix +++ b/nix/hosts/corrino/www/goapp.emile.space.nix @@ -17,11 +17,10 @@ id = "goapp"; # ; nix run nixpkgs#authelia -- crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 - secret = "$pbkdf2-sha512$310000$/Ht5DUFmIeu/7Ty2PWHXnw$.uJIN1vmZMyGjCAoA0PzUcVaTMIH36AK80KvOZAHVXgLr1Y9ZOrRjoiwK.srHAO29mrcw1BNpCjFTYdWOoympg"; + secret = "$pbkdf2-sha512$310000$LPXJRoGR9RyTcaT6cADljg$FK8RV5CnKj5ano4fXmRzzvXcX/00F7k/G6nd67t.8iewpwyq8FntV4JgYZSV8AynYMxz1qnL4j3BzITLCM0KgQ"; public = false; authorization_policy = "two_factor"; redirect_uris = [ - # "http://localhost:8080/oauth2/callback" "https://goapp.emile.space/oauth2/callback" ]; scopes = [ @@ -51,28 +50,40 @@ # - build in order to get the new hash (nix build .#goapp-frontend-pkg) # - update hash in the package (//nix/templates/goapp/frontent/default.nix) # - deploy + # + # https://goapp.emile.space/oauth2/callback?code=authelia_ac_iZKCXtRMnj2yjUAmiSkg_LBWjiME2-ghE6KMkxdb6Zw.nDLgCVpu9ctH1llEKUml5rr8szd3bkZYaGa_MAOtNLI&iss=https%3A%2F%2Fsso.emile.space&scope=openid+profile+email+groups&state=random-string-here + # + # Unable to exchange authorization code for tokens + # + # unable to exchange authorization code for tokens: oauth2: "invalid_client" "Client authentication failed (e.g., unknown client, no client authentication included, or unsupported authentication method)." - # services.emile.goapp-frontend = { - # enable = true; - # package = pkgs.goapp-frontend; + services.emile.goapp-frontend = { + enable = true; + package = pkgs.goapp-frontend; - # host = "127.0.0.1"; - # port = config.emile.ports.goapp-frontend; - # public-url = "https://goapp-frontend.emile.space/"; + host = "127.0.0.1"; + port = config.emile.ports.goapp; + public-url = "https://goapp.emile.space/"; - # oidc = { - # id = "goapp-frontend"; - # issuer = "https://sso.emile.space"; - # cookie-name = "oidc-client"; - # scopes = [ "openid" "profile" "email" "groups" ]; - # secret-path = "/run/goapp-frontend_oidc_secret"; - # }; + oidc = { + id = "goapp"; + issuer = "https://sso.emile.space"; + cookie-name = "oidc-client"; + scopes = [ + "openid" + "profile" + "email" + "groups" + ]; + # secret-path = "/run/goapp-frontend_oidc_secret"; + secret-path = config.age.secrets.goapp_oidc_secret.path; + }; - # # TODO(emile): change these when going live - # session-key-path = config.age.secrets.goapp-frontend_oidc_secret.path; + # TODO(emile): change these when going live + session-key-path = config.age.secrets.goapp_oidc_secret.path; - # logfile-path = "/var/log/goapp-frontend.log"; - # database-path = "/var/lib/goapp-frontend/main.db"; - # sessiondb-path = "/var/lib/goapp-frontend/session.db"; - # }; + logfile-path = "/var/log/goapp-frontend.log"; + database-path = "/var/lib/goapp-frontend/main.db"; + sessiondb-path = "/var/lib/goapp-frontend/session.db"; + }; } diff --git a/nix/modules/goapp-frontend/default.nix b/nix/modules/goapp-frontend/default.nix index 31573f7..c5f62aa 100644 --- a/nix/modules/goapp-frontend/default.nix +++ b/nix/modules/goapp-frontend/default.nix @@ -114,7 +114,7 @@ with lib; }; path = [ pkgs.goapp-frontend ]; serviceConfig.ExecStart = '' - ${pkgs.goapp-frontend}/bin/goapp-frontend \ + ${pkgs.goapp-frontend}/bin/frontend \ --host ${cfg.host} \ --port ${toString cfg.port} \ --public-url ${cfg.public-url} \ diff --git a/nix/templates/goapp/frontend/src/handlers.go b/nix/templates/goapp/frontend/src/handlers.go index b0bbf91..2cbacde 100644 --- a/nix/templates/goapp/frontend/src/handlers.go +++ b/nix/templates/goapp/frontend/src/handlers.go @@ -12,7 +12,7 @@ import ( ) func indexHandler(w http.ResponseWriter, r *http.Request) { - session, err := globalState.sessions.Get(r, "session") + session, err := globalState.sessions.Get(r, options.CookieName) if err != nil { log.Println("error getting the session") } @@ -37,9 +37,14 @@ func indexHandler(w http.ResponseWriter, r *http.Request) { }, }, } - tpl.NextLinks = []Link{ - {"Login", "/login"}, - } + + // session.Values["id_token"] = claimsIDToken + // session.Values["userinfo"] = claimsUserInfo + // session.Values["logged"] = true + // + log.Println("logged", session.Values["logged"]) + log.Println("id-token", session.Values["id_token"]) + log.Println("userinfo", session.Values["userinfo"]) if logged, ok := session.Values["logged"].(bool); ok && logged { tpl.LoggedIn = true @@ -68,6 +73,10 @@ func indexHandler(w http.ResponseWriter, r *http.Request) { 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() + + tpl.NextLinks = []Link{{"Logout", "/logout"}} + } else { + tpl.NextLinks = []Link{{"Login", "/login"}} } w.Header().Add("Content-Type", "text/html") @@ -129,11 +138,11 @@ func logoutHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, "/", http.StatusFound) } -func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) { +func oauthCallbackHandler(w http.ResponseWriter, r *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) + if r.FormValue("error") != "" { + log.Printf("got an error from the idp: %s", r.FormValue("error")) + http.Redirect(w, r, fmt.Sprintf("/error?%s", r.Form.Encode()), http.StatusFound) return } @@ -145,24 +154,32 @@ func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) { ok bool ) + log.Println(r.URL) + // The state should be checked here in production - if token, err = oauth2Config.Exchange(req.Context(), req.URL.Query().Get("code")); err != nil { + if token, err = oauth2Config.Exchange( + r.Context(), + r.URL.Query().Get("code"), + // oauth2.SetAuthURLParam("client_id", oauth2Config.ClientID), + // oauth2.SetAuthURLParam("client_secret", oauth2Config.ClientSecret), + ); err != nil { log.Println("Unable to exchange authorization code for tokens") - writeErr(res, err, "unable to exchange authorization code for tokens", http.StatusInternalServerError) + log.Println(err) + writeErr(w, 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) + writeErr(w, nil, "missing id token", http.StatusInternalServerError) return } // Parse and verify ID Token payload. - if idToken, err = verifier.Verify(req.Context(), idTokenRaw); err != nil { + if idToken, err = verifier.Verify(r.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) + writeErr(w, err, "unable to verify id token or token is invalid", http.StatusInternalServerError) return } @@ -171,15 +188,15 @@ func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) { 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) + writeErr(w, 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 { + if userinfo, err = provider.UserInfo(r.Context(), oauth2.StaticTokenSource(token)); err != nil { log.Printf("unable to retreive userinfo claims") - writeErr(res, err, "unable to retrieve userinfo claims", http.StatusInternalServerError) + writeErr(w, err, "unable to retrieve userinfo claims", http.StatusInternalServerError) return } @@ -187,15 +204,15 @@ func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) { if err = userinfo.Claims(&claimsUserInfo); err != nil { log.Printf("unable to decode userinfo claims") - writeErr(res, err, "unable to decode userinfo claims", http.StatusInternalServerError) + writeErr(w, err, "unable to decode userinfo claims", http.StatusInternalServerError) return } var session *sessions.Session - if session, err = globalState.sessions.Get(req, options.CookieName); err != nil { + if session, err = globalState.sessions.Get(r, options.CookieName); err != nil { log.Printf("unable to get session from cookie") - writeErr(res, err, "unable to get session from cookie", http.StatusInternalServerError) + writeErr(w, err, "unable to get session from cookie", http.StatusInternalServerError) return } @@ -203,11 +220,11 @@ func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) { session.Values["userinfo"] = claimsUserInfo session.Values["logged"] = true rawTokens[claimsIDToken.JWTIdentifier] = idTokenRaw - acURLs[claimsIDToken.JWTIdentifier] = req.URL + acURLs[claimsIDToken.JWTIdentifier] = r.URL - if err = session.Save(req, res); err != nil { + if err = session.Save(r, w); err != nil { log.Printf("unable to save session") - writeErr(res, err, "unable to save session", http.StatusInternalServerError) + writeErr(w, err, "unable to save session", http.StatusInternalServerError) return } @@ -215,11 +232,11 @@ func oauthCallbackHandler(res http.ResponseWriter, req *http.Request) { if redirectUrl, ok = session.Values["redirect-url"].(string); ok { log.Printf("all fine!") - http.Redirect(res, req, redirectUrl, http.StatusFound) + http.Redirect(w, r, redirectUrl, http.StatusFound) return } - http.Redirect(res, req, "/", http.StatusFound) + http.Redirect(w, r, "/", http.StatusFound) } func writeErr(w http.ResponseWriter, err error, msg string, statusCode int) { diff --git a/nix/templates/goapp/frontend/src/init.go b/nix/templates/goapp/frontend/src/init.go index dc0e252..75fd87d 100644 --- a/nix/templates/goapp/frontend/src/init.go +++ b/nix/templates/goapp/frontend/src/init.go @@ -2,8 +2,10 @@ package main import ( "context" + // "crypto/tls" "fmt" "log" + // "net/http" "net/url" "os" "strings" @@ -70,13 +72,15 @@ func oauth2Init() (err error) { if err != nil { panic(err) } - clientSecret := string(clientSecretBytes) + clientSecret := strings.TrimSpace(string(clientSecretBytes)) log.Printf("[ ] ClientID: %s", options.ClientID) log.Printf("[ ] ClientSecret: %s", clientSecret) log.Printf("[ ] redirectURL: %s", redirectURL.String()) log.Printf("[ ] providerEndpoint: %+v", provider.Endpoint()) log.Printf("[ ] Scopes: %s", options.Scopes) + log.Printf("[ ] Endpoint: %+v", provider.Endpoint()) + oauth2Config = oauth2.Config{ ClientID: options.ClientID, ClientSecret: clientSecret, @@ -84,5 +88,8 @@ func oauth2Init() (err error) { Endpoint: provider.Endpoint(), Scopes: strings.Split(options.Scopes, ","), } + + oauth2Config.Endpoint.AuthStyle = oauth2.AuthStyleInParams + return nil } diff --git a/nix/templates/goapp/frontend/templates/index.html b/nix/templates/goapp/frontend/templates/index.html index 1d21f3d..e4693af 100644 --- a/nix/templates/goapp/frontend/templates/index.html +++ b/nix/templates/goapp/frontend/templates/index.html @@ -5,6 +5,8 @@ <h1>goapp</h1> +{{ . }} + {{- if .LoggedIn }} <p id="welcome">Logged in as {{ or .Claims.UserInfo.PreferredUsername .Claims.IDToken.Subject "unknown" }}!</p> <p><a href="/logout" id="log-out">Log out</a></p> |