drone/internal/api/guard/guard.space.go
Johannes Batzill 8c2f900c80 Principals, ServiceAccounts, Tokens and auth.Sessions (#15)
This change introduces the concept of a principal (abstraction of call identity), and adds a new service account type principal. Also adds support for different tokens (session, PAT, SAT, OAuth2) and adds auth.Session which is being used to capture information about the caller and call method.
2022-09-25 23:44:51 -07:00

106 lines
3.3 KiB
Go

// Copyright 2021 Harness Inc. All rights reserved.
// Use of this source code is governed by the Polyform Free Trial License
// that can be found in the LICENSE.md file for this repository.
package guard
import (
"net/http"
"github.com/harness/gitness/internal/api/render"
"github.com/harness/gitness/internal/api/request"
"github.com/harness/gitness/internal/paths"
"github.com/harness/gitness/types"
"github.com/harness/gitness/types/enum"
"github.com/pkg/errors"
"github.com/rs/zerolog/hlog"
"github.com/rs/zerolog/log"
)
/*
* Returns a middleware that guards space related handlers from being executed.
* Only principals that are authorized are able to execute the handler, everyone else is forbidden,
* unless orPublic is configured and the space is public.
*
* Assumes the space is already available in the request context.
*/
func (g *Guard) ForSpace(requiredPermission enum.Permission, orPublic bool) func(http.Handler) http.Handler {
return func(h http.Handler) http.Handler {
return g.Space(requiredPermission, orPublic, h.ServeHTTP)
}
}
/*
* Returns an http.HandlerFunc that guards a space related http.HandlerFunc from being executed.
* Only principals that are authorized are able to execute the handler, everyone else is forbidden,
* unless orPublic is configured and the space is public.
*
* Assumes the space is already available in the request context.
*/
func (g *Guard) Space(permission enum.Permission, orPublic bool, guarded http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
s, ok := request.SpaceFrom(ctx)
if !ok {
// log error for debugging
hlog.FromRequest(r).Error().Msg("Method expects the space to be availabe in the request context, but it wasnt.")
render.InternalError(w)
return
}
// Enforce permission (renders error)
if !(orPublic && s.IsPublic) && !g.EnforceSpace(w, r, permission, s.Path) {
return
}
// executed guarded function
guarded(w, r)
}
}
/*
* Enforces that the executing principal has requested permission on the space.
* Returns true if that is the case, otherwise renders the appropriate error and returns false.
*/
func (g *Guard) EnforceSpace(w http.ResponseWriter, r *http.Request,
permission enum.Permission, spacePath string) bool {
parentSpace, name, err := paths.Disect(spacePath)
if err != nil {
// log error for debugging
hlog.FromRequest(r)
log.Err(err).Msgf("Failed to disect path '%s'.", spacePath)
render.InternalError(w)
return false
}
scope := &types.Scope{SpacePath: parentSpace}
resource := &types.Resource{
Type: enum.ResourceTypeSpace,
Name: name,
}
return g.Enforce(w, r, scope, resource, permission)
}
/*
* Checks whether the principal executing the request has the requested permission on the space.
* Returns nil if the principal is confirmed to be permitted to execute the action, otherwise returns errors
* NotAuthenticated, NotAuthorized, or any unerlaying error.
*/
func (g *Guard) CheckSpace(r *http.Request, permission enum.Permission, spacePath string) error {
parentSpace, name, err := paths.Disect(spacePath)
if err != nil {
return errors.Wrapf(err, "Failed to disect path '%s'", spacePath)
}
scope := &types.Scope{SpacePath: parentSpace}
resource := &types.Resource{
Type: enum.ResourceTypeSpace,
Name: name,
}
return g.Check(r, scope, resource, permission)
}