mirror of
https://github.com/harness/drone.git
synced 2025-05-04 22:50:23 +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_DATABASE_DATASOURCE /data/database.sqlite
|
||||||
ENV GITNESS_METRIC_ENABLED=true
|
ENV GITNESS_METRIC_ENABLED=true
|
||||||
ENV GITNESS_METRIC_ENDPOINT=https://stats.drone.ci/api/v1/gitness
|
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=builder /app/gitness /app/gitness
|
||||||
COPY --from=cert-image /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
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)
|
controller := user.ProvideController(db, principalUID, authorizer, principalStore, tokenStore, membershipStore)
|
||||||
serviceController := service.NewController(principalUID, authorizer, principalStore)
|
serviceController := service.NewController(principalUID, authorizer, principalStore)
|
||||||
bootstrapBootstrap := bootstrap.ProvideBootstrap(config, controller, serviceController)
|
bootstrapBootstrap := bootstrap.ProvideBootstrap(config, controller, serviceController)
|
||||||
authenticator := authn.ProvideAuthenticator(principalStore, tokenStore)
|
authenticator := authn.ProvideAuthenticator(config, principalStore, tokenStore)
|
||||||
provider, err := url.ProvideURLProvider(config)
|
provider, err := url.ProvideURLProvider(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -9,12 +9,15 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/harness/gitness/internal/api/request"
|
|
||||||
"github.com/harness/gitness/types"
|
"github.com/harness/gitness/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func includeTokenCookie(r *http.Request, w http.ResponseWriter, tokenResponse *types.TokenResponse) {
|
func includeTokenCookie(
|
||||||
cookie := newEmptyTokenCookie(r)
|
r *http.Request, w http.ResponseWriter,
|
||||||
|
tokenResponse *types.TokenResponse,
|
||||||
|
cookieName string,
|
||||||
|
) {
|
||||||
|
cookie := newEmptyTokenCookie(r, cookieName)
|
||||||
cookie.Value = tokenResponse.AccessToken
|
cookie.Value = tokenResponse.AccessToken
|
||||||
if tokenResponse.Token.ExpiresAt != nil {
|
if tokenResponse.Token.ExpiresAt != nil {
|
||||||
cookie.Expires = time.UnixMilli(*tokenResponse.Token.ExpiresAt)
|
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)
|
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.
|
// 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.
|
// 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) {
|
if errors.Is(err, http.ErrNoCookie) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie := newEmptyTokenCookie(r)
|
cookie := newEmptyTokenCookie(r, cookieName)
|
||||||
cookie.Value = ""
|
cookie.Value = ""
|
||||||
cookie.Expires = time.UnixMilli(0) // this effectively tells the browser to delete the cookie
|
cookie.Expires = time.UnixMilli(0) // this effectively tells the browser to delete the cookie
|
||||||
|
|
||||||
http.SetCookie(w, cookie)
|
http.SetCookie(w, cookie)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEmptyTokenCookie(r *http.Request) *http.Cookie {
|
func newEmptyTokenCookie(r *http.Request, cookieName string) *http.Cookie {
|
||||||
return &http.Cookie{
|
return &http.Cookie{
|
||||||
Name: request.CookieToken,
|
Name: cookieName,
|
||||||
SameSite: http.SameSiteStrictMode,
|
SameSite: http.SameSiteStrictMode,
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
|
@ -15,19 +15,13 @@ import (
|
|||||||
|
|
||||||
// HandleLogin returns an http.HandlerFunc that authenticates
|
// HandleLogin returns an http.HandlerFunc that authenticates
|
||||||
// the user and returns an authentication token on success.
|
// 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) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
session, _ := request.AuthSessionFrom(ctx)
|
session, _ := request.AuthSessionFrom(ctx)
|
||||||
|
|
||||||
includeCookie, err := request.GetIncludeCookieFromQueryOrDefault(r, false)
|
|
||||||
if err != nil {
|
|
||||||
render.TranslatedUserError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
in := new(user.LoginInput)
|
in := new(user.LoginInput)
|
||||||
err = json.NewDecoder(r.Body).Decode(in)
|
err := json.NewDecoder(r.Body).Decode(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
render.BadRequestf(w, "Invalid request body: %s.", err)
|
render.BadRequestf(w, "Invalid request body: %s.", err)
|
||||||
return
|
return
|
||||||
@ -39,8 +33,8 @@ func HandleLogin(userCtrl *user.Controller) http.HandlerFunc {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if includeCookie {
|
if cookieName != "" {
|
||||||
includeTokenCookie(r, w, tokenResponse)
|
includeTokenCookie(r, w, tokenResponse, cookieName)
|
||||||
}
|
}
|
||||||
|
|
||||||
render.JSON(w, http.StatusOK, tokenResponse)
|
render.JSON(w, http.StatusOK, tokenResponse)
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
// HandleLogout returns a http.HandlerFunc that deletes the
|
// HandleLogout returns a http.HandlerFunc that deletes the
|
||||||
// user token being used in the respective request and logs the user out.
|
// 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) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
session, _ := request.AuthSessionFrom(ctx)
|
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.
|
// 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.
|
// 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.
|
// 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 {
|
if err != nil {
|
||||||
render.TranslatedUserError(w, err)
|
render.TranslatedUserError(w, err)
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
|
|
||||||
// HandleRegister returns an http.HandlerFunc that processes an http.Request
|
// HandleRegister returns an http.HandlerFunc that processes an http.Request
|
||||||
// to register the named user account with the system.
|
// 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) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ func HandleRegister(userCtrl *user.Controller, sysCtrl *system.Controller) http.
|
|||||||
}
|
}
|
||||||
|
|
||||||
if includeCookie {
|
if includeCookie {
|
||||||
includeTokenCookie(r, w, tokenResponse)
|
includeTokenCookie(r, w, tokenResponse, cookieName)
|
||||||
}
|
}
|
||||||
|
|
||||||
render.JSON(w, http.StatusOK, tokenResponse)
|
render.JSON(w, http.StatusOK, tokenResponse)
|
||||||
|
@ -11,7 +11,6 @@ import (
|
|||||||
const (
|
const (
|
||||||
QueryParamAccessToken = "access_token"
|
QueryParamAccessToken = "access_token"
|
||||||
QueryParamIncludeCookie = "include_cookie"
|
QueryParamIncludeCookie = "include_cookie"
|
||||||
CookieToken = "token"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetAccessTokenFromQuery(r *http.Request) (string, bool) {
|
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)
|
return QueryParamAsBoolOrDefault(r, QueryParamIncludeCookie, dflt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetTokenFromCookie(r *http.Request) (string, bool) {
|
func GetTokenFromCookie(r *http.Request, cookieName string) (string, bool) {
|
||||||
return GetCookie(r, CookieToken)
|
return GetCookie(r, cookieName)
|
||||||
}
|
}
|
||||||
|
@ -24,14 +24,18 @@ var _ Authenticator = (*JWTAuthenticator)(nil)
|
|||||||
|
|
||||||
// JWTAuthenticator uses the provided JWT to authenticate the caller.
|
// JWTAuthenticator uses the provided JWT to authenticate the caller.
|
||||||
type JWTAuthenticator struct {
|
type JWTAuthenticator struct {
|
||||||
|
cookieName string
|
||||||
principalStore store.PrincipalStore
|
principalStore store.PrincipalStore
|
||||||
tokenStore store.TokenStore
|
tokenStore store.TokenStore
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTokenAuthenticator(
|
func NewTokenAuthenticator(
|
||||||
principalStore store.PrincipalStore,
|
principalStore store.PrincipalStore,
|
||||||
tokenStore store.TokenStore) *JWTAuthenticator {
|
tokenStore store.TokenStore,
|
||||||
|
cookieName string,
|
||||||
|
) *JWTAuthenticator {
|
||||||
return &JWTAuthenticator{
|
return &JWTAuthenticator{
|
||||||
|
cookieName: cookieName,
|
||||||
principalStore: principalStore,
|
principalStore: principalStore,
|
||||||
tokenStore: tokenStore,
|
tokenStore: tokenStore,
|
||||||
}
|
}
|
||||||
@ -39,7 +43,7 @@ func NewTokenAuthenticator(
|
|||||||
|
|
||||||
func (a *JWTAuthenticator) Authenticate(r *http.Request, sourceRouter SourceRouter) (*auth.Session, error) {
|
func (a *JWTAuthenticator) Authenticate(r *http.Request, sourceRouter SourceRouter) (*auth.Session, error) {
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
str := extractToken(r)
|
str := extractToken(r, a.cookieName)
|
||||||
|
|
||||||
if len(str) == 0 {
|
if len(str) == 0 {
|
||||||
return nil, ErrNoAuthData
|
return nil, ErrNoAuthData
|
||||||
@ -122,7 +126,7 @@ func (a *JWTAuthenticator) metadataFromMembershipClaims(
|
|||||||
}, nil
|
}, 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)
|
// Check query param first (as that's most immediately visible to caller)
|
||||||
if queryToken, ok := request.GetAccessTokenFromQuery(r); ok {
|
if queryToken, ok := request.GetAccessTokenFromQuery(r); ok {
|
||||||
return queryToken
|
return queryToken
|
||||||
@ -145,7 +149,7 @@ func extractToken(r *http.Request) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check cookies last (as that's least visible to caller)
|
// 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
|
return cookieToken
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ package authn
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/harness/gitness/internal/store"
|
"github.com/harness/gitness/internal/store"
|
||||||
|
"github.com/harness/gitness/types"
|
||||||
|
|
||||||
"github.com/google/wire"
|
"github.com/google/wire"
|
||||||
)
|
)
|
||||||
@ -15,6 +16,6 @@ var WireSet = wire.NewSet(
|
|||||||
ProvideAuthenticator,
|
ProvideAuthenticator,
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProvideAuthenticator(principalStore store.PrincipalStore, tokenStore store.TokenStore) Authenticator {
|
func ProvideAuthenticator(config *types.Config, principalStore store.PrincipalStore, tokenStore store.TokenStore) Authenticator {
|
||||||
return NewTokenAuthenticator(principalStore, tokenStore)
|
return NewTokenAuthenticator(principalStore, tokenStore, config.Token.CookieName)
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ func NewAPIHandler(
|
|||||||
r.Use(middlewareauthn.Attempt(authenticator, authn.SourceRouterAPI))
|
r.Use(middlewareauthn.Attempt(authenticator, authn.SourceRouterAPI))
|
||||||
|
|
||||||
r.Route("/v1", func(r chi.Router) {
|
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,
|
connectorCtrl, templateCtrl, pluginCtrl, secretCtrl, spaceCtrl, pullreqCtrl,
|
||||||
webhookCtrl, githookCtrl, saCtrl, userCtrl, principalCtrl, checkCtrl, sysCtrl)
|
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,
|
func setupRoutesV1(r chi.Router,
|
||||||
|
config *types.Config,
|
||||||
repoCtrl *repo.Controller,
|
repoCtrl *repo.Controller,
|
||||||
executionCtrl *execution.Controller,
|
executionCtrl *execution.Controller,
|
||||||
triggerCtrl *trigger.Controller,
|
triggerCtrl *trigger.Controller,
|
||||||
@ -171,7 +172,7 @@ func setupRoutesV1(r chi.Router,
|
|||||||
setupPrincipals(r, principalCtrl)
|
setupPrincipals(r, principalCtrl)
|
||||||
setupInternal(r, githookCtrl)
|
setupInternal(r, githookCtrl)
|
||||||
setupAdmin(r, userCtrl)
|
setupAdmin(r, userCtrl)
|
||||||
setupAccount(r, userCtrl, sysCtrl)
|
setupAccount(r, userCtrl, sysCtrl, config)
|
||||||
setupSystem(r, sysCtrl)
|
setupSystem(r, sysCtrl)
|
||||||
setupResources(r)
|
setupResources(r)
|
||||||
setupPlugins(r, pluginCtrl)
|
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) {
|
func setupAccount(r chi.Router, userCtrl *user.Controller, sysCtrl *system.Controller, config *types.Config) {
|
||||||
r.Post("/login", account.HandleLogin(userCtrl))
|
cookieName := config.Token.CookieName
|
||||||
r.Post("/register", account.HandleRegister(userCtrl, sysCtrl))
|
r.Post("/login", account.HandleLogin(userCtrl, cookieName))
|
||||||
r.Post("/logout", account.HandleLogout(userCtrl))
|
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 defines token configuration parameters.
|
||||||
Token struct {
|
Token struct {
|
||||||
|
CookieName string `envconfig:"GITNESS_TOKEN_COOKIE_NAME" default:"token"`
|
||||||
Expire time.Duration `envconfig:"GITNESS_TOKEN_EXPIRE" default:"720h"`
|
Expire time.Duration `envconfig:"GITNESS_TOKEN_EXPIRE" default:"720h"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user