mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-11-01 14:45:47 +00:00
feat: ACL labels from environment variables (#422)
* feat: add LabelService to retrieve application labels from environment variables * feat: allow usage of labels from docker and env variables simultaneously Prioritize labels from environment variables over labels from docker labels * fix: handle error returned by label_serive.go/LoadLabels see https://github.com/steveiliop56/tinyauth/pull/422#discussion_r2443443032 * refactor(label_service): use simple loop instead of slices.ContainsFunc to avoid experimental slices package see https://github.com/steveiliop56/tinyauth/pull/422#pullrequestreview-3354632045 * refactor: merge acl logic into one service --------- Co-authored-by: Stavros <steveiliop56@gmail.com>
This commit is contained in:
@@ -24,15 +24,15 @@ type ProxyControllerConfig struct {
|
||||
type ProxyController struct {
|
||||
config ProxyControllerConfig
|
||||
router *gin.RouterGroup
|
||||
docker *service.DockerService
|
||||
acls *service.AccessControlsService
|
||||
auth *service.AuthService
|
||||
}
|
||||
|
||||
func NewProxyController(config ProxyControllerConfig, router *gin.RouterGroup, docker *service.DockerService, auth *service.AuthService) *ProxyController {
|
||||
func NewProxyController(config ProxyControllerConfig, router *gin.RouterGroup, acls *service.AccessControlsService, auth *service.AuthService) *ProxyController {
|
||||
return &ProxyController{
|
||||
config: config,
|
||||
router: router,
|
||||
docker: docker,
|
||||
acls: acls,
|
||||
auth: auth,
|
||||
}
|
||||
}
|
||||
@@ -76,20 +76,21 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
||||
proto := c.Request.Header.Get("X-Forwarded-Proto")
|
||||
host := c.Request.Header.Get("X-Forwarded-Host")
|
||||
|
||||
labels, err := controller.docker.GetLabels(host)
|
||||
// Get acls
|
||||
acls, err := controller.acls.GetAccessControls(host)
|
||||
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get labels from Docker")
|
||||
log.Error().Err(err).Msg("Failed to get access controls for resource")
|
||||
controller.handleError(c, req, isBrowser)
|
||||
return
|
||||
}
|
||||
|
||||
log.Trace().Interface("labels", labels).Msg("Labels for resource")
|
||||
log.Trace().Interface("acls", acls).Msg("ACLs for resource")
|
||||
|
||||
clientIP := c.ClientIP()
|
||||
|
||||
if controller.auth.IsBypassedIP(labels.IP, clientIP) {
|
||||
controller.setHeaders(c, labels)
|
||||
if controller.auth.IsBypassedIP(acls.IP, clientIP) {
|
||||
controller.setHeaders(c, acls)
|
||||
c.JSON(200, gin.H{
|
||||
"status": 200,
|
||||
"message": "Authenticated",
|
||||
@@ -97,7 +98,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
authEnabled, err := controller.auth.IsAuthEnabled(uri, labels.Path)
|
||||
authEnabled, err := controller.auth.IsAuthEnabled(uri, acls.Path)
|
||||
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to check if auth is enabled for resource")
|
||||
@@ -107,7 +108,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
||||
|
||||
if !authEnabled {
|
||||
log.Debug().Msg("Authentication disabled for resource, allowing access")
|
||||
controller.setHeaders(c, labels)
|
||||
controller.setHeaders(c, acls)
|
||||
c.JSON(200, gin.H{
|
||||
"status": 200,
|
||||
"message": "Authenticated",
|
||||
@@ -115,7 +116,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if !controller.auth.CheckIP(labels.IP, clientIP) {
|
||||
if !controller.auth.CheckIP(acls.IP, clientIP) {
|
||||
if req.Proxy == "nginx" || !isBrowser {
|
||||
c.JSON(401, gin.H{
|
||||
"status": 401,
|
||||
@@ -160,7 +161,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
if userContext.IsLoggedIn {
|
||||
appAllowed := controller.auth.IsResourceAllowed(c, userContext, labels)
|
||||
appAllowed := controller.auth.IsResourceAllowed(c, userContext, acls)
|
||||
|
||||
if !appAllowed {
|
||||
log.Warn().Str("user", userContext.Username).Str("resource", strings.Split(host, ".")[0]).Msg("User not allowed to access resource")
|
||||
@@ -194,7 +195,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
if userContext.OAuth {
|
||||
groupOK := controller.auth.IsInOAuthGroup(c, userContext, labels.OAuth.Groups)
|
||||
groupOK := controller.auth.IsInOAuthGroup(c, userContext, acls.OAuth.Groups)
|
||||
|
||||
if !groupOK {
|
||||
log.Warn().Str("user", userContext.Username).Str("resource", strings.Split(host, ".")[0]).Msg("User OAuth groups do not match resource requirements")
|
||||
@@ -234,7 +235,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
||||
c.Header("Remote-Email", utils.SanitizeHeader(userContext.Email))
|
||||
c.Header("Remote-Groups", utils.SanitizeHeader(userContext.OAuthGroups))
|
||||
|
||||
controller.setHeaders(c, labels)
|
||||
controller.setHeaders(c, acls)
|
||||
|
||||
c.JSON(200, gin.H{
|
||||
"status": 200,
|
||||
@@ -264,21 +265,21 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
||||
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/login?%s", controller.config.AppURL, queries.Encode()))
|
||||
}
|
||||
|
||||
func (controller *ProxyController) setHeaders(c *gin.Context, labels config.App) {
|
||||
func (controller *ProxyController) setHeaders(c *gin.Context, acls config.App) {
|
||||
c.Header("Authorization", c.Request.Header.Get("Authorization"))
|
||||
|
||||
headers := utils.ParseHeaders(labels.Response.Headers)
|
||||
headers := utils.ParseHeaders(acls.Response.Headers)
|
||||
|
||||
for key, value := range headers {
|
||||
log.Debug().Str("header", key).Msg("Setting header")
|
||||
c.Header(key, value)
|
||||
}
|
||||
|
||||
basicPassword := utils.GetSecret(labels.Response.BasicAuth.Password, labels.Response.BasicAuth.PasswordFile)
|
||||
basicPassword := utils.GetSecret(acls.Response.BasicAuth.Password, acls.Response.BasicAuth.PasswordFile)
|
||||
|
||||
if labels.Response.BasicAuth.Username != "" && basicPassword != "" {
|
||||
log.Debug().Str("username", labels.Response.BasicAuth.Username).Msg("Setting basic auth header")
|
||||
c.Header("Authorization", fmt.Sprintf("Basic %s", utils.GetBasicAuth(labels.Response.BasicAuth.Username, basicPassword)))
|
||||
if acls.Response.BasicAuth.Username != "" && basicPassword != "" {
|
||||
log.Debug().Str("username", acls.Response.BasicAuth.Username).Msg("Setting basic auth header")
|
||||
c.Header("Authorization", fmt.Sprintf("Basic %s", utils.GetBasicAuth(acls.Response.BasicAuth.Username, basicPassword)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,11 @@ func setupProxyController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.En
|
||||
|
||||
assert.NilError(t, dockerService.Init())
|
||||
|
||||
// Access controls
|
||||
accessControlsService := service.NewAccessControlsService(dockerService)
|
||||
|
||||
assert.NilError(t, accessControlsService.Init())
|
||||
|
||||
// Auth service
|
||||
authService := service.NewAuthService(service.AuthServiceConfig{
|
||||
Users: []config.User{
|
||||
@@ -59,7 +64,7 @@ func setupProxyController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.En
|
||||
// Controller
|
||||
ctrl := controller.NewProxyController(controller.ProxyControllerConfig{
|
||||
AppURL: "http://localhost:8080",
|
||||
}, group, dockerService, authService)
|
||||
}, group, accessControlsService, authService)
|
||||
ctrl.SetupRoutes()
|
||||
|
||||
return router, recorder, authService
|
||||
|
||||
Reference in New Issue
Block a user