mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-12-25 17:42:30 +00:00
feat: add support for required oauth groups
This commit is contained in:
@@ -42,6 +42,7 @@
|
|||||||
"unauthorizedTitle": "Unauthorized",
|
"unauthorizedTitle": "Unauthorized",
|
||||||
"unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.",
|
"unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||||
"unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.",
|
"unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.",
|
||||||
|
"unauthorizedGroupsSubtitle": "The user with username <Code>{{username}}</Code> is not in the groups required by the resource <Code>{{resource}}</Code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
"untrustedRedirectTitle": "Untrusted redirect",
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<Code>{{domain}}</Code>). Are you sure you want to continue?",
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<Code>{{domain}}</Code>). Are you sure you want to continue?",
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
"unauthorizedTitle": "Unauthorized",
|
"unauthorizedTitle": "Unauthorized",
|
||||||
"unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.",
|
"unauthorizedResourceSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to access the resource <Code>{{resource}}</Code>.",
|
||||||
"unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.",
|
"unaothorizedLoginSubtitle": "The user with username <Code>{{username}}</Code> is not authorized to login.",
|
||||||
|
"unauthorizedGroupsSubtitle": "The user with username <Code>{{username}}</Code> is not in the groups required by the resource <Code>{{resource}}</Code>.",
|
||||||
"unauthorizedButton": "Try again",
|
"unauthorizedButton": "Try again",
|
||||||
"untrustedRedirectTitle": "Untrusted redirect",
|
"untrustedRedirectTitle": "Untrusted redirect",
|
||||||
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<Code>{{domain}}</Code>). Are you sure you want to continue?",
|
"untrustedRedirectSubtitle": "You are trying to redirect to a domain that does not match your configured domain (<Code>{{domain}}</Code>). Are you sure you want to continue?",
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ import { Layout } from "../components/layouts/layout";
|
|||||||
import { Navigate } from "react-router";
|
import { Navigate } from "react-router";
|
||||||
import { isQueryValid } from "../utils/utils";
|
import { isQueryValid } from "../utils/utils";
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
export const UnauthorizedPage = () => {
|
export const UnauthorizedPage = () => {
|
||||||
const queryString = window.location.search;
|
const queryString = window.location.search;
|
||||||
const params = new URLSearchParams(queryString);
|
const params = new URLSearchParams(queryString);
|
||||||
const username = params.get("username") ?? "";
|
const username = params.get("username") ?? "";
|
||||||
|
const groupErr = params.get("groupErr") ?? "";
|
||||||
const resource = params.get("resource") ?? "";
|
const resource = params.get("resource") ?? "";
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -16,6 +18,47 @@ export const UnauthorizedPage = () => {
|
|||||||
return <Navigate to="/" />;
|
return <Navigate to="/" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isQueryValid(resource) && !isQueryValid(groupErr)) {
|
||||||
|
return (
|
||||||
|
<UnauthorizedLayout>
|
||||||
|
<Trans
|
||||||
|
i18nKey="unauthorizedResourceSubtitle"
|
||||||
|
t={t}
|
||||||
|
components={{ Code: <Code /> }}
|
||||||
|
values={{ resource, username }}
|
||||||
|
/>
|
||||||
|
</UnauthorizedLayout>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isQueryValid(groupErr) && isQueryValid(resource)) {
|
||||||
|
return (
|
||||||
|
<UnauthorizedLayout>
|
||||||
|
<Trans
|
||||||
|
i18nKey="unauthorizedGroupsSubtitle"
|
||||||
|
t={t}
|
||||||
|
components={{ Code: <Code /> }}
|
||||||
|
values={{ username, resource }}
|
||||||
|
/>
|
||||||
|
</UnauthorizedLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UnauthorizedLayout>
|
||||||
|
<Trans
|
||||||
|
i18nKey="unaothorizedLoginSubtitle"
|
||||||
|
t={t}
|
||||||
|
components={{ Code: <Code /> }}
|
||||||
|
values={{ username }}
|
||||||
|
/>
|
||||||
|
</UnauthorizedLayout>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const UnauthorizedLayout = ({ children }: { children: React.ReactNode }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Paper shadow="md" p={30} mt={30} radius="md" withBorder>
|
<Paper shadow="md" p={30} mt={30} radius="md" withBorder>
|
||||||
@@ -23,25 +66,7 @@ export const UnauthorizedPage = () => {
|
|||||||
{t("Unauthorized")}
|
{t("Unauthorized")}
|
||||||
</Text>
|
</Text>
|
||||||
<Text>
|
<Text>
|
||||||
{isQueryValid(resource) ? (
|
{children}
|
||||||
<Text>
|
|
||||||
<Trans
|
|
||||||
i18nKey="unauthorizedResourceSubtitle"
|
|
||||||
t={t}
|
|
||||||
components={{ Code: <Code /> }}
|
|
||||||
values={{ resource, username }}
|
|
||||||
/>
|
|
||||||
</Text>
|
|
||||||
) : (
|
|
||||||
<Text>
|
|
||||||
<Trans
|
|
||||||
i18nKey="unaothorizedLoginSubtitle"
|
|
||||||
t={t}
|
|
||||||
components={{ Code: <Code /> }}
|
|
||||||
values={{ username }}
|
|
||||||
/>
|
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Text>
|
</Text>
|
||||||
<Button
|
<Button
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ func (auth *Auth) CreateSessionCookie(c *gin.Context, data *types.SessionCookie)
|
|||||||
session.Values["provider"] = data.Provider
|
session.Values["provider"] = data.Provider
|
||||||
session.Values["expiry"] = time.Now().Add(time.Duration(sessionExpiry) * time.Second).Unix()
|
session.Values["expiry"] = time.Now().Add(time.Duration(sessionExpiry) * time.Second).Unix()
|
||||||
session.Values["totpPending"] = data.TotpPending
|
session.Values["totpPending"] = data.TotpPending
|
||||||
|
session.Values["oauthGroups"] = data.OAuthGroups
|
||||||
|
|
||||||
// Save session
|
// Save session
|
||||||
err = session.Save(c.Request, c.Writer)
|
err = session.Save(c.Request, c.Writer)
|
||||||
@@ -213,7 +214,7 @@ func (auth *Auth) GetSessionCookie(c *gin.Context) (types.SessionCookie, error)
|
|||||||
return types.SessionCookie{}, err
|
return types.SessionCookie{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Interface("session", session).Msg("Got session")
|
log.Debug().Msg("Got session")
|
||||||
|
|
||||||
// Get data from session
|
// Get data from session
|
||||||
username, usernameOk := session.Values["username"].(string)
|
username, usernameOk := session.Values["username"].(string)
|
||||||
@@ -222,8 +223,9 @@ func (auth *Auth) GetSessionCookie(c *gin.Context) (types.SessionCookie, error)
|
|||||||
provider, providerOK := session.Values["provider"].(string)
|
provider, providerOK := session.Values["provider"].(string)
|
||||||
expiry, expiryOk := session.Values["expiry"].(int64)
|
expiry, expiryOk := session.Values["expiry"].(int64)
|
||||||
totpPending, totpPendingOk := session.Values["totpPending"].(bool)
|
totpPending, totpPendingOk := session.Values["totpPending"].(bool)
|
||||||
|
oauthGroups, oauthGroupsOk := session.Values["oauthGroups"].(string)
|
||||||
|
|
||||||
if !usernameOk || !providerOK || !expiryOk || !totpPendingOk || !emailOk || !nameOk {
|
if !usernameOk || !providerOK || !expiryOk || !totpPendingOk || !emailOk || !nameOk || !oauthGroupsOk {
|
||||||
log.Warn().Msg("Session cookie is invalid")
|
log.Warn().Msg("Session cookie is invalid")
|
||||||
|
|
||||||
// If any data is missing, delete the session cookie
|
// If any data is missing, delete the session cookie
|
||||||
@@ -244,7 +246,7 @@ func (auth *Auth) GetSessionCookie(c *gin.Context) (types.SessionCookie, error)
|
|||||||
return types.SessionCookie{}, nil
|
return types.SessionCookie{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Str("username", username).Str("provider", provider).Int64("expiry", expiry).Bool("totpPending", totpPending).Str("name", name).Str("email", email).Msg("Parsed cookie")
|
log.Debug().Str("username", username).Str("provider", provider).Int64("expiry", expiry).Bool("totpPending", totpPending).Str("name", name).Str("email", email).Str("oauthGroups", oauthGroups).Msg("Parsed cookie")
|
||||||
|
|
||||||
// Return the cookie
|
// Return the cookie
|
||||||
return types.SessionCookie{
|
return types.SessionCookie{
|
||||||
@@ -253,6 +255,7 @@ func (auth *Auth) GetSessionCookie(c *gin.Context) (types.SessionCookie, error)
|
|||||||
Email: email,
|
Email: email,
|
||||||
Provider: provider,
|
Provider: provider,
|
||||||
TotpPending: totpPending,
|
TotpPending: totpPending,
|
||||||
|
OAuthGroups: oauthGroups,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,48 +264,46 @@ func (auth *Auth) UserAuthConfigured() bool {
|
|||||||
return len(auth.Config.Users) > 0
|
return len(auth.Config.Users) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (auth *Auth) ResourceAllowed(c *gin.Context, context types.UserContext) (bool, error) {
|
func (auth *Auth) ResourceAllowed(c *gin.Context, context types.UserContext, labels types.TinyauthLabels) bool {
|
||||||
// Get headers
|
|
||||||
host := c.Request.Header.Get("X-Forwarded-Host")
|
|
||||||
|
|
||||||
// Get app id
|
|
||||||
appId := strings.Split(host, ".")[0]
|
|
||||||
|
|
||||||
// Get the container labels
|
|
||||||
labels, err := auth.Docker.GetLabels(appId)
|
|
||||||
|
|
||||||
// If there is an error, return false
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if oauth is allowed
|
// Check if oauth is allowed
|
||||||
if context.OAuth {
|
if context.OAuth {
|
||||||
log.Debug().Msg("Checking OAuth whitelist")
|
log.Debug().Msg("Checking OAuth whitelist")
|
||||||
return utils.CheckWhitelist(labels.OAuthWhitelist, context.Username), nil
|
return utils.CheckWhitelist(labels.OAuthWhitelist, context.Username)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check users
|
// Check users
|
||||||
log.Debug().Msg("Checking users")
|
log.Debug().Msg("Checking users")
|
||||||
|
|
||||||
return utils.CheckWhitelist(labels.Users, context.Username), nil
|
return utils.CheckWhitelist(labels.Users, context.Username)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (auth *Auth) AuthEnabled(c *gin.Context) (bool, error) {
|
func (auth *Auth) OAuthGroup(c *gin.Context, context types.UserContext, labels types.TinyauthLabels) bool {
|
||||||
|
// Check if groups are required
|
||||||
|
if labels.OAuthGroups == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the groups by comma (no need to parse since they are from the API response)
|
||||||
|
oauthGroups := strings.Split(context.OAuthGroups, ",")
|
||||||
|
|
||||||
|
// For every group check if it is in the required groups
|
||||||
|
for _, group := range oauthGroups {
|
||||||
|
if utils.CheckWhitelist(labels.OAuthGroups, group) {
|
||||||
|
log.Debug().Str("group", group).Msg("Group is in required groups")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No groups matched
|
||||||
|
log.Debug().Msg("No groups matched")
|
||||||
|
|
||||||
|
// Return false
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (auth *Auth) AuthEnabled(c *gin.Context, labels types.TinyauthLabels) (bool, error) {
|
||||||
// Get headers
|
// Get headers
|
||||||
uri := c.Request.Header.Get("X-Forwarded-Uri")
|
uri := c.Request.Header.Get("X-Forwarded-Uri")
|
||||||
host := c.Request.Header.Get("X-Forwarded-Host")
|
|
||||||
|
|
||||||
// Get app id
|
|
||||||
appId := strings.Split(host, ".")[0]
|
|
||||||
|
|
||||||
// Get the container labels
|
|
||||||
labels, err := auth.Docker.GetLabels(appId)
|
|
||||||
|
|
||||||
// If there is an error, auth enabled
|
|
||||||
if err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the allowed label is empty
|
// Check if the allowed label is empty
|
||||||
if labels.Allowed == "" {
|
if labels.Allowed == "" {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ var TinyauthLabels = []string{
|
|||||||
"tinyauth.users",
|
"tinyauth.users",
|
||||||
"tinyauth.allowed",
|
"tinyauth.allowed",
|
||||||
"tinyauth.headers",
|
"tinyauth.headers",
|
||||||
|
"tinyauth.oauth.groups",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Claims are the OIDC supported claims (including preferd username for some reason)
|
// Claims are the OIDC supported claims (including preferd username for some reason)
|
||||||
@@ -13,4 +14,5 @@ type Claims struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
PreferredUsername string `json:"preferred_username"`
|
PreferredUsername string `json:"preferred_username"`
|
||||||
|
Groups []string `json:"groups"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,12 +69,15 @@ func (h *Handlers) AuthHandler(c *gin.Context) {
|
|||||||
proto := c.Request.Header.Get("X-Forwarded-Proto")
|
proto := c.Request.Header.Get("X-Forwarded-Proto")
|
||||||
host := c.Request.Header.Get("X-Forwarded-Host")
|
host := c.Request.Header.Get("X-Forwarded-Host")
|
||||||
|
|
||||||
// Check if auth is enabled
|
// Get the app id
|
||||||
authEnabled, err := h.Auth.AuthEnabled(c)
|
appId := strings.Split(host, ".")[0]
|
||||||
|
|
||||||
|
// Get the container labels
|
||||||
|
labels, err := h.Docker.GetLabels(appId)
|
||||||
|
|
||||||
// Check if there was an error
|
// Check if there was an error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to check if app is allowed")
|
log.Error().Err(err).Msg("Failed to get container labels")
|
||||||
|
|
||||||
if proxy.Proxy == "nginx" || !isBrowser {
|
if proxy.Proxy == "nginx" || !isBrowser {
|
||||||
c.JSON(500, gin.H{
|
c.JSON(500, gin.H{
|
||||||
@@ -88,11 +91,8 @@ func (h *Handlers) AuthHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the app id
|
// Check if auth is enabled
|
||||||
appId := strings.Split(host, ".")[0]
|
authEnabled, err := h.Auth.AuthEnabled(c, labels)
|
||||||
|
|
||||||
// Get the container labels
|
|
||||||
labels, err := h.Docker.GetLabels(appId)
|
|
||||||
|
|
||||||
// Check if there was an error
|
// Check if there was an error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -131,23 +131,7 @@ func (h *Handlers) AuthHandler(c *gin.Context) {
|
|||||||
log.Debug().Msg("Authenticated")
|
log.Debug().Msg("Authenticated")
|
||||||
|
|
||||||
// Check if user is allowed to access subdomain, if request is nginx.example.com the subdomain (resource) is nginx
|
// Check if user is allowed to access subdomain, if request is nginx.example.com the subdomain (resource) is nginx
|
||||||
appAllowed, err := h.Auth.ResourceAllowed(c, userContext)
|
appAllowed := h.Auth.ResourceAllowed(c, userContext, labels)
|
||||||
|
|
||||||
// Check if there was an error
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Failed to check if app is allowed")
|
|
||||||
|
|
||||||
if proxy.Proxy == "nginx" || !isBrowser {
|
|
||||||
c.JSON(500, gin.H{
|
|
||||||
"status": 500,
|
|
||||||
"message": "Internal Server Error",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Redirect(http.StatusPermanentRedirect, fmt.Sprintf("%s/error", h.Config.AppURL))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug().Bool("appAllowed", appAllowed).Msg("Checking if app is allowed")
|
log.Debug().Bool("appAllowed", appAllowed).Msg("Checking if app is allowed")
|
||||||
|
|
||||||
@@ -184,9 +168,51 @@ func (h *Handlers) AuthHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debug().Interface("labels", labels).Msg("Got labels")
|
||||||
|
|
||||||
|
// Check if user is in required groups
|
||||||
|
groupOk := h.Auth.OAuthGroup(c, userContext, labels)
|
||||||
|
|
||||||
|
log.Debug().Bool("groupOk", groupOk).Msg("Checking if user is in required groups")
|
||||||
|
|
||||||
|
// The user is not allowed to access the app
|
||||||
|
if !groupOk {
|
||||||
|
log.Warn().Str("username", userContext.Username).Str("host", host).Msg("User is not in required groups")
|
||||||
|
|
||||||
|
// Set WWW-Authenticate header
|
||||||
|
c.Header("WWW-Authenticate", "Basic realm=\"tinyauth\"")
|
||||||
|
|
||||||
|
if proxy.Proxy == "nginx" || !isBrowser {
|
||||||
|
c.JSON(401, gin.H{
|
||||||
|
"status": 401,
|
||||||
|
"message": "Unauthorized",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build query
|
||||||
|
queries, err := query.Values(types.UnauthorizedQuery{
|
||||||
|
Username: userContext.Username,
|
||||||
|
Resource: strings.Split(host, ".")[0],
|
||||||
|
GroupErr: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Handle error (no need to check for nginx/headers since we are sure we are using caddy/traefik)
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Err(err).Msg("Failed to build queries")
|
||||||
|
c.Redirect(http.StatusPermanentRedirect, fmt.Sprintf("%s/error", h.Config.AppURL))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// We are using caddy/traefik so redirect
|
||||||
|
c.Redirect(http.StatusTemporaryRedirect, fmt.Sprintf("%s/unauthorized?%s", h.Config.AppURL, queries.Encode()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.Header("Remote-User", userContext.Username)
|
c.Header("Remote-User", userContext.Username)
|
||||||
c.Header("Remote-Name", userContext.Name)
|
c.Header("Remote-Name", userContext.Name)
|
||||||
c.Header("Remote-Email", userContext.Email)
|
c.Header("Remote-Email", userContext.Email)
|
||||||
|
c.Header("Remote-Groups", userContext.OAuthGroups)
|
||||||
|
|
||||||
// Set the rest of the headers
|
// Set the rest of the headers
|
||||||
for key, value := range labels.Headers {
|
for key, value := range labels.Headers {
|
||||||
@@ -688,6 +714,7 @@ func (h *Handlers) OauthCallbackHandler(c *gin.Context) {
|
|||||||
Name: name,
|
Name: name,
|
||||||
Email: user.Email,
|
Email: user.Email,
|
||||||
Provider: providerName.Provider,
|
Provider: providerName.Provider,
|
||||||
|
OAuthGroups: strings.Join(user.Groups, ","),
|
||||||
})
|
})
|
||||||
|
|
||||||
// Check if we have a redirect URI
|
// Check if we have a redirect URI
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ func (hooks *Hooks) UseUserContext(c *gin.Context) types.UserContext {
|
|||||||
IsLoggedIn: true,
|
IsLoggedIn: true,
|
||||||
OAuth: true,
|
OAuth: true,
|
||||||
Provider: cookie.Provider,
|
Provider: cookie.Provider,
|
||||||
|
OAuthGroups: cookie.OAuthGroups,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ type OAuthRequest struct {
|
|||||||
type UnauthorizedQuery struct {
|
type UnauthorizedQuery struct {
|
||||||
Username string `url:"username"`
|
Username string `url:"username"`
|
||||||
Resource string `url:"resource"`
|
Resource string `url:"resource"`
|
||||||
|
GroupErr bool `url:"groupErr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proxy is the uri parameters for the proxy endpoint
|
// Proxy is the uri parameters for the proxy endpoint
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ type SessionCookie struct {
|
|||||||
Email string
|
Email string
|
||||||
Provider string
|
Provider string
|
||||||
TotpPending bool
|
TotpPending bool
|
||||||
|
OAuthGroups string
|
||||||
}
|
}
|
||||||
|
|
||||||
// TinyauthLabels is the labels for the tinyauth container
|
// TinyauthLabels is the labels for the tinyauth container
|
||||||
@@ -37,6 +38,7 @@ type TinyauthLabels struct {
|
|||||||
Users string
|
Users string
|
||||||
Allowed string
|
Allowed string
|
||||||
Headers map[string]string
|
Headers map[string]string
|
||||||
|
OAuthGroups string
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserContext is the context for the user
|
// UserContext is the context for the user
|
||||||
@@ -48,6 +50,7 @@ type UserContext struct {
|
|||||||
OAuth bool
|
OAuth bool
|
||||||
Provider string
|
Provider string
|
||||||
TotpPending bool
|
TotpPending bool
|
||||||
|
OAuthGroups string
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoginAttempt tracks information about login attempts for rate limiting
|
// LoginAttempt tracks information about login attempts for rate limiting
|
||||||
|
|||||||
@@ -204,6 +204,8 @@ func GetTinyauthLabels(labels map[string]string) types.TinyauthLabels {
|
|||||||
}
|
}
|
||||||
tinyauthLabels.Headers[headerSplit[0]] = headerSplit[1]
|
tinyauthLabels.Headers[headerSplit[0]] = headerSplit[1]
|
||||||
}
|
}
|
||||||
|
case "tinyauth.oauth.groups":
|
||||||
|
tinyauthLabels.OAuthGroups = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user