diff --git a/cmd/root.go b/cmd/root.go
index 4be9b1b..4c612be 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -78,8 +78,15 @@ var rootCmd = &cobra.Command{
log.Debug().Msg("Parsed OAuth config")
+ // Create docker service
+ docker := docker.NewDocker()
+
+ // Initialize docker
+ dockerErr := docker.Init()
+ HandleError(dockerErr, "Failed to initialize docker")
+
// Create auth service
- auth := auth.NewAuth(users, oauthWhitelist)
+ auth := auth.NewAuth(docker, users, oauthWhitelist)
// Create OAuth providers service
providers := providers.NewProviders(oauthConfig)
@@ -90,13 +97,6 @@ var rootCmd = &cobra.Command{
// Create hooks service
hooks := hooks.NewHooks(auth, providers)
- // Create docker service
- docker := docker.NewDocker()
-
- // Initialize docker
- dockerErr := docker.Init()
- HandleError(dockerErr, "Failed to initialize docker")
-
// Create API
api := api.NewAPI(types.APIConfig{
Port: config.Port,
@@ -113,18 +113,7 @@ var rootCmd = &cobra.Command{
api.SetupRoutes()
// Start
- // api.Run()
- containers, err := docker.GetContainers()
- HandleError(err, "Failed to get containers")
-
- for _, container := range containers {
- log.Debug().Str("container", container.ID).Msg("Found container")
- inspect, err := docker.InspectContainer(container.ID)
- HandleError(err, "Failed to inspect container")
- log.Debug().Str("container", container.ID).Str("name", inspect.Name).Interface("labels", container.Labels).Msg("Inspected container")
- labels := utils.GetTinyauthLabels(inspect.Config.Labels)
- log.Debug().Interface("labels", labels).Msg("Parsed labels")
- }
+ api.Run()
},
}
diff --git a/internal/api/api.go b/internal/api/api.go
index 6088bc9..8839ea4 100644
--- a/internal/api/api.go
+++ b/internal/api/api.go
@@ -98,8 +98,30 @@ func (api *API) SetupRoutes() {
log.Debug().Msg("Checking auth")
userContext := api.Hooks.UseUserContext(c)
+ uri := c.Request.Header.Get("X-Forwarded-Uri")
+ proto := c.Request.Header.Get("X-Forwarded-Proto")
+ host := c.Request.Header.Get("X-Forwarded-Host")
+
if userContext.IsLoggedIn {
log.Debug().Msg("Authenticated")
+
+ appAllowed, appAllowedErr := api.Auth.ResourceAllowed(userContext, host)
+ if handleApiError(c, "Failed to check if resource is allowed", appAllowedErr) {
+ return
+ }
+
+ if !appAllowed {
+ log.Warn().Str("username", userContext.Username).Str("host", host).Msg("User not allowed")
+ queries, queryErr := query.Values(types.UnauthorizedQuery{
+ Username: userContext.Username,
+ Resource: strings.Split(host, ".")[0],
+ })
+ if handleApiError(c, "Failed to build query", queryErr) {
+ return
+ }
+ c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/unauthorized?%s", api.Config.AppURL, queries.Encode()))
+ }
+
c.JSON(200, gin.H{
"status": 200,
"message": "Authenticated",
@@ -107,9 +129,6 @@ func (api *API) SetupRoutes() {
return
}
- uri := c.Request.Header.Get("X-Forwarded-Uri")
- proto := c.Request.Header.Get("X-Forwarded-Proto")
- host := c.Request.Header.Get("X-Forwarded-Host")
queries, queryErr := query.Values(types.LoginQuery{
RedirectURI: fmt.Sprintf("%s://%s%s", proto, host, uri),
})
diff --git a/internal/auth/auth.go b/internal/auth/auth.go
index 6ed71a5..554cafa 100644
--- a/internal/auth/auth.go
+++ b/internal/auth/auth.go
@@ -1,7 +1,11 @@
package auth
import (
+ "slices"
+ "strings"
+ "tinyauth/internal/docker"
"tinyauth/internal/types"
+ "tinyauth/internal/utils"
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
@@ -9,8 +13,9 @@ import (
"golang.org/x/crypto/bcrypt"
)
-func NewAuth(userList types.Users, oauthWhitelist []string) *Auth {
+func NewAuth(docker *docker.Docker, userList types.Users, oauthWhitelist []string) *Auth {
return &Auth{
+ Docker: docker,
Users: userList,
OAuthWhitelist: oauthWhitelist,
}
@@ -18,6 +23,7 @@ func NewAuth(userList types.Users, oauthWhitelist []string) *Auth {
type Auth struct {
Users types.Users
+ Docker *docker.Docker
OAuthWhitelist []string
}
@@ -89,3 +95,53 @@ func (auth *Auth) GetSessionCookie(c *gin.Context) (types.SessionCookie, error)
func (auth *Auth) UserAuthConfigured() bool {
return len(auth.Users) > 0
}
+
+func (auth *Auth) ResourceAllowed(context types.UserContext, host string) (bool, error) {
+ appId := strings.Split(host, ".")[0]
+ containers, containersErr := auth.Docker.GetContainers()
+
+ if containersErr != nil {
+ return false, containersErr
+ }
+
+ log.Debug().Msg("Got containers")
+
+ for _, container := range containers {
+ inspect, inspectErr := auth.Docker.InspectContainer(container.ID)
+
+ if inspectErr != nil {
+ return false, inspectErr
+ }
+
+ containerName := strings.Split(inspect.Name, "/")[1]
+
+ if containerName == appId {
+ log.Debug().Str("container", containerName).Msg("Found container")
+
+ labels := utils.GetTinyauthLabels(inspect.Config.Labels)
+
+ log.Debug().Msg("Got labels")
+
+ if context.OAuth && len(labels.OAuthWhitelist) != 0 {
+ log.Debug().Msg("Checking OAuth whitelist")
+ if slices.Contains(labels.OAuthWhitelist, context.Username) {
+ return true, nil
+ }
+ return false, nil
+ }
+
+ if len(labels.Users) != 0 {
+ log.Debug().Msg("Checking users")
+ if slices.Contains(labels.Users, context.Username) {
+ return true, nil
+ }
+ return false, nil
+ }
+ }
+
+ }
+
+ log.Debug().Msg("No matching container found, allowing access")
+
+ return true, nil
+}
diff --git a/internal/types/types.go b/internal/types/types.go
index 951d549..bbc0542 100644
--- a/internal/types/types.go
+++ b/internal/types/types.go
@@ -89,6 +89,7 @@ type OAuthProviders struct {
type UnauthorizedQuery struct {
Username string `url:"username"`
+ Resource string `url:"resource"`
}
type SessionCookie struct {
diff --git a/site/src/pages/unauthorized-page.tsx b/site/src/pages/unauthorized-page.tsx
index 2a92f74..7c3b8a8 100644
--- a/site/src/pages/unauthorized-page.tsx
+++ b/site/src/pages/unauthorized-page.tsx
@@ -1,18 +1,12 @@
import { Button, Code, Paper, Text } from "@mantine/core";
import { Layout } from "../components/layouts/layout";
-import { useUserContext } from "../context/user-context";
import { Navigate } from "react-router";
export const UnauthorizedPage = () => {
const queryString = window.location.search;
const params = new URLSearchParams(queryString);
const username = params.get("username");
-
- const { isLoggedIn } = useUserContext();
-
- if (isLoggedIn) {
- return ;
- }
+ const resource = params.get("resource");
if (username === "null") {
return ;
@@ -25,8 +19,14 @@ export const UnauthorizedPage = () => {
Unauthorized
- The user with username {username} is not authorized to
- login.
+ The user with username {username} is not authorized to{" "}
+ {resource !== "null" ? (
+
+ access the {resource} resource.
+
+ ) : (
+ "login."
+ )}