diff --git a/changelog.md b/changelog.md index ed42568..757dd10 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased +### Changed +- let the session expire when the token expires +### Added +- add identity output to index page + ## [0.2.0] ### Changed - re-order configuration precedence diff --git a/cmd/app/main.go b/cmd/app/main.go index 069a061..4afc18d 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -128,7 +128,7 @@ func main() { publicURL := buildPublicURL(config.MustString("server.name"), config.MustInt("server.port")) - indexHandler, err := handlers.NewIndexHandler(bundle, catalog, ui.Templates, oidcInfo, publicURL) + indexHandler, err := handlers.NewIndexHandler(logger, bundle, catalog, oidcInfo, publicURL) if err != nil { logger.WithError(err).Fatal("could not initialize index handler") } @@ -154,7 +154,7 @@ func main() { logging := handlers.Logging(logger) hsts := handlers.EnableHSTS() - errorMiddleware, err := handlers.ErrorHandling(logger, ui.Templates, bundle, catalog) + errorMiddleware, err := handlers.ErrorHandling(logger, bundle, catalog) if err != nil { logger.WithError(err).Fatal("could not initialize request error handling") } diff --git a/internal/handlers/common.go b/internal/handlers/common.go index 538e5d8..9dc7da5 100644 --- a/internal/handlers/common.go +++ b/internal/handlers/common.go @@ -77,7 +77,7 @@ func Authenticate(logger *log.Logger, oauth2Config *oauth2.Config, clientID stri queryValues := authURL.Query() queryValues.Set("client_id", clientID) queryValues.Set("response_type", "code") - queryValues.Set("scope", "openid offline_access profile email") + queryValues.Set("scope", "openid profile email cacert_groups") queryValues.Set("state", base64.URLEncoding.EncodeToString(services.GenerateKey(oauth2RedirectStateLength))) queryValues.Set("claims", getRequestedClaims(logger)) authURL.RawQuery = queryValues.Encode() diff --git a/internal/handlers/errors.go b/internal/handlers/errors.go index 68043f2..a05ee35 100644 --- a/internal/handlers/errors.go +++ b/internal/handlers/errors.go @@ -21,12 +21,13 @@ import ( "context" "fmt" "html/template" - "io/fs" "net/http" "github.com/nicksnyder/go-i18n/v2/i18n" log "github.com/sirupsen/logrus" + "code.cacert.org/cacert/oidc-demo-app/ui" + "code.cacert.org/cacert/oidc-demo-app/internal/services" ) @@ -135,12 +136,11 @@ func (w *errorResponseWriter) Write(content []byte) (int, error) { func ErrorHandling( logger *log.Logger, - templateFS fs.FS, bundle *i18n.Bundle, messageCatalog *services.MessageCatalog, ) (func(http.Handler) http.Handler, error) { errorTemplates, err := template.ParseFS( - templateFS, + ui.Templates, "templates/base.gohtml", "templates/errors.gohtml", ) diff --git a/internal/handlers/index.go b/internal/handlers/index.go index 0318490..bfb9798 100644 --- a/internal/handlers/index.go +++ b/internal/handlers/index.go @@ -20,12 +20,14 @@ package handlers import ( "fmt" "html/template" - "io/fs" "net/http" "net/url" "github.com/lestrrat-go/jwx/jwk" "github.com/nicksnyder/go-i18n/v2/i18n" + log "github.com/sirupsen/logrus" + + "code.cacert.org/cacert/oidc-demo-app/ui" "code.cacert.org/cacert/oidc-demo-app/internal/services" ) @@ -33,6 +35,7 @@ import ( type IndexHandler struct { bundle *i18n.Bundle indexTemplate *template.Template + logger *log.Logger keySet jwk.Set logoutURL string messageCatalog *services.MessageCatalog @@ -72,10 +75,20 @@ func (h *IndexHandler) ServeHTTP(writer http.ResponseWriter, request *http.Reque } var ( - idToken string - ok bool + accessToken string + refreshToken string + idToken string + ok bool ) + if accessToken, ok = session.Values[sessionKeyAccessToken].(string); ok { + h.logger.WithField("access_token", accessToken).Info("found access token in session") + } + + if refreshToken, ok = session.Values[refreshToken].(string); ok { + h.logger.WithField("refresh_token", refreshToken).Info("found refresh token in session") + } + if idToken, ok = session.Values[sessionKeyIDToken].(string); ok { logoutURL.RawQuery = url.Values{ "id_token_hint": []string{idToken}, @@ -92,6 +105,10 @@ func (h *IndexHandler) ServeHTTP(writer http.ResponseWriter, request *http.Reque return } + expires := oidcToken.Expiration() + + h.logger.WithField("expires", expires).Info("id token expires at") + writer.Header().Add("Content-Type", "text/html") msgLookup := h.messageCatalog.LookupMessage @@ -104,6 +121,10 @@ func (h *IndexHandler) ServeHTTP(writer http.ResponseWriter, request *http.Reque "IntroductionText": msgLookup("IndexIntroductionText", nil, localizer), "LogoutLabel": msgLookup("LogoutLabel", nil, localizer), "LogoutURL": logoutURL.String(), + "AuthenticatedAs": msgLookup("AuthenticatedAs", map[string]interface{}{ + "Name": oidcToken.Name(), + "Email": oidcToken.Email(), + }, localizer), }) if err != nil { http.Error(writer, err.Error(), http.StatusInternalServerError) @@ -113,20 +134,21 @@ func (h *IndexHandler) ServeHTTP(writer http.ResponseWriter, request *http.Reque } func NewIndexHandler( + logger *log.Logger, bundle *i18n.Bundle, catalog *services.MessageCatalog, - templateFS fs.FS, oidcInfo *services.OIDCInformation, publicURL string, ) (*IndexHandler, error) { indexTemplate, err := template.ParseFS( - templateFS, + ui.Templates, "templates/base.gohtml", "templates/index.gohtml") if err != nil { return nil, fmt.Errorf("could not parse templates: %w", err) } return &IndexHandler{ + logger: logger, bundle: bundle, indexTemplate: indexTemplate, keySet: oidcInfo.KeySet, diff --git a/internal/handlers/oidc_callback.go b/internal/handlers/oidc_callback.go index 40e0157..c07360b 100644 --- a/internal/handlers/oidc_callback.go +++ b/internal/handlers/oidc_callback.go @@ -20,6 +20,7 @@ package handlers import ( "fmt" "net/http" + "time" "github.com/gorilla/sessions" "github.com/lestrrat-go/jwx/jwk" @@ -142,6 +143,8 @@ func (c *OidcCallbackHandler) storeTokens( session.Values[sessionKeyIDToken] = idToken + session.Options.MaxAge = int(time.Until(tok.Expiry).Seconds()) + oidcToken, err := ParseIDToken(idToken, c.keySet) if err != nil { return fmt.Errorf("could not parse ID token: %w", err) diff --git a/internal/services/i18n.go b/internal/services/i18n.go index 0b9c36f..2fd26bd 100644 --- a/internal/services/i18n.go +++ b/internal/services/i18n.go @@ -32,6 +32,11 @@ import ( func AddMessages(catalog *MessageCatalog) { messages := make(map[string]*i18n.Message) + messages["AuthenticatedAs"] = &i18n.Message{ + ID: "AuthenticatedAs", + Other: "The identity provider authenticated your identity as {{ .Name }}" + + " with the email address {{ .Email }}.", + } messages["IndexGreeting"] = &i18n.Message{ ID: "IndexGreeting", Other: "Hello {{ .User }}", diff --git a/translations/active.de.toml b/translations/active.de.toml index ec6153e..6e38b1d 100644 --- a/translations/active.de.toml +++ b/translations/active.de.toml @@ -1,3 +1,7 @@ +[AuthenticatedAs] +hash = "sha1-58e33592c806dab9cddd3693c0cfee64a07a0a9b" +other = "Der Identity-Provider hat dich als {{ .Name }} mit der E-Mail-Adresse {{ .Email }} identifiziert." + [ErrorTitle] hash = "sha1-736aec25a98f5ec5b71400bb0163f891f509b566" other = "Es ist ein Fehler aufgetreten" diff --git a/translations/active.en.toml b/translations/active.en.toml index 6a516a7..23a9930 100644 --- a/translations/active.en.toml +++ b/translations/active.en.toml @@ -1,3 +1,4 @@ +AuthenticatedAs = "The identity provider authenticated your identity as {{ .Name }} with the email address {{ .Email }}." ErrorTitle = "An error has occurred" IndexGreeting = "Hello {{ .User }}" IndexIntroductionText = "This is an authorization protected resource" diff --git a/ui/templates/index.gohtml b/ui/templates/index.gohtml index adba408..fa446d0 100644 --- a/ui/templates/index.gohtml +++ b/ui/templates/index.gohtml @@ -3,6 +3,7 @@ CAcert

{{ .Greeting }}

{{ .IntroductionText }}

+

{{ .AuthenticatedAs }}

{{ .LogoutLabel }} {{ end }} \ No newline at end of file