Documentation ¶
Index ¶
- Constants
- Variables
- func AuthMetrics(registry prometheus.Registerer) gin.HandlerFunc
- func AuthenticatedSessionRequired(autoAuth bool, next gin.HandlerFunc) gin.HandlerFunc
- func Cache(client redis.Cmdable, registry prometheus.Registerer) gin.HandlerFunc
- func ClearAuthToken(ctx *gin.Context) error
- func Config(c *ConfigOptions) gin.HandlerFunc
- func ErrorLogger() gin.HandlerFunc
- func GetAuthConfig(ctx *gin.Context) *oauth2.Config
- func GetAuthToken(ctx *gin.Context) *oauth2.Token
- func GetNamespace(ctx *gin.Context) string
- func GetTopLevelGroupID(ctx *gin.Context) int
- func GetTopLevelNamespaceFromGroup(ginCtx *gin.Context, groupID int) int
- func GetTopLevelNamespaceFromProject(ginCtx *gin.Context, projectID int) int
- func GroupAuthHandlerFactory() gin.HandlerFunc
- func HandleAuthFinish(ctx *gin.Context)
- func HandleAuthStart(ctx *gin.Context)
- func HandleError(ctx *gin.Context, err error)
- func HandleGLAccessTokenAuth(ctx *gin.Context, bearerToken string, requiredScopes []string)
- func HandleGroupAccessAuth(ginCtx *gin.Context, namespaceID, minAccessLevel int)
- func HandleNamespaceProvisioning(ctx *gin.Context)
- func HandlePath(ctx *gin.Context)
- func HandleProjectAccessAuth(ginCtx *gin.Context, projectID, minAccessLevelKey int)
- func HandleTokenAuth(ctx *gin.Context)
- func ListGroupProjectsHandler(ctx *gin.Context)
- func OAuth2(o *AuthOptions) gin.HandlerFunc
- func ProjectAuthHandlerFactory(namespacedPath bool) gin.HandlerFunc
- func RateLimitingHandler() gin.HandlerFunc
- func ReadAccessTokenScopes() []string
- func ReadWriteAccessTokenScopes() []string
- func Session(client redis.Cmdable, o *SessionOptions) []gin.HandlerFunc
- func SetAuthConfig(ctx *gin.Context, cfg *oauth2.Config)
- func SetAuthToken(ctx *gin.Context, token *oauth2.Token) error
- func SetGitLabService(ctx *gin.Context, us *GitLabService)
- func SetRateLimiter(rl RateLimiter) gin.HandlerFunc
- func SetRoutes(router *gin.Engine, debugMode bool)
- func VerifyProjectGroupMembership(ginCtx *gin.Context, namespaceID, projectID int)
- func WriteAccessTokenScopes() []string
- type AuthMetricsData
- type AuthOptions
- type CacheAdapter
- type CacheMetricsWrapper
- type CacheOptions
- type ConfigOptions
- type CustomErrorsParams
- type EmptyValue
- type ErrorTrackingAuthHandler
- type GitLabGroup
- type GitLabNamespace
- type GitLabService
- func (s *GitLabService) CanAccessNamespace(nid string) (bool, gitlab.AccessLevelValue, error)
- func (s *GitLabService) CanAccessProject(pid, minAccessLevelKey int) (bool, error)
- func (s *GitLabService) CurrentUser() (*gitlab.User, error)
- func (s *GitLabService) GetAccessTokenScopes() ([]string, error)
- func (s *GitLabService) GetGroup(gid string) (*GitLabGroup, error)
- func (s *GitLabService) GetGroupProjects(gid interface{}) ([]*gitlab.BasicProject, error)
- func (s *GitLabService) GetInheritedGroupMember(gid int, user int) (*gitlab.GroupMember, error)
- func (s *GitLabService) GetInheritedProjectMember(pid, user int) (*gitlab.ProjectMember, error)
- func (s *GitLabService) GetNamespace(nid string) (*GitLabNamespace, error)
- func (s *GitLabService) GetProject(pid interface{}) (*gitlab.Project, error)
- func (s *GitLabService) GetTopLevelGroups() ([]*GitLabGroup, error)
- func (s *GitLabService) HandleError(err error) error
- func (s *GitLabService) IsProjectInGroup(pid, gid int) (bool, error)
- func (s *GitLabService) IsProjectInUserNamespace(pid, nsid int) (bool, error)
- func (s *GitLabService) ListProjectsGroups(pid interface{}) ([]*gitlab.ProjectGroup, error)
- func (s *GitLabService) Token() (*oauth2.Token, error)
- type GroupAuthHandlerFormParams
- type GroupAuthHandlerPathParams
- type GroupParams
- type IngestAuthHeader
- type LimitIDRateLimitHandlerFormParams
- type NamespaceParams
- type NamespacePathParam
- type NamespaceWatcher
- type PathFormParams
- type ProjectAuthHandlerFormParams
- type ProjectAuthHandlerPathParams
- type Projects
- type RateLimiter
- type RateLimiterBackend
- type RedisCache
- type RoutingParams
- type SessionOptions
Constants ¶
const ( UserNamespaceType = "user" GroupNamespaceType = "group" )
const ( IDTypeProject = "project" IDTypeGroup = "organization" EndpointTypeETWrite = "et_write" EndpointTypeETRead = "et_read" EndpointTypeTRWrite = "tr_write" )
const (
CacheClientKey = "gatekeeper/redisCache"
)
Variables ¶
Functions ¶
func AuthMetrics ¶
func AuthMetrics(registry prometheus.Registerer) gin.HandlerFunc
func AuthenticatedSessionRequired ¶
func AuthenticatedSessionRequired(autoAuth bool, next gin.HandlerFunc) gin.HandlerFunc
Ensures request is authenticated. If autoAuth=true, will redirect client through the auth flow and then return back to this route. If autoAuth=false, will return an unauthorized response to client.
func Cache ¶
func Cache(client redis.Cmdable, registry prometheus.Registerer) gin.HandlerFunc
Middleware to set the database clients on the context for downstream handlers.
func ClearAuthToken ¶
Helper to clear the authToken in the session.
func Config ¶
func Config(c *ConfigOptions) gin.HandlerFunc
Middleware to set the config options on the context for downstream handlers.
func ErrorLogger ¶
func ErrorLogger() gin.HandlerFunc
ErrorLogger middleware to log errors created with gin context. e.g. c.Error(err) or c.AbortWithError(500, err).
func GetAuthConfig ¶
Helper to get the oauth2 client config from the context.
func GetAuthToken ¶
Helper to get the authToken from the session.
func GetNamespace ¶
Helper to get the target namespaceID from the ctx.
func GetTopLevelGroupID ¶
func GroupAuthHandlerFactory ¶
func GroupAuthHandlerFactory() gin.HandlerFunc
GroupAuthHandlerFactory returns an auth handler that will handle several cases of authn/authz for Group/Namespace membership.
func HandleAuthFinish ¶
HandleAuthFinish handles the callback from GitLab during oauth2.
If user already has an active session, this handler will update it with the new auth token (in the case where the user changed identity in the GitLab instance). @Id AuthFinish @Summary Finish the OAuth2 Flow setting session on success @Router /v1/auth/callback [get] @Produce html @Success 200 "Complete auth flow" @Param code query string true "Authorization code" @Param state query string true "State parameter" @Failure 400 "Required parameters missing or state parameter does not match flow start state" @Failure 401 "Invalid authorization code or failure to exchange for access token"
func HandleAuthStart ¶
HandleAuthStart Initiates the oauth2 authentication with GitLab. @Id AuthStart @Summary Start the OAuth2 Flow @Router /v1/auth/start [get] @Produce html @Success 200 "Valid auth token already exists in the session" @Success 302 "OAuth2 redirect to GitLab with auth coded URL"
func HandleError ¶
Returns a 401 if the error is due to an authorization issue, or aborts with the error and a generic message back to the user.
func HandleGLAccessTokenAuth ¶
func HandleGroupAccessAuth ¶
func HandleNamespaceProvisioning ¶
Handles incoming requests for a Gitlab namespace for namespaces that do not yet exist in Opstrace. If the request lands here, we need to provision the namespace in Opstrace. This is a lazy provisioner that only provisions namespaces when the first request comes in for that namespace. Request must have Owner permissions on the respective GitLab namespace to proceed.
See the namespace API docs in gitlab https://docs.gitlab.com/ee/api/namespaces.html
@Id NamespaceProvisioning @Summary Handles provisioning of new namespaces. @Router /v1/provision/{namespace_id}/{action} [get] @Param namespace_id path string true "Namespace ID" @Param action path string false "Action URL part" @Success 302 "Redirect to provisioned UI" @Failure 401 "Unauthorized" @Failure 404 "Namespace not found" @Deprecated
func HandlePath ¶
HandlePath catches any gitlab namespace and redirects to UI if already provisioned, or returns HTML with button to provision. @Id HandleNamespacePath @Summary Handles wildcard paths to namespace related components. @Router /-/{namespace_id}/{action} [get] @Param namespace_id path string true "Namespace ID" @Param action path string false "Action URL part" @Deprecated
func HandleProjectAccessAuth ¶
Handles the token-based external auth request from ingress, both oauth-based session as well as Gitlab Access Token.
func HandleTokenAuth ¶
Handles the token-based external auth request from ingress, both oauth-based session as well as Gitlab Access Token.
func ListGroupProjectsHandler ¶
ListGroupProjectsHandler lists all projects in a group. @Id ListGroupProjectsHandler @Summary Lists all projects in a group, used internally. @Router /v1/{group_id}/projects [get] @Param group_id path string true "Group ID" @Success 200 {array} Projects "GitLab projects" @Provides json @Deprecated
func OAuth2 ¶
func OAuth2(o *AuthOptions) gin.HandlerFunc
Make the oauth2 config available on the request context. Handlers can then invoke the the oauth flow and use the authenticated http.client for interacting with the gitlab API that is available on the oauth2.Config object.
func ProjectAuthHandlerFactory ¶
func ProjectAuthHandlerFactory(namespacedPath bool) gin.HandlerFunc
ProjectAuthHandlerFactory returns an auth handler that will handle several cases of auth for project membership.
func RateLimitingHandler ¶
func RateLimitingHandler() gin.HandlerFunc
handleRateLimiting checks if the request that belongs to given `limitID` group is permitted/below the quota limits for given topLevelGroupID. The return value signifies whether the request was rate limited or not, in case e.g. extra headers need to be added.
func ReadAccessTokenScopes ¶
func ReadAccessTokenScopes() []string
ReadAccessTokenScopes returns scope sets. Token needs to have one or more of them in order for request to be granted.
func ReadWriteAccessTokenScopes ¶
func ReadWriteAccessTokenScopes() []string
func Session ¶
func Session(client redis.Cmdable, o *SessionOptions) []gin.HandlerFunc
Session middleware that stores session state in redis.
func SetAuthConfig ¶
Helper to set the oauth2 client config on the context.
func SetAuthToken ¶
Helper to set the authToken in the session.
func SetGitLabService ¶
func SetGitLabService(ctx *gin.Context, us *GitLabService)
Helper to set the gitLabService on the context.
func SetRateLimiter ¶
func SetRateLimiter(rl RateLimiter) gin.HandlerFunc
Middleware to set the ratelimiter in the Gin's context for downstream handlers..
func WriteAccessTokenScopes ¶
func WriteAccessTokenScopes() []string
Types ¶
type AuthMetricsData ¶
type AuthMetricsData struct { LoginStarts prometheus.Counter LoginSuccesses prometheus.Counter LoginFailures prometheus.Counter }
func GetAuthMetrics ¶
func GetAuthMetrics(ctx *gin.Context) *AuthMetricsData
Helper to get the metrics from the context.
type AuthOptions ¶
type CacheAdapter ¶
type CacheAdapter struct {
// contains filtered or unexported fields
}
func NewCacheAdapter ¶
func NewCacheAdapter(size int, ttl time.Duration, evictionCallback func(bool)) *CacheAdapter
func (*CacheAdapter) Del ¶
func (ca *CacheAdapter) Del(key string)
func (*CacheAdapter) Set ¶
func (ca *CacheAdapter) Set(key string, data []byte)
type CacheMetricsWrapper ¶
type CacheMetricsWrapper struct {
// contains filtered or unexported fields
}
func NewCacheMetricsWrapper ¶
func NewCacheMetricsWrapper(registry prometheus.Registerer) *CacheMetricsWrapper
func (*CacheMetricsWrapper) EvictionCallback ¶
func (cwm *CacheMetricsWrapper) EvictionCallback(isObjectAdd bool)
func (*CacheMetricsWrapper) Get ¶
func (cwm *CacheMetricsWrapper) Get( ctx context.Context, key string, value interface{}, ) error
func (*CacheMetricsWrapper) SetCacheObject ¶
func (cwm *CacheMetricsWrapper) SetCacheObject(c *cache.Cache)
type CacheOptions ¶
type CacheOptions struct { RedisAddr string RedisPassword string ConnectionPoolSize int Registry prometheus.Registerer }
type ConfigOptions ¶
type ConfigOptions struct { Port string UseSecureCookie bool CookieName string CookieSecret string OauthClientID string OauthClientSecret string ServerDomain string GitlabAddr string GitlabInternalEndpointAddr string GitlabInternalEndpointToken string K8sClient client.Client Namespace string }
func GetConfig ¶
func GetConfig(ctx *gin.Context) *ConfigOptions
Helper to get the server config from the context.
type CustomErrorsParams ¶
type CustomErrorsParams struct { Code int `json:"code" form:"code" binding:"required,numeric,min=400,max=599"` OriginalURI string `json:"uri" form:"uri" binding:"required"` }
CustomErrorsParams defines the parameters for the custom errors handler
type EmptyValue ¶
type EmptyValue struct{}
type ErrorTrackingAuthHandler ¶
func NewErrorTrackingAuthHandler ¶
func NewErrorTrackingAuthHandler() ErrorTrackingAuthHandler
type GitLabGroup ¶
func (*GitLabGroup) Equals ¶
func (n *GitLabGroup) Equals(other *GitLabGroup) bool
GetTopLevel returns top-level parent namespace for this child namespace.
func (*GitLabGroup) GetTopLevelNamespaceID ¶
func (n *GitLabGroup) GetTopLevelNamespaceID() string
GetTopLevel returns top-level parent namespace for this child namespace.
func (*GitLabGroup) IsTopLevel ¶
func (n *GitLabGroup) IsTopLevel() bool
IsTopLevel returns true if this namespace is a top-level namespace. Returns false if this is a child namespace.
type GitLabNamespace ¶
func (*GitLabNamespace) Equals ¶
func (n *GitLabNamespace) Equals(other *GitLabNamespace) bool
GetTopLevel returns top-level parent namespace for this child namespace.
func (*GitLabNamespace) GetTopLevelNamespaceID ¶
func (n *GitLabNamespace) GetTopLevelNamespaceID() string
GetTopLevel returns top-level parent namespace for this child namespace.
func (*GitLabNamespace) IsTopLevel ¶
func (n *GitLabNamespace) IsTopLevel() bool
IsTopLevel returns true if this namespace is a top-level namespace. Returns false if this is a child namespace.
type GitLabService ¶
type GitLabService struct {
// contains filtered or unexported fields
}
func GetGitLabService ¶
func GetGitLabService(ctx *gin.Context) *GitLabService
Helper to get the gitLabService from the context.
func NewGitLabServiceFromAccessToken ¶
func NewGitLabServiceFromAccessToken(requestCtx *gin.Context, bearerToken string) (*GitLabService, error)
Returns an instance of GitLabService that uses an http.Client configured with the access token. All GET requests against GitLab are cached.
func NewGitLabServiceFromOauthToken ¶
func NewGitLabServiceFromOauthToken(ctx *gin.Context) (*GitLabService, error)
Returns an instance of GitLabService that uses an http.Client configured with the Oauth token taken from the request context. The http.Client will handle token.access_token expiry and request a new access_token using token.refresh_token. All GET requests against GitLab are cached.
func (*GitLabService) CanAccessNamespace ¶
func (s *GitLabService) CanAccessNamespace(nid string) (bool, gitlab.AccessLevelValue, error)
Check if current user can access the namespace by Id.
func (*GitLabService) CanAccessProject ¶
func (s *GitLabService) CanAccessProject(pid, minAccessLevelKey int) (bool, error)
Check if current user can access the namespace by Id.
func (*GitLabService) CurrentUser ¶
func (s *GitLabService) CurrentUser() (*gitlab.User, error)
Get the current user.
func (*GitLabService) GetAccessTokenScopes ¶
func (s *GitLabService) GetAccessTokenScopes() ([]string, error)
GetAccessTokenScopes returns the list of scopes assigned to the access token that this instance of GitlabService uses.
This method is added here because it doesn't exist in the underlying library
Docs: https://docs.gitlab.com/ee/api/personal_access_tokens.html#using-a-request-header
func (*GitLabService) GetGroup ¶
func (s *GitLabService) GetGroup(gid string) (*GitLabGroup, error)
Get GitLab group by Id.
func (*GitLabService) GetGroupProjects ¶
func (s *GitLabService) GetGroupProjects(gid interface{}) ([]*gitlab.BasicProject, error)
GetGroupProjects return all the projects available under passed Group ID.
func (*GitLabService) GetInheritedGroupMember ¶
func (s *GitLabService) GetInheritedGroupMember( gid int, user int, ) (*gitlab.GroupMember, error)
GetGroupMember gets a member of a group, including inherited membership. This method is added here because it doesn't exist in the underlying library
GitLab API docs: https://docs.gitlab.com/ee/api/members.html#get-a-member-of-a-group-or-project-including-inherited-and-invited-members
func (*GitLabService) GetInheritedProjectMember ¶
func (s *GitLabService) GetInheritedProjectMember(pid, user int) (*gitlab.ProjectMember, error)
func (*GitLabService) GetNamespace ¶
func (s *GitLabService) GetNamespace(nid string) (*GitLabNamespace, error)
Get GitLab namespace by Id.
func (*GitLabService) GetProject ¶
func (s *GitLabService) GetProject(pid interface{}) (*gitlab.Project, error)
Get Project
func (*GitLabService) GetTopLevelGroups ¶
func (s *GitLabService) GetTopLevelGroups() ([]*GitLabGroup, error)
Get GitLab group by Id.
func (*GitLabService) HandleError ¶
func (s *GitLabService) HandleError(err error) error
TODO: Investigate usage.
func (*GitLabService) IsProjectInGroup ¶
func (s *GitLabService) IsProjectInGroup(pid, gid int) (bool, error)
IsProjectInGroup checks if given project belongs to the given namespace id.
func (*GitLabService) IsProjectInUserNamespace ¶
func (s *GitLabService) IsProjectInUserNamespace(pid, nsid int) (bool, error)
IsProjectInGroup checks if given project is in the user-namespace. NOTE(prozlach) The way we do it is a bit hacky. According to the documentation:
https://docs.gitlab.com/ee/api/namespaces.html
``` A personal namespace, which is based on your username and provided to you when you create your account.
- You cannot create subgroups in a personal namespace.
- Groups in your namespace do not inherit your namespace permissions and group features.
- All the projects you create are under the scope of this namespace.
```
The way I interpret it is that even if we have groups in the user NS (haven't found a way to create them), you will be only to create projects in the namespace itself, not it in the group. Creation of subgroups does not apply here either, nor the permissions inheritance, so no need to check hierarchy.
So the idea is simple - fetch the project and see the namespace it is sitting in. If it is the same as the one we are looking for - return true, return false otherwise.
func (*GitLabService) ListProjectsGroups ¶
func (s *GitLabService) ListProjectsGroups(pid interface{}) ([]*gitlab.ProjectGroup, error)
Get Projects ancestor groups, sorted in descending order, top-level NS first
type GroupParams ¶
type GroupParams struct {
ID string `uri:"group_id" binding:"required"`
}
type IngestAuthHeader ¶
type IngestAuthHeader struct {
SentryAuth string `header:"X-Sentry-Auth" binding:"required"`
}
func (IngestAuthHeader) ParseSentryKey ¶
func (h IngestAuthHeader) ParseSentryKey() (string, error)
type LimitIDRateLimitHandlerFormParams ¶
type LimitIDRateLimitHandlerFormParams struct {
LimitID *string `json:"limit_id" form:"limit_id" binding:"omitempty,oneof=tr_write et_read et_write"`
}
type NamespaceParams ¶
type NamespacePathParam ¶
type NamespacePathParam struct {
NamespaceID int `uri:"namespace_id" binding:"required,numeric,min=1"`
}
type NamespaceWatcher ¶
type NamespaceWatcher struct { // This client, initialized using mgr.Client() above, is a split client // that reads objects from the cache and writes to the apiserver Client client.Client Scheme *runtime.Scheme Transport *http.Transport Log logr.Logger Namespace string }
NamespaceWatcher reconciles a Cluster object.
func (*NamespaceWatcher) Reconcile ¶
func (r *NamespaceWatcher) Reconcile(ctx context.Context, request reconcile.Request) (ctrl.Result, error)
Although this is a reconciler, it's being used as a cache/watcher to log update events on the GitLabNamespace. This is helpful to track the status in the same process as we start the change (creation, updating, deleting) GitLabNamespaces. We can optionally in the future at a channel to push the status back to the gatekeeper API thread so that status can be communicated to the user.
func (*NamespaceWatcher) SetupWithManager ¶
func (r *NamespaceWatcher) SetupWithManager(mgr ctrl.Manager) error
SetupWithManager sets up the controller with the Manager.
type PathFormParams ¶
type PathFormParams struct { // The shortest prefix is `/projects/{projectId}` which for single-digit // project ID gives us 11 chars. Add to it the `/errortracking/api/v1` // prefix and you get the minimal length of 32. Path string `json:"request_path" form:"request_path" binding:"required,uri,min=32"` }
type RateLimiter ¶
type RateLimiter interface { IsAllowed(context.Context, int, string, uint64) (*redis_rate.Result, error) SetLimits(*ratelimiting.LimitsConfig) }
func GetRateLimiter ¶
func GetRateLimiter(ctx *gin.Context) RateLimiter
Helper to get the ratelimiter from the context.
func NewNullRateLimiter ¶
func NewNullRateLimiter() RateLimiter
func NewRateLimiter ¶
func NewRateLimiter(limiter RateLimiterBackend) RateLimiter
type RateLimiterBackend ¶
type RedisCache ¶
type RedisCache interface { Set(item *cache.Item) error Get(ctx context.Context, key string, value interface{}) error }
func GetCache ¶
func GetCache(ctx *gin.Context) RedisCache
Helper to get the Redis client from the context.
type RoutingParams ¶
type SessionOptions ¶
type SessionOptions struct { CookieName string CookieSecret string UseSecureCookie bool Registry prometheus.Registerer }
Source Files ¶
- auth_controllers.go
- auth_metrics_middleware.go
- auth_middleware.go
- auth_utils.go
- cache.go
- config.go
- errors.go
- errortracking_auth_controller.go
- gitlab_namespace.go
- gitlab_service.go
- namespace_watcher.go
- oauth_controllers.go
- project_controller.go
- provisioning_controller.go
- rate_limit.go
- router.go
- routing_controller.go
- session_auth_controller.go
- session_middleware.go
- token_auth_controller.go