Skip to content

Commit

Permalink
feat: add user session cookies ttl external config
Browse files Browse the repository at this point in the history
  • Loading branch information
BarcoMasile committed Jun 28, 2024
1 parent 9cfdd69 commit b4da23d
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 45 deletions.
5 changes: 4 additions & 1 deletion OAUTH2.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ OAUTH2_CLIENT_SECRET=client secret
OAUTH2_REDIRECT_URI=http://localhost:${PORT}/api/v0/auth/callback
OAUTH2_CODEGRANT_SCOPES=openid,offline_access (defaults to these two, technically two more would be needed: "profile,email")
OAUTH2_AUTH_COOKIES_ENCRYPTION_KEY="WrfOcYmVBwyduEbKYTUhO4X7XVaOQ1wF" (required, this needs to be exactly 32 bytes in lenght secret key)
OAUTH2_REFRESHTOKEN_COOKIE_TTL_SECONDS=expiration in seconds for the refresh token cookie, should match the hydra refresh token ttl, (defaults to 21600)
ACCESS_TOKEN_VERIFICATION_STRATEGY="jwks|userinfo", (defaults to jwks)
```

Expand Down Expand Up @@ -79,7 +80,9 @@ The Hydra client for Admin UI needs to be set with the proper:
- response types: `"token,code,id_token"`
- grant types: `"authorization_code,refresh_token"`

If you use the Login UI [docker compose](https://github.com/canonical/identity-platform-login-ui/blob/main/docker-compose.yml) to deploy the solution with Github integration, you can first create an OAuth2
If you use the Login
UI [docker compose](https://github.com/canonical/identity-platform-login-ui/blob/main/docker-compose.yml) to deploy the
solution with Github integration, you can first create an OAuth2
client.
Then update it with the correct values, as in the following script:

Expand Down
1 change: 1 addition & 0 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ func serve() {
specs.OAuth2RedirectURI,
specs.AccessTokenVerificationStrategy,
specs.OAuth2AuthCookiesTTLSeconds,
specs.OAuth2UserSessionTTLSeconds,
specs.OAuth2AuthCookiesEncryptionKey,
specs.OAuth2CodeGrantScopes,
)
Expand Down
20 changes: 11 additions & 9 deletions internal/config/specs.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,17 @@ type EnvSpec struct {
HydraAdminURL string `envconfig:"hydra_admin_url" required:"true"`
OathkeeperPublicURL string `envconfig:"oathkeeper_public_url" required:"true"`

AuthenticationEnabled bool `envconfig:"authentication_enabled" default:"false" validate:"required"`
OIDCIssuer string `envconfig:"oidc_issuer" validate:"required"`
OAuth2ClientId string `envconfig:"oauth2_client_id" validate:"required"`
OAuth2ClientSecret string `envconfig:"oauth2_client_secret" validate:"required"`
OAuth2RedirectURI string `envconfig:"oauth2_redirect_uri" validate:"required"`
OAuth2CodeGrantScopes []string `envconfig:"oauth2_codegrant_scopes" default:"openid,offline_access" validate:"required"`
OAuth2AuthCookiesTTLSeconds int `envconfig:"oauth2_auth_cookies_ttl_seconds" default:"300" validate:"required"`
OAuth2AuthCookiesEncryptionKey string `envconfig:"oauth2_auth_cookies_encryption_key" required:"true" validate:"required,min=32,max=32"`
AccessTokenVerificationStrategy string `envconfig:"access_token_verification_strategy" default:"jwks" validate:"oneof=jwks userinfo"`
AuthenticationEnabled bool `envconfig:"authentication_enabled" default:"false" validate:"required"`
OIDCIssuer string `envconfig:"oidc_issuer" validate:"required"`
OAuth2ClientId string `envconfig:"oauth2_client_id" validate:"required"`
OAuth2ClientSecret string `envconfig:"oauth2_client_secret" validate:"required"`
OAuth2RedirectURI string `envconfig:"oauth2_redirect_uri" validate:"required"`
OAuth2CodeGrantScopes []string `envconfig:"oauth2_codegrant_scopes" default:"openid,offline_access" validate:"required"`
OAuth2AuthCookiesTTLSeconds int `envconfig:"oauth2_auth_cookies_ttl_seconds" default:"300" validate:"required"`
OAuth2UserSessionTTLSeconds int `envconfig:"oauth2_user_session_ttl_seconds" default:"21600" validate:"required"`

OAuth2AuthCookiesEncryptionKey string `envconfig:"oauth2_auth_cookies_encryption_key" required:"true" validate:"required,min=32,max=32"`
AccessTokenVerificationStrategy string `envconfig:"access_token_verification_strategy" default:"jwks" validate:"oneof=jwks userinfo"`

IDPConfigMapName string `envconfig:"idp_configmap_name" required:"true"`
IDPConfigMapNamespace string `envconfig:"idp_configmap_namespace" required:"true"`
Expand Down
61 changes: 30 additions & 31 deletions pkg/authentication/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,19 @@ const (
)

type Config struct {
Enabled bool `validate:"required,boolean"`
AuthCookieTTLSeconds int `validate:"required"`
CookiesEncryptionKey string `validate:"required,min=32,max=32"`
issuer string `validate:"required"`
clientID string `validate:"required"`
clientSecret string `validate:"required"`
redirectURL string `validate:"required"`
verificationStrategy string `validate:"required,oneof=jwks userinfo"`
scopes []string `validate:"required,dive,required"`
Enabled bool `validate:"required,boolean"`
AuthCookieTTLSeconds int `validate:"required"`
UserSessionCookieTTLSeconds int `validate:"required"`
CookiesEncryptionKey string `validate:"required,min=32,max=32"`
issuer string `validate:"required"`
clientID string `validate:"required"`
clientSecret string `validate:"required"`
redirectURL string `validate:"required"`
verificationStrategy string `validate:"required,oneof=jwks userinfo"`
scopes []string `validate:"required,dive,required"`
}

type oauth2Tokens struct {
IDToken string `json:"id_token"`
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
}

func NewAuthenticationConfig(enabled bool, issuer, clientID, clientSecret, redirectURL, verificationStrategy string, cookieTTLSeconds int, cookiesEncryptionKey string, scopes []string) *Config {
func NewAuthenticationConfig(enabled bool, issuer, clientID, clientSecret, redirectURL, verificationStrategy string, authCookiesTTLSeconds, userSessionCookieTTLSeconds int, cookiesEncryptionKey string, scopes []string) *Config {
c := new(Config)
c.Enabled = enabled
c.CookiesEncryptionKey = cookiesEncryptionKey
Expand All @@ -51,18 +46,18 @@ func NewAuthenticationConfig(enabled bool, issuer, clientID, clientSecret, redir
c.redirectURL = redirectURL
c.verificationStrategy = verificationStrategy
c.scopes = scopes
c.AuthCookieTTLSeconds = cookieTTLSeconds
c.AuthCookieTTLSeconds = authCookiesTTLSeconds
c.UserSessionCookieTTLSeconds = userSessionCookieTTLSeconds

return c
}

type API struct {
apiKey string
payloadValidator validation.PayloadValidatorInterface
oauth2 OAuth2ContextInterface
helper OAuth2HelperInterface
cookieManager AuthCookieManagerInterface
authCookiesTTLSeconds int
apiKey string
payloadValidator validation.PayloadValidatorInterface
oauth2 OAuth2ContextInterface
helper OAuth2HelperInterface
cookieManager AuthCookieManagerInterface

tracer trace.Tracer
logger logging.LoggerInterface
Expand All @@ -80,10 +75,8 @@ func (a *API) handleLogin(w http.ResponseWriter, r *http.Request) {
nonce := a.helper.RandomURLString()
state := a.helper.RandomURLString()

ttl := time.Duration(a.authCookiesTTLSeconds) * time.Second

a.cookieManager.SetNonceCookie(w, nonce, ttl)
a.cookieManager.SetStateCookie(w, state, ttl)
a.cookieManager.SetNonceCookie(w, nonce, a.authCookiesTTL)
a.cookieManager.SetStateCookie(w, state, a.authCookiesTTL)

redirect := a.oauth2.LoginRedirect(r.Context(), nonce, state)
http.Redirect(w, r, redirect, http.StatusFound)
Expand Down Expand Up @@ -200,15 +193,21 @@ func badRequest(w http.ResponseWriter, err error) {
return
}

func NewAPI(authCookiesTTLSeconds int, oauth2Context OAuth2ContextInterface, helper OAuth2HelperInterface, cookieManager AuthCookieManagerInterface, tracer trace.Tracer, logger logging.LoggerInterface) *API {
func NewAPI(
oauth2Context OAuth2ContextInterface,
helper OAuth2HelperInterface,
cookieManager AuthCookieManagerInterface,
tracer trace.Tracer,
logger logging.LoggerInterface,
) *API {
a := new(API)
a.apiKey = "authentication"
a.tracer = tracer
a.logger = logger
a.oauth2 = oauth2Context
a.helper = helper
a.authCookiesTTLSeconds = authCookiesTTLSeconds
a.cookieManager = cookieManager

a.logger = logger
a.tracer = tracer

return a
}
24 changes: 20 additions & 4 deletions pkg/web/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,12 +137,22 @@ func NewRouter(config *RouterConfig, wpool pool.WorkerPoolInterface) http.Handle
r.Use(authorizationMiddleware)
}).(*chi.Mux)

var oauth2Context *authentication.OAuth2Context
var oauth2Context authentication.OAuth2ContextInterface
var cookieManager authentication.AuthCookieManagerInterface

if oauth2Config.Enabled {
oauth2Context = authentication.NewOAuth2Context(config.oauth2, oidc.NewProvider, tracer, logger, monitor)
encrypt := authentication.NewEncrypt([]byte(oauth2Config.CookiesEncryptionKey), logger, tracer)
cookieManager = authentication.NewAuthCookieManager(
oauth2Config.AuthCookieTTLSeconds,
oauth2Config.IdTokenCookieTTLSeconds,
oauth2Config.AccessTokenCookieTTLSeconds,
oauth2Config.RefreshTokenCookieTTLSeconds,
encrypt,
logger,
)

authenticationMiddleware := authentication.NewAuthenticationMiddleware(oauth2Context, tracer, logger)
authenticationMiddleware := authentication.NewAuthenticationMiddleware(oauth2Context, cookieManager, tracer, logger)
authenticationMiddleware.SetAllowListedEndpoints(
"/api/v0/auth",
"/api/v0/auth/callback",
Expand Down Expand Up @@ -178,8 +188,14 @@ func NewRouter(config *RouterConfig, wpool pool.WorkerPoolInterface) http.Handle
groupsAPI.RegisterEndpoints(apiRouter)

if oauth2Config.Enabled {
encrypt := authentication.NewEncrypt([]byte(oauth2Config.CookiesEncryptionKey), logger, tracer)
login := authentication.NewAPI(oauth2Config.AuthCookieTTLSeconds, oauth2Context, authentication.NewOAuth2Helper(), authentication.NewAuthCookieManager(encrypt, logger), tracer, logger)

login := authentication.NewAPI(
oauth2Context,
authentication.NewOAuth2Helper(),
cookieManager,
tracer,
logger,
)
login.RegisterEndpoints(apiRouter)
}

Expand Down

0 comments on commit b4da23d

Please sign in to comment.