mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-10-29 13:15:46 +00:00
Compare commits
9 Commits
v4.0.0
...
9b76a84ee2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b76a84ee2 | ||
|
|
ed20d2cf51 | ||
|
|
fc7e395e66 | ||
|
|
b940d681c3 | ||
|
|
a1ec4a69cf | ||
|
|
4047cea451 | ||
|
|
5a4855c12c | ||
|
|
05d4dbd68e | ||
|
|
ae8347fd28 |
4
.github/workflows/nightly.yml
vendored
4
.github/workflows/nightly.yml
vendored
@@ -396,6 +396,8 @@ jobs:
|
|||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
||||||
|
flavor: |
|
||||||
|
latest=false
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,nightly
|
type=raw,nightly
|
||||||
|
|
||||||
@@ -433,6 +435,8 @@ jobs:
|
|||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
||||||
|
flavor: |
|
||||||
|
latest=false
|
||||||
tags: |
|
tags: |
|
||||||
type=raw,nightly-distroless
|
type=raw,nightly-distroless
|
||||||
|
|
||||||
|
|||||||
19
.github/workflows/release.yml
vendored
19
.github/workflows/release.yml
vendored
@@ -359,10 +359,13 @@ jobs:
|
|||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
||||||
|
flavor: |
|
||||||
|
latest=true
|
||||||
|
prefix=v,onlatest=false
|
||||||
tags: |
|
tags: |
|
||||||
type=semver,pattern={{version}},prefix=v
|
type=semver,pattern={{version}}
|
||||||
type=semver,pattern={{major}},prefix=v
|
type=semver,pattern={{major}}
|
||||||
type=semver,pattern={{major}}.{{minor}},prefix=v
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
|
||||||
- name: Create manifest list and push
|
- name: Create manifest list and push
|
||||||
working-directory: ${{ runner.temp }}/digests
|
working-directory: ${{ runner.temp }}/digests
|
||||||
@@ -398,10 +401,14 @@ jobs:
|
|||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
images: ghcr.io/${{ github.repository_owner }}/tinyauth
|
||||||
|
flavor: |
|
||||||
|
latest=false
|
||||||
|
prefix=v,onlatest=false
|
||||||
|
suffix=-distroless,onlatest=false
|
||||||
tags: |
|
tags: |
|
||||||
type=semver,pattern={{version}},prefix=v,suffix=-distroless
|
type=semver,pattern={{version}}
|
||||||
type=semver,pattern={{major}},prefix=v,suffix=-distroless
|
type=semver,pattern={{major}}
|
||||||
type=semver,pattern={{major}}.{{minor}},prefix=v,suffix=-distroless
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
|
||||||
- name: Create manifest list and push
|
- name: Create manifest list and push
|
||||||
working-directory: ${{ runner.temp }}/digests
|
working-directory: ${{ runner.temp }}/digests
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ WORKDIR /tinyauth
|
|||||||
|
|
||||||
COPY --from=builder /tinyauth/tinyauth ./
|
COPY --from=builder /tinyauth/tinyauth ./
|
||||||
|
|
||||||
|
RUN mkdir -p /data
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
VOLUME ["/data"]
|
VOLUME ["/data"]
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ COPY ./cmd ./cmd
|
|||||||
COPY ./internal ./internal
|
COPY ./internal ./internal
|
||||||
COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
|
COPY --from=frontend-builder /frontend/dist ./internal/assets/dist
|
||||||
|
|
||||||
|
RUN mkdir -p data
|
||||||
|
|
||||||
RUN CGO_ENABLED=0 go build -ldflags "-s -w -X tinyauth/internal/config.Version=${VERSION} -X tinyauth/internal/config.CommitHash=${COMMIT_HASH} -X tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}"
|
RUN CGO_ENABLED=0 go build -ldflags "-s -w -X tinyauth/internal/config.Version=${VERSION} -X tinyauth/internal/config.CommitHash=${COMMIT_HASH} -X tinyauth/internal/config.BuildTimestamp=${BUILD_TIMESTAMP}"
|
||||||
|
|
||||||
# Runner
|
# Runner
|
||||||
@@ -47,6 +49,9 @@ WORKDIR /tinyauth
|
|||||||
|
|
||||||
COPY --from=builder /tinyauth/tinyauth ./
|
COPY --from=builder /tinyauth/tinyauth ./
|
||||||
|
|
||||||
|
# Since it's distroless, we need to copy the data directory from the builder stage
|
||||||
|
COPY --from=builder /tinyauth/data /data
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
VOLUME ["/data"]
|
VOLUME ["/data"]
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ Tinyauth is licensed under the GNU General Public License v3.0. TL;DR — You ma
|
|||||||
|
|
||||||
A big thank you to the following people for providing me with more coffee:
|
A big thank you to the following people for providing me with more coffee:
|
||||||
|
|
||||||
<!-- sponsors --><a href="https://github.com/erwinkramer"><img src="https://github.com/erwinkramer.png" width="64px" alt="User avatar: erwinkramer" /></a> <a href="https://github.com/nicotsx"><img src="https://github.com/nicotsx.png" width="64px" alt="User avatar: nicotsx" /></a> <a href="https://github.com/SimpleHomelab"><img src="https://github.com/SimpleHomelab.png" width="64px" alt="User avatar: SimpleHomelab" /></a> <a href="https://github.com/jmadden91"><img src="https://github.com/jmadden91.png" width="64px" alt="User avatar: jmadden91" /></a> <a href="https://github.com/tribor"><img src="https://github.com/tribor.png" width="64px" alt="User avatar: tribor" /></a> <a href="https://github.com/eliasbenb"><img src="https://github.com/eliasbenb.png" width="64px" alt="User avatar: eliasbenb" /></a> <a href="https://github.com/afunworm"><img src="https://github.com/afunworm.png" width="64px" alt="User avatar: afunworm" /></a> <!-- sponsors -->
|
<!-- sponsors --><a href="https://github.com/erwinkramer"><img src="https://github.com/erwinkramer.png" width="64px" alt="User avatar: erwinkramer" /></a> <a href="https://github.com/nicotsx"><img src="https://github.com/nicotsx.png" width="64px" alt="User avatar: nicotsx" /></a> <a href="https://github.com/SimpleHomelab"><img src="https://github.com/SimpleHomelab.png" width="64px" alt="User avatar: SimpleHomelab" /></a> <a href="https://github.com/jmadden91"><img src="https://github.com/jmadden91.png" width="64px" alt="User avatar: jmadden91" /></a> <a href="https://github.com/tribor"><img src="https://github.com/tribor.png" width="64px" alt="User avatar: tribor" /></a> <a href="https://github.com/eliasbenb"><img src="https://github.com/eliasbenb.png" width="64px" alt="User avatar: eliasbenb" /></a> <a href="https://github.com/afunworm"><img src="https://github.com/afunworm.png" width="64px" alt="User avatar: afunworm" /></a> <a href="https://github.com/chip-well"><img src="https://github.com/chip-well.png" width="64px" alt="User avatar: chip-well" /></a> <a href="https://github.com/Lancelot-Enguerrand"><img src="https://github.com/Lancelot-Enguerrand.png" width="64px" alt="User avatar: Lancelot-Enguerrand" /></a> <!-- sponsors -->
|
||||||
|
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
|
||||||
|
|||||||
2
air.toml
2
air.toml
@@ -2,7 +2,7 @@ root = "/tinyauth"
|
|||||||
tmp_dir = "tmp"
|
tmp_dir = "tmp"
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
pre_cmd = ["mkdir -p internal/assets/dist", "echo 'backend running' > internal/assets/dist/index.html", "go install github.com/go-delve/delve/cmd/dlv@v1.25.0"]
|
pre_cmd = ["mkdir -p internal/assets/dist", "mkdir -p /data", "echo 'backend running' > internal/assets/dist/index.html", "go install github.com/go-delve/delve/cmd/dlv@v1.25.0"]
|
||||||
cmd = "CGO_ENABLED=0 go build -gcflags=\"all=-N -l\" -o tmp/tinyauth ."
|
cmd = "CGO_ENABLED=0 go build -gcflags=\"all=-N -l\" -o tmp/tinyauth ."
|
||||||
bin = "/go/bin/dlv --listen :4000 --headless=true --api-version=2 --accept-multiclient --log=true exec tmp/tinyauth --continue --check-go-version=false"
|
bin = "/go/bin/dlv --listen :4000 --headless=true --api-version=2 --accept-multiclient --log=true exec tmp/tinyauth --continue --check-go-version=false"
|
||||||
include_ext = ["go"]
|
include_ext = ["go"]
|
||||||
|
|||||||
@@ -112,6 +112,10 @@ func (c *rootCmd) run(cmd *cobra.Command, args []string) {
|
|||||||
log.Logger = log.Level(zerolog.Level(utils.GetLogLevel(conf.LogLevel)))
|
log.Logger = log.Level(zerolog.Level(utils.GetLogLevel(conf.LogLevel)))
|
||||||
log.Info().Str("version", strings.TrimSpace(config.Version)).Msg("Starting Tinyauth")
|
log.Info().Str("version", strings.TrimSpace(config.Version)).Msg("Starting Tinyauth")
|
||||||
|
|
||||||
|
if log.Logger.GetLevel() == zerolog.TraceLevel {
|
||||||
|
log.Warn().Msg("Log level set to trace, this will log sensitive information!")
|
||||||
|
}
|
||||||
|
|
||||||
app := bootstrap.NewBootstrapApp(conf)
|
app := bootstrap.NewBootstrapApp(conf)
|
||||||
|
|
||||||
err = app.Setup()
|
err = app.Setup()
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/config"
|
"tinyauth/internal/config"
|
||||||
@@ -157,6 +158,10 @@ func (app *BootstrapApp) Setup() error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort.Slice(configuredProviders, func(i, j int) bool {
|
||||||
|
return configuredProviders[i].Name < configuredProviders[j].Name
|
||||||
|
})
|
||||||
|
|
||||||
if authService.UserAuthConfigured() || ldapService != nil {
|
if authService.UserAuthConfigured() || ldapService != nil {
|
||||||
configuredProviders = append(configuredProviders, controller.Provider{
|
configuredProviders = append(configuredProviders, controller.Provider{
|
||||||
Name: "Username",
|
Name: "Username",
|
||||||
@@ -173,6 +178,7 @@ func (app *BootstrapApp) Setup() error {
|
|||||||
|
|
||||||
// Create engine
|
// Create engine
|
||||||
engine := gin.New()
|
engine := gin.New()
|
||||||
|
engine.Use(gin.Recovery())
|
||||||
|
|
||||||
if len(app.config.TrustedProxies) > 0 {
|
if len(app.config.TrustedProxies) > 0 {
|
||||||
err := engine.SetTrustedProxies(strings.Split(app.config.TrustedProxies, ","))
|
err := engine.SetTrustedProxies(strings.Split(app.config.TrustedProxies, ","))
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) {
|
|||||||
|
|
||||||
var name string
|
var name string
|
||||||
|
|
||||||
if user.Name != "" {
|
if strings.TrimSpace(user.Name) != "" {
|
||||||
log.Debug().Msg("Using name from OAuth provider")
|
log.Debug().Msg("Using name from OAuth provider")
|
||||||
name = user.Name
|
name = user.Name
|
||||||
} else {
|
} else {
|
||||||
@@ -172,7 +172,7 @@ func (controller *OAuthController) oauthCallbackHandler(c *gin.Context) {
|
|||||||
|
|
||||||
var username string
|
var username string
|
||||||
|
|
||||||
if user.PreferredUsername != "" {
|
if strings.TrimSpace(user.PreferredUsername) != "" {
|
||||||
log.Debug().Msg("Using preferred username from OAuth provider")
|
log.Debug().Msg("Using preferred username from OAuth provider")
|
||||||
username = user.PreferredUsername
|
username = user.PreferredUsername
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -84,6 +84,8 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Trace().Interface("labels", labels).Msg("Labels for resource")
|
||||||
|
|
||||||
clientIP := c.ClientIP()
|
clientIP := c.ClientIP()
|
||||||
|
|
||||||
if controller.auth.IsBypassedIP(labels.IP, clientIP) {
|
if controller.auth.IsBypassedIP(labels.IP, clientIP) {
|
||||||
@@ -150,6 +152,8 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
|
|||||||
userContext = context
|
userContext = context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Trace().Interface("context", userContext).Msg("User context from request")
|
||||||
|
|
||||||
if userContext.Provider == "basic" && userContext.TotpEnabled {
|
if userContext.Provider == "basic" && userContext.TotpEnabled {
|
||||||
log.Debug().Msg("User has TOTP enabled, denying basic auth access")
|
log.Debug().Msg("User has TOTP enabled, denying basic auth access")
|
||||||
userContext.IsLoggedIn = false
|
userContext.IsLoggedIn = false
|
||||||
|
|||||||
@@ -318,6 +318,7 @@ func (auth *AuthService) IsInOAuthGroup(c *gin.Context, context config.UserConte
|
|||||||
|
|
||||||
for userGroup := range strings.SplitSeq(context.OAuthGroups, ",") {
|
for userGroup := range strings.SplitSeq(context.OAuthGroups, ",") {
|
||||||
if utils.CheckFilter(requiredGroups, strings.TrimSpace(userGroup)) {
|
if utils.CheckFilter(requiredGroups, strings.TrimSpace(userGroup)) {
|
||||||
|
log.Trace().Str("group", userGroup).Str("required", requiredGroups).Msg("User group matched")
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type DockerService struct {
|
type DockerService struct {
|
||||||
client *client.Client
|
client *client.Client
|
||||||
context context.Context
|
context context.Context
|
||||||
|
isConnected bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDockerService() *DockerService {
|
func NewDockerService() *DockerService {
|
||||||
@@ -31,10 +32,24 @@ func (docker *DockerService) Init() error {
|
|||||||
|
|
||||||
docker.client = client
|
docker.client = client
|
||||||
docker.context = ctx
|
docker.context = ctx
|
||||||
|
|
||||||
|
_, err = docker.client.Ping(docker.context)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Debug().Err(err).Msg("Docker not connected")
|
||||||
|
docker.isConnected = false
|
||||||
|
docker.client = nil
|
||||||
|
docker.context = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
docker.isConnected = true
|
||||||
|
log.Debug().Msg("Docker connected")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (docker *DockerService) GetContainers() ([]container.Summary, error) {
|
func (docker *DockerService) getContainers() ([]container.Summary, error) {
|
||||||
containers, err := docker.client.ContainerList(docker.context, container.ListOptions{})
|
containers, err := docker.client.ContainerList(docker.context, container.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -42,7 +57,7 @@ func (docker *DockerService) GetContainers() ([]container.Summary, error) {
|
|||||||
return containers, nil
|
return containers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (docker *DockerService) InspectContainer(containerId string) (container.InspectResponse, error) {
|
func (docker *DockerService) inspectContainer(containerId string) (container.InspectResponse, error) {
|
||||||
inspect, err := docker.client.ContainerInspect(docker.context, containerId)
|
inspect, err := docker.client.ContainerInspect(docker.context, containerId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return container.InspectResponse{}, err
|
return container.InspectResponse{}, err
|
||||||
@@ -50,26 +65,19 @@ func (docker *DockerService) InspectContainer(containerId string) (container.Ins
|
|||||||
return inspect, nil
|
return inspect, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (docker *DockerService) DockerConnected() bool {
|
|
||||||
_, err := docker.client.Ping(docker.context)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (docker *DockerService) GetLabels(appDomain string) (config.App, error) {
|
func (docker *DockerService) GetLabels(appDomain string) (config.App, error) {
|
||||||
isConnected := docker.DockerConnected()
|
if !docker.isConnected {
|
||||||
|
|
||||||
if !isConnected {
|
|
||||||
log.Debug().Msg("Docker not connected, returning empty labels")
|
log.Debug().Msg("Docker not connected, returning empty labels")
|
||||||
return config.App{}, nil
|
return config.App{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
containers, err := docker.GetContainers()
|
containers, err := docker.getContainers()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return config.App{}, err
|
return config.App{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, ctr := range containers {
|
for _, ctr := range containers {
|
||||||
inspect, err := docker.InspectContainer(ctr.ID)
|
inspect, err := docker.inspectContainer(ctr.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return config.App{}, err
|
return config.App{}, err
|
||||||
}
|
}
|
||||||
@@ -81,12 +89,12 @@ func (docker *DockerService) GetLabels(appDomain string) (config.App, error) {
|
|||||||
|
|
||||||
for appName, appLabels := range labels.Apps {
|
for appName, appLabels := range labels.Apps {
|
||||||
if appLabels.Config.Domain == appDomain {
|
if appLabels.Config.Domain == appDomain {
|
||||||
log.Debug().Str("id", inspect.ID).Msg("Found matching container by domain")
|
log.Debug().Str("id", inspect.ID).Str("name", inspect.Name).Msg("Found matching container by domain")
|
||||||
return appLabels, nil
|
return appLabels, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.TrimPrefix(inspect.Name, "/") == appName {
|
if strings.TrimPrefix(inspect.Name, "/") == appName {
|
||||||
log.Debug().Str("id", inspect.ID).Msg("Found matching container by app name")
|
log.Debug().Str("id", inspect.ID).Str("name", inspect.Name).Msg("Found matching container by app name")
|
||||||
return appLabels, nil
|
return appLabels, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"tinyauth/internal/config"
|
"tinyauth/internal/config"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -110,6 +111,8 @@ func (generic *GenericOAuthService) Userinfo() (config.Claims, error) {
|
|||||||
return user, err
|
return user, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Trace().Str("body", string(body)).Msg("Userinfo response body")
|
||||||
|
|
||||||
err = json.Unmarshal(body, &user)
|
err = json.Unmarshal(body, &user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return user, err
|
return user, err
|
||||||
|
|||||||
Reference in New Issue
Block a user