mirror of
https://github.com/harness/drone.git
synced 2025-05-02 13:40:22 +00:00
Merge branch 'eb/cookiename-configurable' of _OKE5H2PQKOUfzFFDuD4FA/default/CODE/gitness (#573)
This commit is contained in:
commit
138f47dd92
@ -79,6 +79,7 @@ ENV GITNESS_DATABASE_DRIVER sqlite3
|
||||
ENV GITNESS_DATABASE_DATASOURCE /data/database.sqlite
|
||||
ENV GITNESS_METRIC_ENABLED=true
|
||||
ENV GITNESS_METRIC_ENDPOINT=https://stats.drone.ci/api/v1/gitness
|
||||
ENV GITNESS_TOKEN_COOKIE_NAME=token
|
||||
|
||||
COPY --from=builder /app/gitness /app/gitness
|
||||
COPY --from=cert-image /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
|
@ -94,7 +94,7 @@ func initSystem(ctx context.Context, config *types.Config) (*server.System, erro
|
||||
controller := user.ProvideController(db, principalUID, authorizer, principalStore, tokenStore, membershipStore)
|
||||
serviceController := service.NewController(principalUID, authorizer, principalStore)
|
||||
bootstrapBootstrap := bootstrap.ProvideBootstrap(config, controller, serviceController)
|
||||
authenticator := authn.ProvideAuthenticator(principalStore, tokenStore)
|
||||
authenticator := authn.ProvideAuthenticator(config, principalStore, tokenStore)
|
||||
provider, err := url.ProvideURLProvider(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -9,12 +9,15 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/harness/gitness/internal/api/request"
|
||||
"github.com/harness/gitness/types"
|
||||
)
|
||||
|
||||
func includeTokenCookie(r *http.Request, w http.ResponseWriter, tokenResponse *types.TokenResponse) {
|
||||
cookie := newEmptyTokenCookie(r)
|
||||
func includeTokenCookie(
|
||||
r *http.Request, w http.ResponseWriter,
|
||||
tokenResponse *types.TokenResponse,
|
||||
cookieName string,
|
||||
) {
|
||||
cookie := newEmptyTokenCookie(r, cookieName)
|
||||
cookie.Value = tokenResponse.AccessToken
|
||||
if tokenResponse.Token.ExpiresAt != nil {
|
||||
cookie.Expires = time.UnixMilli(*tokenResponse.Token.ExpiresAt)
|
||||
@ -23,24 +26,24 @@ func includeTokenCookie(r *http.Request, w http.ResponseWriter, tokenResponse *t
|
||||
http.SetCookie(w, cookie)
|
||||
}
|
||||
|
||||
func deleteTokenCookieIfPresent(r *http.Request, w http.ResponseWriter) {
|
||||
func deleteTokenCookieIfPresent(r *http.Request, w http.ResponseWriter, cookieName string) {
|
||||
// if no token is present in the cookies, nothing todo.
|
||||
// No other error type expected here - and even if there is, let's try best effort deletion.
|
||||
_, err := r.Cookie(request.CookieToken)
|
||||
_, err := r.Cookie(cookieName)
|
||||
if errors.Is(err, http.ErrNoCookie) {
|
||||
return
|
||||
}
|
||||
|
||||
cookie := newEmptyTokenCookie(r)
|
||||
cookie := newEmptyTokenCookie(r, cookieName)
|
||||
cookie.Value = ""
|
||||
cookie.Expires = time.UnixMilli(0) // this effectively tells the browser to delete the cookie
|
||||
|
||||
http.SetCookie(w, cookie)
|
||||
}
|
||||
|
||||
func newEmptyTokenCookie(r *http.Request) *http.Cookie {
|
||||
func newEmptyTokenCookie(r *http.Request, cookieName string) *http.Cookie {
|
||||
return &http.Cookie{
|
||||
Name: request.CookieToken,
|
||||
Name: cookieName,
|
||||
SameSite: http.SameSiteStrictMode,
|
||||
HttpOnly: true,
|
||||
Path: "/",
|
||||
|
@ -15,19 +15,13 @@ import (
|
||||
|
||||
// HandleLogin returns an http.HandlerFunc that authenticates
|
||||
// the user and returns an authentication token on success.
|
||||
func HandleLogin(userCtrl *user.Controller) http.HandlerFunc {
|
||||
func HandleLogin(userCtrl *user.Controller, cookieName string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
|
||||
includeCookie, err := request.GetIncludeCookieFromQueryOrDefault(r, false)
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
in := new(user.LoginInput)
|
||||
err = json.NewDecoder(r.Body).Decode(in)
|
||||
err := json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequestf(w, "Invalid request body: %s.", err)
|
||||
return
|
||||
@ -39,8 +33,8 @@ func HandleLogin(userCtrl *user.Controller) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if includeCookie {
|
||||
includeTokenCookie(r, w, tokenResponse)
|
||||
if cookieName != "" {
|
||||
includeTokenCookie(r, w, tokenResponse, cookieName)
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusOK, tokenResponse)
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
|
||||
// HandleLogout returns a http.HandlerFunc that deletes the
|
||||
// user token being used in the respective request and logs the user out.
|
||||
func HandleLogout(userCtrl *user.Controller) http.HandlerFunc {
|
||||
func HandleLogout(userCtrl *user.Controller, cookieName string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
session, _ := request.AuthSessionFrom(ctx)
|
||||
@ -24,7 +24,7 @@ func HandleLogout(userCtrl *user.Controller) http.HandlerFunc {
|
||||
// best effort delete cookie even in case of errors, to avoid clients being unable to remove the cookie.
|
||||
// WARNING: It could be that the cookie is removed even though the token is still there in the DB.
|
||||
// However, we have APIs to list and delete session tokens, and expiry time is usually short.
|
||||
deleteTokenCookieIfPresent(r, w)
|
||||
deleteTokenCookieIfPresent(r, w, cookieName)
|
||||
|
||||
if err != nil {
|
||||
render.TranslatedUserError(w, err)
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
|
||||
// HandleRegister returns an http.HandlerFunc that processes an http.Request
|
||||
// to register the named user account with the system.
|
||||
func HandleRegister(userCtrl *user.Controller, sysCtrl *system.Controller) http.HandlerFunc {
|
||||
func HandleRegister(userCtrl *user.Controller, sysCtrl *system.Controller, cookieName string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
@ -40,7 +40,7 @@ func HandleRegister(userCtrl *user.Controller, sysCtrl *system.Controller) http.
|
||||
}
|
||||
|
||||
if includeCookie {
|
||||
includeTokenCookie(r, w, tokenResponse)
|
||||
includeTokenCookie(r, w, tokenResponse, cookieName)
|
||||
}
|
||||
|
||||
render.JSON(w, http.StatusOK, tokenResponse)
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
const (
|
||||
QueryParamAccessToken = "access_token"
|
||||
QueryParamIncludeCookie = "include_cookie"
|
||||
CookieToken = "token"
|
||||
)
|
||||
|
||||
func GetAccessTokenFromQuery(r *http.Request) (string, bool) {
|
||||
@ -22,6 +21,6 @@ func GetIncludeCookieFromQueryOrDefault(r *http.Request, dflt bool) (bool, error
|
||||
return QueryParamAsBoolOrDefault(r, QueryParamIncludeCookie, dflt)
|
||||
}
|
||||
|
||||
func GetTokenFromCookie(r *http.Request) (string, bool) {
|
||||
return GetCookie(r, CookieToken)
|
||||
func GetTokenFromCookie(r *http.Request, cookieName string) (string, bool) {
|
||||
return GetCookie(r, cookieName)
|
||||
}
|
||||
|
@ -24,14 +24,18 @@ var _ Authenticator = (*JWTAuthenticator)(nil)
|
||||
|
||||
// JWTAuthenticator uses the provided JWT to authenticate the caller.
|
||||
type JWTAuthenticator struct {
|
||||
cookieName string
|
||||
principalStore store.PrincipalStore
|
||||
tokenStore store.TokenStore
|
||||
}
|
||||
|
||||
func NewTokenAuthenticator(
|
||||
principalStore store.PrincipalStore,
|
||||
tokenStore store.TokenStore) *JWTAuthenticator {
|
||||
tokenStore store.TokenStore,
|
||||
cookieName string,
|
||||
) *JWTAuthenticator {
|
||||
return &JWTAuthenticator{
|
||||
cookieName: cookieName,
|
||||
principalStore: principalStore,
|
||||
tokenStore: tokenStore,
|
||||
}
|
||||
@ -39,7 +43,7 @@ func NewTokenAuthenticator(
|
||||
|
||||
func (a *JWTAuthenticator) Authenticate(r *http.Request, sourceRouter SourceRouter) (*auth.Session, error) {
|
||||
ctx := r.Context()
|
||||
str := extractToken(r)
|
||||
str := extractToken(r, a.cookieName)
|
||||
|
||||
if len(str) == 0 {
|
||||
return nil, ErrNoAuthData
|
||||
@ -122,7 +126,7 @@ func (a *JWTAuthenticator) metadataFromMembershipClaims(
|
||||
}, nil
|
||||
}
|
||||
|
||||
func extractToken(r *http.Request) string {
|
||||
func extractToken(r *http.Request, cookieName string) string {
|
||||
// Check query param first (as that's most immediately visible to caller)
|
||||
if queryToken, ok := request.GetAccessTokenFromQuery(r); ok {
|
||||
return queryToken
|
||||
@ -145,7 +149,7 @@ func extractToken(r *http.Request) string {
|
||||
}
|
||||
|
||||
// check cookies last (as that's least visible to caller)
|
||||
if cookieToken, ok := request.GetTokenFromCookie(r); ok {
|
||||
if cookieToken, ok := request.GetTokenFromCookie(r, cookieName); ok {
|
||||
return cookieToken
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ package authn
|
||||
|
||||
import (
|
||||
"github.com/harness/gitness/internal/store"
|
||||
"github.com/harness/gitness/types"
|
||||
|
||||
"github.com/google/wire"
|
||||
)
|
||||
@ -15,6 +16,6 @@ var WireSet = wire.NewSet(
|
||||
ProvideAuthenticator,
|
||||
)
|
||||
|
||||
func ProvideAuthenticator(principalStore store.PrincipalStore, tokenStore store.TokenStore) Authenticator {
|
||||
return NewTokenAuthenticator(principalStore, tokenStore)
|
||||
func ProvideAuthenticator(config *types.Config, principalStore store.PrincipalStore, tokenStore store.TokenStore) Authenticator {
|
||||
return NewTokenAuthenticator(principalStore, tokenStore, config.Token.CookieName)
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ func NewAPIHandler(
|
||||
r.Use(middlewareauthn.Attempt(authenticator, authn.SourceRouterAPI))
|
||||
|
||||
r.Route("/v1", func(r chi.Router) {
|
||||
setupRoutesV1(r, repoCtrl, executionCtrl, triggerCtrl, logCtrl, pipelineCtrl,
|
||||
setupRoutesV1(r, config, repoCtrl, executionCtrl, triggerCtrl, logCtrl, pipelineCtrl,
|
||||
connectorCtrl, templateCtrl, pluginCtrl, secretCtrl, spaceCtrl, pullreqCtrl,
|
||||
webhookCtrl, githookCtrl, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl)
|
||||
})
|
||||
@ -142,6 +142,7 @@ func corsHandler(config *types.Config) func(http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
func setupRoutesV1(r chi.Router,
|
||||
config *types.Config,
|
||||
repoCtrl *repo.Controller,
|
||||
executionCtrl *execution.Controller,
|
||||
triggerCtrl *trigger.Controller,
|
||||
@ -171,7 +172,7 @@ func setupRoutesV1(r chi.Router,
|
||||
setupPrincipals(r, principalCtrl)
|
||||
setupInternal(r, githookCtrl)
|
||||
setupAdmin(r, userCtrl)
|
||||
setupAccount(r, userCtrl, sysCtrl)
|
||||
setupAccount(r, userCtrl, sysCtrl, config)
|
||||
setupSystem(r, sysCtrl)
|
||||
setupResources(r)
|
||||
setupPlugins(r, pluginCtrl)
|
||||
@ -599,8 +600,9 @@ func setupAdmin(r chi.Router, userCtrl *user.Controller) {
|
||||
})
|
||||
}
|
||||
|
||||
func setupAccount(r chi.Router, userCtrl *user.Controller, sysCtrl *system.Controller) {
|
||||
r.Post("/login", account.HandleLogin(userCtrl))
|
||||
r.Post("/register", account.HandleRegister(userCtrl, sysCtrl))
|
||||
r.Post("/logout", account.HandleLogout(userCtrl))
|
||||
func setupAccount(r chi.Router, userCtrl *user.Controller, sysCtrl *system.Controller, config *types.Config) {
|
||||
cookieName := config.Token.CookieName
|
||||
r.Post("/login", account.HandleLogin(userCtrl, cookieName))
|
||||
r.Post("/register", account.HandleRegister(userCtrl, sysCtrl, cookieName))
|
||||
r.Post("/logout", account.HandleLogout(userCtrl, cookieName))
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ type Config struct {
|
||||
|
||||
// Token defines token configuration parameters.
|
||||
Token struct {
|
||||
CookieName string `envconfig:"GITNESS_TOKEN_COOKIE_NAME" default:"token"`
|
||||
Expire time.Duration `envconfig:"GITNESS_TOKEN_EXPIRE" default:"720h"`
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user