[AUTHZ] Move Blocking of Session Tokens for GIT to Middleware (#646)
This commit is contained in:
parent
d4e221f539
commit
9bede77cb9
|
@ -28,14 +28,14 @@ import (
|
|||
|
||||
// Attempt returns an http.HandlerFunc middleware that authenticates
|
||||
// the http.Request if authentication payload is available.
|
||||
func Attempt(authenticator authn.Authenticator, sourceRouter authn.SourceRouter) func(http.Handler) http.Handler {
|
||||
return performAuthentication(authenticator, false, sourceRouter)
|
||||
func Attempt(authenticator authn.Authenticator) func(http.Handler) http.Handler {
|
||||
return performAuthentication(authenticator, false)
|
||||
}
|
||||
|
||||
// Required returns an http.HandlerFunc middleware that authenticates
|
||||
// the http.Request and fails the request if no auth data was available.
|
||||
func Required(authenticator authn.Authenticator, sourceRouter authn.SourceRouter) func(http.Handler) http.Handler {
|
||||
return performAuthentication(authenticator, true, sourceRouter)
|
||||
func Required(authenticator authn.Authenticator) func(http.Handler) http.Handler {
|
||||
return performAuthentication(authenticator, true)
|
||||
}
|
||||
|
||||
// performAuthentication returns an http.HandlerFunc middleware that authenticates
|
||||
|
@ -43,14 +43,14 @@ func Required(authenticator authn.Authenticator, sourceRouter authn.SourceRouter
|
|||
// Depending on whether it is required or not, the request will be failed.
|
||||
func performAuthentication(
|
||||
authenticator authn.Authenticator,
|
||||
required bool, sourceRouter authn.SourceRouter,
|
||||
required bool,
|
||||
) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
log := hlog.FromRequest(r)
|
||||
|
||||
session, err := authenticator.Authenticate(r, sourceRouter)
|
||||
session, err := authenticator.Authenticate(r)
|
||||
if err != nil {
|
||||
if !errors.Is(err, authn.ErrNoAuthData) {
|
||||
// log error to help with investigating any auth related errors
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright 2023 Harness, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package authz
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/harness/gitness/app/api/render"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
"github.com/harness/gitness/app/auth"
|
||||
"github.com/harness/gitness/types/enum"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
// BlockSessionToken blocks any request that uses a session token for authentication.
|
||||
// NOTE: Major use case as of now is blocking usage of session tokens with git.
|
||||
func BlockSessionToken(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
// only block if auth data was available and it's based on a session token.
|
||||
if session, ok := request.AuthSessionFrom(ctx); ok {
|
||||
if tokenMetadata, ok := session.Metadata.(*auth.TokenMetadata); ok &&
|
||||
tokenMetadata.TokenType == enum.TokenTypeSession {
|
||||
log.Ctx(ctx).Warn().Msg("blocking git operation - session tokens are not allowed for usage with git")
|
||||
|
||||
// NOTE: Git doesn't print the error message, so just return default 401 Unauthorized.
|
||||
render.Unauthorized(w)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
|
@ -29,13 +29,6 @@ var (
|
|||
ErrNotAcceptedAuthMethod = errors.New("the request contains auth method that is not accepted by the Authorizer")
|
||||
)
|
||||
|
||||
type SourceRouter string
|
||||
|
||||
const (
|
||||
SourceRouterAPI SourceRouter = "api"
|
||||
SourceRouterGIT SourceRouter = "git"
|
||||
)
|
||||
|
||||
// Authenticator is an abstraction of an entity that's responsible for authenticating principals
|
||||
// that are making calls via HTTP.
|
||||
type Authenticator interface {
|
||||
|
@ -46,5 +39,5 @@ type Authenticator interface {
|
|||
* (nil, ErrNoAuthData) - request doesn't contain any auth data
|
||||
* (nil, err) - request contains auth data but verification failed
|
||||
*/
|
||||
Authenticate(r *http.Request, sourceRouter SourceRouter) (*auth.Session, error)
|
||||
Authenticate(r *http.Request) (*auth.Session, error)
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ func NewTokenAuthenticator(
|
|||
}
|
||||
}
|
||||
|
||||
func (a *JWTAuthenticator) Authenticate(r *http.Request, sourceRouter SourceRouter) (*auth.Session, error) {
|
||||
func (a *JWTAuthenticator) Authenticate(r *http.Request) (*auth.Session, error) {
|
||||
ctx := r.Context()
|
||||
str := extractToken(r, a.cookieName)
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ func NewAPIHandler(
|
|||
r.Use(corsHandler(config))
|
||||
|
||||
// for now always attempt auth - enforced per operation.
|
||||
r.Use(middlewareauthn.Attempt(authenticator, authn.SourceRouterAPI))
|
||||
r.Use(middlewareauthn.Attempt(authenticator))
|
||||
|
||||
r.Route("/v1", func(r chi.Router) {
|
||||
setupRoutesV1(r, config, repoCtrl, executionCtrl, triggerCtrl, logCtrl, pipelineCtrl,
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/harness/gitness/app/api/controller/repo"
|
||||
handlerrepo "github.com/harness/gitness/app/api/handler/repo"
|
||||
middlewareauthn "github.com/harness/gitness/app/api/middleware/authn"
|
||||
middlewareauthz "github.com/harness/gitness/app/api/middleware/authz"
|
||||
"github.com/harness/gitness/app/api/middleware/encode"
|
||||
"github.com/harness/gitness/app/api/middleware/logging"
|
||||
"github.com/harness/gitness/app/api/request"
|
||||
|
@ -64,26 +65,35 @@ func NewGitHandler(
|
|||
r.Use(logging.HLogRequestIDHandler())
|
||||
r.Use(logging.HLogAccessLogHandler())
|
||||
|
||||
// for now always attempt auth - enforced per operation.
|
||||
r.Use(middlewareauthn.Attempt(authenticator))
|
||||
|
||||
r.Route(fmt.Sprintf("/{%s}", request.PathParamRepoRef), func(r chi.Router) {
|
||||
r.Use(middlewareauthn.Attempt(authenticator, authn.SourceRouterGIT))
|
||||
// routes that aren't coming from git
|
||||
r.Group(func(r chi.Router) {
|
||||
// redirect to repo (meant for UI, in case user navigates to clone url in browser)
|
||||
r.Get("/", handlerrepo.HandleGitRedirect(repoCtrl, urlProvider))
|
||||
})
|
||||
|
||||
// redirect to repo (meant for UI, in case user navigates to clone url in browser)
|
||||
r.Get("/", handlerrepo.HandleGitRedirect(repoCtrl, urlProvider))
|
||||
// routes that are coming from git (where we block the usage of session tokens)
|
||||
r.Group(func(r chi.Router) {
|
||||
r.Use(middlewareauthz.BlockSessionToken)
|
||||
|
||||
// smart protocol
|
||||
r.Handle("/git-upload-pack", handlerrepo.GetUploadPack(client, urlProvider, repoStore, authorizer))
|
||||
r.Post("/git-receive-pack", handlerrepo.PostReceivePack(client, urlProvider, repoStore, authorizer))
|
||||
r.Get("/info/refs", handlerrepo.GetInfoRefs(client, repoStore, authorizer))
|
||||
// smart protocol
|
||||
r.Handle("/git-upload-pack", handlerrepo.GetUploadPack(client, urlProvider, repoStore, authorizer))
|
||||
r.Post("/git-receive-pack", handlerrepo.PostReceivePack(client, urlProvider, repoStore, authorizer))
|
||||
r.Get("/info/refs", handlerrepo.GetInfoRefs(client, repoStore, authorizer))
|
||||
|
||||
// dumb protocol
|
||||
r.Get("/HEAD", stubGitHandler(repoStore))
|
||||
r.Get("/objects/info/alternates", stubGitHandler(repoStore))
|
||||
r.Get("/objects/info/http-alternates", stubGitHandler(repoStore))
|
||||
r.Get("/objects/info/packs", stubGitHandler(repoStore))
|
||||
r.Get("/objects/info/{file:[^/]*}", stubGitHandler(repoStore))
|
||||
r.Get("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", stubGitHandler(repoStore))
|
||||
r.Get("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", stubGitHandler(repoStore))
|
||||
r.Get("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", stubGitHandler(repoStore))
|
||||
// dumb protocol
|
||||
r.Get("/HEAD", stubGitHandler(repoStore))
|
||||
r.Get("/objects/info/alternates", stubGitHandler(repoStore))
|
||||
r.Get("/objects/info/http-alternates", stubGitHandler(repoStore))
|
||||
r.Get("/objects/info/packs", stubGitHandler(repoStore))
|
||||
r.Get("/objects/info/{file:[^/]*}", stubGitHandler(repoStore))
|
||||
r.Get("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", stubGitHandler(repoStore))
|
||||
r.Get("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", stubGitHandler(repoStore))
|
||||
r.Get("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", stubGitHandler(repoStore))
|
||||
})
|
||||
})
|
||||
|
||||
// wrap router in git path encoder.
|
||||
|
|
Loading…
Reference in New Issue