feat: support oidc login (#1488)

This commit is contained in:
Jray
2025-12-15 21:56:59 +08:00
committed by GitHub
parent 56b18741f3
commit 0e7ea57110
16 changed files with 373 additions and 42 deletions
+3
View File
@@ -52,6 +52,7 @@ func GetSettings(c *gin.Context) {
"database": settings.DatabaseSettings,
"auth": settings.AuthSettings,
"casdoor": settings.CasdoorSettings,
"oidc": settings.OIDCSettings,
"cert": settings.CertSettings,
"http": settings.HTTPSettings,
"logrotate": settings.LogrotateSettings,
@@ -74,6 +75,7 @@ func SaveSettings(c *gin.Context) {
Openai settings.OpenAI `json:"openai"`
Logrotate settings.Logrotate `json:"logrotate"`
Nginx settings.Nginx `json:"nginx"`
Oidc settings.OIDC `json:"oidc"`
}
if !cosy.BindAndValid(c, &json) {
@@ -130,6 +132,7 @@ func SaveSettings(c *gin.Context) {
cSettings.ProtectedFill(settings.OpenAISettings, &json.Openai)
cSettings.ProtectedFill(settings.LogrotateSettings, &json.Logrotate)
cSettings.ProtectedFill(settings.NginxSettings, &json.Nginx)
cSettings.ProtectedFill(settings.OIDCSettings, &json.Oidc)
err := settings.Save()
if err != nil {
+207
View File
@@ -0,0 +1,207 @@
package user
import (
"context"
"crypto/rand"
"encoding/hex"
"errors"
"net/http"
"strings"
"github.com/0xJacky/Nginx-UI/internal/user"
"github.com/0xJacky/Nginx-UI/settings"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/gin-gonic/gin"
"github.com/uozi-tech/cosy"
cSettings "github.com/uozi-tech/cosy/settings"
"golang.org/x/oauth2"
"gorm.io/gorm"
)
type OIDCLoginUser struct {
Code string `json:"code" binding:"required,max=255"`
State string `json:"state" binding:"required,max=255"`
}
func OIDCCallback(c *gin.Context) {
var loginUser OIDCLoginUser
ok := cosy.BindAndValid(c, &loginUser)
if !ok {
return
}
state, err := c.Cookie("oidc_state")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"message": "State cookie not found",
})
return
}
if state != loginUser.State {
c.JSON(http.StatusForbidden, gin.H{
"message": "State mismatch",
})
return
}
c.SetCookie("oidc_state", "", -1, "/", "", cSettings.ServerSettings.EnableHTTPS, true)
endpoint := settings.OIDCSettings.Endpoint
clientId := settings.OIDCSettings.ClientId
clientSecret := settings.OIDCSettings.ClientSecret
redirectUri := settings.OIDCSettings.RedirectUri
if endpoint == "" || clientId == "" || clientSecret == "" || redirectUri == "" {
c.JSON(http.StatusInternalServerError, gin.H{
"message": "OIDC is not configured",
})
return
}
ctx := context.Background()
provider, err := oidc.NewProvider(ctx, endpoint)
if err != nil {
cosy.ErrHandler(c, err)
return
}
scopes := []string{oidc.ScopeOpenID, "profile", "email"}
if settings.OIDCSettings.Scopes != "" {
scopes = strings.Split(settings.OIDCSettings.Scopes, " ")
}
oauth2Config := oauth2.Config{
ClientID: clientId,
ClientSecret: clientSecret,
RedirectURL: redirectUri,
Endpoint: provider.Endpoint(),
Scopes: scopes,
}
oauth2Token, err := oauth2Config.Exchange(ctx, loginUser.Code)
if err != nil {
cosy.ErrHandler(c, err)
return
}
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
if !ok {
c.JSON(http.StatusInternalServerError, gin.H{
"message": "No id_token field in oauth2 token",
})
return
}
idTokenVerifier := provider.Verifier(&oidc.Config{ClientID: clientId})
idToken, err := idTokenVerifier.Verify(ctx, rawIDToken)
if err != nil {
cosy.ErrHandler(c, err)
return
}
var claims map[string]interface{}
if err := idToken.Claims(&claims); err != nil {
cosy.ErrHandler(c, err)
return
}
var username string
if settings.OIDCSettings.Identifier != "" {
if v, ok := claims[settings.OIDCSettings.Identifier]; ok {
username, _ = v.(string)
}
}
if username == "" {
if v, ok := claims["email"]; ok {
username, _ = v.(string)
}
}
if username == "" {
if v, ok := claims["name"]; ok {
username, _ = v.(string)
}
}
if username == "" {
if v, ok := claims["sub"]; ok {
username, _ = v.(string)
}
}
u, err := user.GetUser(username)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
c.JSON(http.StatusForbidden, gin.H{
"message": "User not exist",
})
} else {
cosy.ErrHandler(c, err)
}
return
}
userToken, err := user.GenerateJWT(u)
if err != nil {
cosy.ErrHandler(c, err)
return
}
c.JSON(http.StatusOK, LoginResponse{
Message: "ok",
AccessTokenPayload: userToken,
})
}
func GetOIDCUri(c *gin.Context) {
endpoint := settings.OIDCSettings.Endpoint
clientId := settings.OIDCSettings.ClientId
redirectUri := settings.OIDCSettings.RedirectUri
scopes := settings.OIDCSettings.Scopes
if endpoint == "" || clientId == "" || redirectUri == "" {
c.JSON(http.StatusOK, gin.H{
"uri": "",
})
return
}
ctx := context.Background()
provider, err := oidc.NewProvider(ctx, endpoint)
if err != nil {
cosy.ErrHandler(c, err)
return
}
scopeList := []string{oidc.ScopeOpenID, "profile", "email"}
if scopes != "" {
scopeList = strings.Split(scopes, " ")
}
oauth2Config := oauth2.Config{
ClientID: clientId,
RedirectURL: redirectUri,
Endpoint: provider.Endpoint(),
Scopes: scopeList,
}
b := make([]byte, 16)
_, err = rand.Read(b)
if err != nil {
cosy.ErrHandler(c, err)
return
}
state := "nginx-ui-oidc_" + hex.EncodeToString(b)
c.SetCookie("oidc_state", state, 300, "/", "", cSettings.ServerSettings.EnableHTTPS, true)
c.JSON(http.StatusOK, gin.H{
"uri": oauth2Config.AuthCodeURL(state),
})
}
+3
View File
@@ -15,6 +15,9 @@ func InitAuthRouter(r *gin.RouterGroup) {
r.GET("/casdoor_uri", GetCasdoorUri)
r.POST("/casdoor_callback", CasdoorCallback)
r.GET("/oidc_uri", GetOIDCUri)
r.POST("/oidc_callback", OIDCCallback)
r.GET("/passkeys/config", GetPasskeyConfigStatus)
}
+8
View File
@@ -27,6 +27,14 @@ Organization =
Application =
RedirectUri =
[oidc]
ClientId =
ClientSecret =
Endpoint =
RedirectUri =
Scopes =
Identifier =
[cert]
Email =
CADir =
+12
View File
@@ -31,6 +31,15 @@ const auth = {
login(r.token, r.short_token)
})
},
async oidc_login(code?: string, state?: string) {
await http.post('/oidc_callback', {
code,
state,
})
.then((r: AuthResponse) => {
login(r.token, r.short_token)
})
},
async logout() {
return http.delete('/logout').then(async () => {
logout()
@@ -39,6 +48,9 @@ const auth = {
async get_casdoor_uri(): Promise<{ uri: string }> {
return http.get('/casdoor_uri')
},
async get_oidc_uri(): Promise<{ uri: string }> {
return http.get('/oidc_uri')
},
begin_passkey_login() {
return http.get('/begin_passkey_login')
},
+10
View File
@@ -110,12 +110,22 @@ export interface BannedIP {
expired_at: string
}
export interface OIDCSettings {
client_id: string
client_secret: string
endpoint: string
redirect_uri: string
scopes: string
identifier: string
}
export interface Settings {
app: AppSettings
server: ServerSettings
database: DatabaseSettings
auth: AuthSettings
casdoor: CasdoorSettings
oidc: OIDCSettings
cert: CertSettings
http: HTTPSettings
logrotate: LogrotateSettings
+49 -6
View File
@@ -134,6 +134,11 @@ async function handleLoginSuccess(options: LoginSuccessOptions = {}) {
await settingsStore.set_language(userStore.info?.language)
}
if (window.location.search) {
const newUrl = window.location.pathname + window.location.hash
window.history.replaceState(null, '', newUrl)
}
const next = (route.query?.next || '').toString() || '/'
await router.push(next)
}
@@ -187,17 +192,46 @@ auth.get_casdoor_uri()
}
})
const has_oidc = ref(false)
const oidc_uri = ref('')
auth.get_oidc_uri()
.then(r => {
if (r?.uri) {
has_oidc.value = true
oidc_uri.value = r.uri
}
})
function loginWithCasdoor() {
window.location.href = casdoor_uri.value
}
if (route.query?.code !== undefined && route.query?.state !== undefined) {
function loginWithOIDC() {
window.location.href = oidc_uri.value
}
const searchParams = new URLSearchParams(window.location.search)
const query = route.query
const code = query?.code?.toString() ?? searchParams.get('code')
const state = query?.state?.toString() ?? searchParams.get('state')
if (code && state) {
loading.value = true
auth.casdoor_login(route.query?.code?.toString(), route.query?.state?.toString()).then(async () => {
await handleLoginSuccess()
}).finally(() => {
loading.value = false
})
if (state.startsWith('nginx-ui-oidc_')) {
auth.oidc_login(code, state).then(async () => {
await handleLoginSuccess()
}).finally(() => {
loading.value = false
})
}
else {
auth.casdoor_login(code, state).then(async () => {
await handleLoginSuccess()
}).finally(() => {
loading.value = false
})
}
}
function handleOTPSubmit(code: string, recovery: string) {
@@ -291,6 +325,15 @@ async function handlePasskeyLogin() {
>
{{ $gettext('SSO Login') }}
</AButton>
<AButton
v-if="has_oidc"
block
:loading="loading"
class="mb-5"
@click="loginWithOIDC"
>
{{ $gettext('OIDC Login') }}
</AButton>
</template>
<div v-else>
<Authorization
+8
View File
@@ -38,6 +38,14 @@ const useSystemSettingsStore = defineStore('systemSettings', () => {
application: '',
redirect_uri: '',
},
oidc: {
client_id: '',
client_secret: '',
endpoint: '',
redirect_uri: '',
scopes: '',
identifier: '',
},
cert: {
email: '',
ca_dir: '',
+10
View File
@@ -42,6 +42,16 @@ Applicable for version v2.0.0-beta.37 and above.
| Application | NGINX_UI_CASDOOR_APPLICATION |
| RedirectUri | NGINX_UI_CASDOOR_REDIRECT_URI |
## Oidc
| Configuration Setting | Environment Variable |
|-----------------------|-----------------------------|
| Endpoint | NGINX_UI_OIDC_ENDPOINT |
| ClientId | NGINX_UI_OIDC_CLIENT_ID |
| ClientSecret | NGINX_UI_OIDC_CLIENT_SECRET |
| RedirectUri | NGINX_UI_OIDC_REDIRECT_URI |
| Scopes | NGINX_UI_OIDC_SCOPES |
| Identifier | NGINX_UI_OIDC_IDENTIFIER |
## Cert
| Configuration Setting | Environment Variable |
|-----------------------|-------------------------------------|
+11
View File
@@ -46,6 +46,17 @@
| Application | NGINX_UI_CASDOOR_APPLICATION |
| RedirectUri | NGINX_UI_CASDOOR_REDIRECT_URI |
## Oidc
| 配置 | 环境变量 |
|-----------------|-----------------------------|
| Endpoint | NGINX_UI_OIDC_ENDPOINT |
| ClientId | NGINX_UI_OIDC_CLIENT_ID |
| ClientSecret | NGINX_UI_OIDC_CLIENT_SECRET |
| RedirectUri | NGINX_UI_OIDC_REDIRECT_URI |
| Scopes | NGINX_UI_OIDC_SCOPES |
| Identifier | NGINX_UI_OIDC_IDENTIFIER |
## Cert
| 配置 | 环境变量 |
+11
View File
@@ -46,6 +46,17 @@
| Application | NGINX_UI_CASDOOR_APPLICATION |
| RedirectUri | NGINX_UI_CASDOOR_REDIRECT_URI |
## Oidc
| 設定 | 環境變數 |
|-----------------|-----------------------------|
| Endpoint | NGINX_UI_OIDC_ENDPOINT |
| ClientId | NGINX_UI_OIDC_CLIENT_ID |
| ClientSecret | NGINX_UI_OIDC_CLIENT_SECRET |
| RedirectUri | NGINX_UI_OIDC_REDIRECT_URI |
| Scopes | NGINX_UI_OIDC_SCOPES |
| Identifier | NGINX_UI_OIDC_IDENTIFIER |
## Cert
| 設定 | 環境變數 |
+2 -1
View File
@@ -14,6 +14,7 @@ require (
github.com/caarlos0/env/v11 v11.3.1
github.com/casdoor/casdoor-go-sdk v1.40.0
github.com/cloudflare/cloudflare-go/v6 v6.4.0
github.com/coreos/go-oidc/v3 v3.17.0
github.com/creack/pty v1.1.24
github.com/dgraph-io/ristretto/v2 v2.3.0
github.com/docker/docker v28.5.2+incompatible
@@ -58,6 +59,7 @@ require (
github.com/urfave/cli/v3 v3.6.1
golang.org/x/crypto v0.46.0
golang.org/x/net v0.48.0
golang.org/x/oauth2 v0.33.0
google.golang.org/grpc v1.77.0
gopkg.in/ini.v1 v1.67.0
gorm.io/datatypes v1.2.7
@@ -353,7 +355,6 @@ require (
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/arch v0.23.0 // indirect
golang.org/x/mod v0.30.0 // indirect
golang.org/x/oauth2 v0.33.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
+6 -33
View File
@@ -738,15 +738,12 @@ github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/Ke
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
github.com/alibabacloud-go/tea v1.3.13 h1:WhGy6LIXaMbBM6VBYcsDCz6K/TPsT1Ri2hPmmZffZ94=
github.com/alibabacloud-go/tea v1.3.13/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
github.com/alibabacloud-go/tea v1.3.14 h1:/Uzj5ZCFPpbPR+Bs7jfzsyXkYIVsi5TOIuQNOWwc/9c=
github.com/alibabacloud-go/tea v1.3.14/go.mod h1:A560v/JTQ1n5zklt2BEpurJzZTI8TUT+Psg2drWlxRg=
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
github.com/alibabacloud-go/tea-utils/v2 v2.0.8 h1:3Xc2aQY8g6gXoNufwOXdLk8a9Zeks4FewXH1wlV69gI=
github.com/alibabacloud-go/tea-utils/v2 v2.0.8/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
github.com/alibabacloud-go/tea-utils/v2 v2.0.9 h1:y6pUIlhjxbZl9ObDAcmA1H3c21eaAxADHTDQmBnAIgA=
github.com/alibabacloud-go/tea-utils/v2 v2.0.9/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
github.com/aliyun/aliyun-log-go-sdk v0.1.112 h1:g17aXc1AN5emfp0tqHumOZqMBkm4Eix3kKVD8hwHsW4=
@@ -889,8 +886,6 @@ github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdf
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/casdoor/casdoor-go-sdk v1.39.0 h1:jo8pDi4Ue2Qdivps3Gs1l4DWBX1Z8zVps04ZaMTHM9Q=
github.com/casdoor/casdoor-go-sdk v1.39.0/go.mod h1:hVSgmSdwTCsBEJNt9r2K5aLVsoeMc37/N4Zzescy5SA=
github.com/casdoor/casdoor-go-sdk v1.40.0 h1:2CsrCqhgE2ln/swon1IN70l+dPE4paE1cBjWREmtv30=
github.com/casdoor/casdoor-go-sdk v1.40.0/go.mod h1:hVSgmSdwTCsBEJNt9r2K5aLVsoeMc37/N4Zzescy5SA=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
@@ -945,6 +940,8 @@ github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc=
github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@@ -1041,8 +1038,6 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gabriel-vasile/mimetype v1.4.11 h1:AQvxbp830wPhHTqc1u7nzoLT+ZFxGY7emj5DR5DYFik=
github.com/gabriel-vasile/mimetype v1.4.11/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw=
github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
@@ -1068,8 +1063,6 @@ github.com/go-acme/tencentclouddnspod v1.1.25/go.mod h1:XXfzp0AYV7UAUsHKT6R0KAUJ
github.com/go-acme/tencentedgdeone v1.1.48 h1:WLyLBsRVhSLFmtbEFXk0naLODSQn7X6J0Fc/qR8xVUk=
github.com/go-acme/tencentedgdeone v1.1.48/go.mod h1:mu6tA+bPhlSd+CKUfzRikE0mfxmTlBI6dVTn9LY9dRI=
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
github.com/go-co-op/gocron/v2 v2.18.2 h1:+5VU41FUXPWSPKLXZQ/77SGzUiPCcakU0v7ENc2H20Q=
github.com/go-co-op/gocron/v2 v2.18.2/go.mod h1:Zii6he+Zfgy5W9B+JKk/KwejFOW0kZTFvHtwIpR4aBI=
github.com/go-co-op/gocron/v2 v2.19.0 h1:OKf2y6LXPs/BgBI2fl8PxUpNAI1DA9Mg+hSeGOS38OU=
github.com/go-co-op/gocron/v2 v2.19.0/go.mod h1:5lEiCKk1oVJV39Zg7/YG10OnaVrDAV5GGR6O0663k6U=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
@@ -1130,8 +1123,6 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
github.com/go-playground/validator/v10 v10.29.0 h1:lQlF5VNJWNlRbRZNeOIkWElR+1LL/OuHcc0Kp14w1xk=
github.com/go-playground/validator/v10 v10.29.0/go.mod h1:D6QxqeMlgIPuT02L66f2ccrZ7AGgHkzKmmTMZhk/Kc4=
github.com/go-resty/resty/v2 v2.17.0 h1:pW9DeXcaL4Rrym4EZ8v7L19zZiIlWPg5YXAcVmt+gN0=
@@ -1547,6 +1538,8 @@ github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA=
github.com/lestrrat-go/strftime v1.1.1 h1:zgf8QCsgj27GlKBy3SU9/8MMgegZ8UCzlCyHYrUF0QU=
@@ -1994,17 +1987,9 @@ github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQ
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.1.25/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.1.48/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.7/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.8 h1:DdeB0VtEs8UmJSPdNCTeqMW5ifX3Phlvu0o0WJXZ6yE=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.8/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.10 h1:TJqvZJmxfU/SsM+kdqFNpBMJFuyMMPpYx8P+8FdaCSI=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.10/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.11 h1:pexLAyZVjVcxS8dmGY5qtiYyXZ68vKUmKPamMqsAoso=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.11/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.12 h1:/ABtv4x4FSGxGW0d6Sc88iQn6Up2LalWKwt/Tj7Dtz8=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.3.12/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.3.7 h1:lbQreENxWLI6SeKbjvbKnTgMsBPGaFeJ0OYX74utwxA=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.3.7/go.mod h1:+wjQc7L2X9CUvczJ+2pAdZiv8teqkrCfBD2x1vpKWhw=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.3.8 h1:U9bSkvKY/EalAWt7iymCCLuGbTAWxcS7UJAzS3NSfaE=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.3.8/go.mod h1:2qr7BDm+5FNTxTmWzcvoZuJndLByhQGh+FkqmTSu8ew=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@@ -2048,8 +2033,6 @@ github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ultradns/ultradns-go-sdk v1.8.1-20250722213956-faef419 h1:/VaznPrb/b68e3iMvkr27fU7JqPKU4j7tIITZnjQX1k=
github.com/ultradns/ultradns-go-sdk v1.8.1-20250722213956-faef419/go.mod h1:QN0/PdenvYWB0GRMz6JJbPeZz2Lph2iys1p8AFVHm2c=
github.com/uozi-tech/cosy v1.27.7 h1:eWJnPwiLQkgYrxdFJ42Isfc+drIV8Nz8QEs09DMcDYU=
github.com/uozi-tech/cosy v1.27.7/go.mod h1:dCaZpbpw/RXLNuonmYZ8WyPbpdvND8GBur2qxoOnQRI=
github.com/uozi-tech/cosy v1.27.9 h1:jUQsxWf6mVy9Yx/tTN32F8I4OFc1ArApRJaHmrbKRls=
github.com/uozi-tech/cosy v1.27.9/go.mod h1:2G79V3ntkKHQBXTEbV+mQ+neOiiuASd6KOdvJCgmUHE=
github.com/uozi-tech/cosy-driver-mysql v0.2.2 h1:22S/XNIvuaKGqxQPsYPXN8TZ8hHjCQdcJKVQ83Vzxoo=
@@ -2232,8 +2215,6 @@ golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZP
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -2385,8 +2366,6 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -2439,8 +2418,6 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -2571,8 +2548,6 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
@@ -2596,8 +2571,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -2619,8 +2594,6 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+12
View File
@@ -0,0 +1,12 @@
package settings
type OIDC struct {
ClientId string `json:"client_id" protected:"true"`
ClientSecret string `json:"client_secret" protected:"true"`
Endpoint string `json:"endpoint" protected:"true"`
RedirectUri string `json:"redirect_uri" protected:"true"`
Scopes string `json:"scopes" protected:"true"`
Identifier string `json:"identifier" protected:"true"`
}
var OIDCSettings = &OIDC{}
+2
View File
@@ -40,6 +40,7 @@ var envPrefixMap = map[string]interface{}{
"TERMINAL": TerminalSettings,
"WEBAUTHN": WebAuthnSettings,
"BACKUP": BackupSettings,
"OIDC": OIDCSettings,
}
func init() {
@@ -50,6 +51,7 @@ func init() {
sections.Set("auth", AuthSettings)
sections.Set("backup", BackupSettings)
sections.Set("casdoor", CasdoorSettings)
sections.Set("oidc", OIDCSettings)
sections.Set("cert", CertSettings)
sections.Set("cluster", ClusterSettings)
sections.Set("crypto", CryptoSettings)
+19 -2
View File
@@ -1,10 +1,11 @@
package settings
import (
"github.com/stretchr/testify/assert"
cSettings "github.com/uozi-tech/cosy/settings"
"os"
"testing"
"github.com/stretchr/testify/assert"
cSettings "github.com/uozi-tech/cosy/settings"
)
func TestSetup(t *testing.T) {
@@ -36,6 +37,14 @@ func TestSetup(t *testing.T) {
_ = os.Setenv("NGINX_UI_CASDOOR_APPLICATION", "app1")
_ = os.Setenv("NGINX_UI_CASDOOR_REDIRECT_URI", "https://redirect.example.com")
// Oidc
_ = os.Setenv("NGINX_UI_OIDC_CLIENT_ID", "clientId")
_ = os.Setenv("NGINX_UI_OIDC_CLIENT_SECRET", "clientSecret")
_ = os.Setenv("NGINX_UI_OIDC_ENDPOINT", "https://casdoor.example.com/oidc")
_ = os.Setenv("NGINX_UI_OIDC_REDIRECT_URI", "https://redirect.example.com")
_ = os.Setenv("NGINX_UI_OIDC_SCOPES", "openid profile email username")
_ = os.Setenv("NGINX_UI_OIDC_IDENTIFIER", "username")
// Cert
_ = os.Setenv("NGINX_UI_CERT_EMAIL", "test")
_ = os.Setenv("NGINX_UI_CERT_CA_DIR", "/test/ca")
@@ -118,6 +127,14 @@ func TestSetup(t *testing.T) {
assert.Equal(t, "app1", CasdoorSettings.Application)
assert.Equal(t, "https://redirect.example.com", CasdoorSettings.RedirectUri)
// Oidc
assert.Equal(t, "clientId", OIDCSettings.ClientId)
assert.Equal(t, "clientSecret", OIDCSettings.ClientSecret)
assert.Equal(t, "https://casdoor.example.com/oidc", OIDCSettings.Endpoint)
assert.Equal(t, "https://redirect.example.com", OIDCSettings.RedirectUri)
assert.Equal(t, "openid profile email username", OIDCSettings.Scopes)
assert.Equal(t, "username", OIDCSettings.Identifier)
// Cert
assert.Equal(t, "test", CertSettings.Email)
assert.Equal(t, "1080", CertSettings.HTTPChallengePort)