forked from casdoor/casdoor
Compare commits
5 Commits
custom
...
copilot/su
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5483b40a88 | ||
|
|
4516101db6 | ||
|
|
a849203e4b | ||
|
|
3b4485ae24 | ||
|
|
8b78b9909c |
@@ -118,6 +118,7 @@ p, *, *, GET, /api/run-casbin-command, *, *
|
||||
p, *, *, POST, /api/refresh-engines, *, *
|
||||
p, *, *, GET, /api/get-invitation-info, *, *
|
||||
p, *, *, GET, /api/faceid-signin-begin, *, *
|
||||
p, *, *, GET, /api/kerberos-login, *, *
|
||||
`
|
||||
|
||||
sa := stringadapter.NewAdapter(ruleText)
|
||||
|
||||
123
controllers/kerberos.go
Normal file
123
controllers/kerberos.go
Normal file
@@ -0,0 +1,123 @@
|
||||
// Copyright 2025 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/casdoor/casdoor/form"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
// GetKerberosLogin
|
||||
// @Title GetKerberosLogin
|
||||
// @Tag Login API
|
||||
// @Description perform Integrated Windows Authentication (IWA) via Kerberos SPNEGO
|
||||
// @Param applicationName query string true "name of the application"
|
||||
// @Param redirectUri query string false "redirect URI after successful login"
|
||||
// @Success 200 {object} controllers.Response The Response object
|
||||
// @router /api/kerberos-login [get]
|
||||
func (c *ApiController) GetKerberosLogin() {
|
||||
applicationName := c.Ctx.Input.Query("application")
|
||||
responseType := c.Ctx.Input.Query("responseType")
|
||||
clientId := c.Ctx.Input.Query("clientId")
|
||||
redirectUri := c.Ctx.Input.Query("redirectUri")
|
||||
|
||||
application, err := object.GetApplication(fmt.Sprintf("admin/%s", applicationName))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if application == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), applicationName))
|
||||
return
|
||||
}
|
||||
|
||||
if !application.IsKerberosEnabled() {
|
||||
c.ResponseError(c.T("auth:The login method: login with Kerberos is not enabled for the application"))
|
||||
return
|
||||
}
|
||||
|
||||
// Get organization to access Kerberos config
|
||||
org, err := object.GetOrganization(util.GetId("admin", application.Organization))
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if org == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The organization: %s does not exist"), application.Organization))
|
||||
return
|
||||
}
|
||||
|
||||
// Check for SPNEGO Authorization header
|
||||
authHeader := c.Ctx.Request.Header.Get("Authorization")
|
||||
if authHeader == "" || !strings.HasPrefix(authHeader, "Negotiate ") {
|
||||
// No Kerberos token yet - send 401 challenge to trigger browser negotiation
|
||||
c.Ctx.ResponseWriter.Header().Set("WWW-Authenticate", "Negotiate")
|
||||
c.Ctx.ResponseWriter.WriteHeader(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
// Extract the SPNEGO token from the Authorization header
|
||||
tokenBase64 := strings.TrimPrefix(authHeader, "Negotiate ")
|
||||
|
||||
// Validate the Kerberos token and get the username
|
||||
username, err := object.CheckKerberosToken(org, tokenBase64)
|
||||
if err != nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:Kerberos authentication failed: %s"), err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
// Find the user in the organization
|
||||
user, err := object.GetUserByFields(application.Organization, username)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
if user == nil {
|
||||
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), username))
|
||||
return
|
||||
}
|
||||
|
||||
// Build the AuthForm for the login flow
|
||||
authForm := form.AuthForm{
|
||||
Type: responseType,
|
||||
Application: applicationName,
|
||||
Organization: application.Organization,
|
||||
Username: username,
|
||||
SigninMethod: "Kerberos",
|
||||
ClientId: clientId,
|
||||
RedirectUri: redirectUri,
|
||||
}
|
||||
|
||||
organization, err := object.GetOrganizationByUser(user)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if checkMfaEnable(c, user, organization, "kerberos") {
|
||||
return
|
||||
}
|
||||
|
||||
resp := c.HandleLoggedIn(application, user, &authForm)
|
||||
c.Ctx.Input.SetParam("recordUserId", user.GetId())
|
||||
|
||||
c.Data["json"] = resp
|
||||
c.ServeJSON()
|
||||
}
|
||||
7
go.mod
7
go.mod
@@ -48,6 +48,7 @@ require (
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/hsluoyz/modsecurity-go v0.0.7
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/lestrrat-go/jwx v1.2.29
|
||||
github.com/lib/pq v1.10.9
|
||||
@@ -184,8 +185,14 @@ require (
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/gregdel/pushover v1.3.1 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
|
||||
github.com/jcmturner/gofork v1.7.6 // indirect
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
|
||||
22
go.sum
22
go.sum
@@ -910,6 +910,8 @@ github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWH
|
||||
github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI=
|
||||
github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/corazawaf/coraza-coreruleset v0.0.0-20240226094324-415b1017abdc h1:OlJhrgI3I+FLUCTI3JJW8MoqyM78WbqJjecqMnqG+wc=
|
||||
github.com/corazawaf/coraza-coreruleset v0.0.0-20240226094324-415b1017abdc/go.mod h1:7rsocqNDkTCira5T0M7buoKR2ehh7YZiPkzxRuAgvVU=
|
||||
github.com/corazawaf/coraza/v3 v3.3.3 h1:kqjStHAgWqwP5dh7n0vhTOF0a3t+VikNS/EaMiG0Fhk=
|
||||
github.com/corazawaf/coraza/v3 v3.3.3/go.mod h1:xSaXWOhFMSbrV8qOOfBKAyw3aOqfwaSaOy5BgSF8XlA=
|
||||
github.com/corazawaf/libinjection-go v0.2.2 h1:Chzodvb6+NXh6wew5/yhD0Ggioif9ACrQGR4qjTCs1g=
|
||||
@@ -929,7 +931,6 @@ github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs
|
||||
github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
|
||||
github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -1001,6 +1002,8 @@ github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzP
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
|
||||
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
|
||||
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
|
||||
github.com/franela/goblin v0.0.0-20210519012713-85d372ac71e2/go.mod h1:VzmDKDJVZI3aJmnRI9VjAn9nJ8qPPsN1fqzr9dqInIo=
|
||||
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
@@ -1261,7 +1264,9 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1 h1:LqbZZ9sNMWVjeXS4NN5oVvhMjDyLhmA1LG86oSo+IqY=
|
||||
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
@@ -1293,6 +1298,8 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
@@ -1313,11 +1320,21 @@ github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da h1:FjHUJJ7oBW4G/9
|
||||
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jcchavezs/mergefs v0.1.0 h1:7oteO7Ocl/fnfFMkoVLJxTveCjrsd//UB0j89xmnpec=
|
||||
github.com/jcchavezs/mergefs v0.1.0/go.mod h1:eRLTrsA+vFwQZ48hj8p8gki/5v9C2bFtHH5Mnn4bcGk=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=
|
||||
github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo=
|
||||
github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM=
|
||||
github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o=
|
||||
github.com/jcmturner/gofork v1.7.6 h1:QH0l3hzAU1tfT3rZCnW5zXl+orbkNMMRGJfdJjHVETg=
|
||||
github.com/jcmturner/gofork v1.7.6/go.mod h1:1622LH6i/EZqLloHfE7IeZ0uEJwMSUyQ/nDd82IeqRo=
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o=
|
||||
github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg=
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.2/go.mod h1:sb+Xq/fTY5yktf/VxLsE3wlfPqQjp0aWNYyvBVK62bc=
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh687T8=
|
||||
github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY=
|
||||
github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc=
|
||||
github.com/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko=
|
||||
github.com/jinzhu/configor v1.2.1/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc=
|
||||
@@ -1458,7 +1475,6 @@ github.com/microsoft/go-mssqldb v1.9.0 h1:5Vq+u2f4LDujJNeZn62Z4kBDEC9MjLv0ukRzOu
|
||||
github.com/microsoft/go-mssqldb v1.9.0/go.mod h1:GBbW9ASTiDC+mpgWDGKdm3FnFLTUsLYN3iFL90lQ+PA=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
||||
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
||||
@@ -1556,7 +1572,6 @@ github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZ
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -1873,6 +1888,7 @@ golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
"UserCode Invalid": "Benutzercode ungültig",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "Bezahlter Benutzer %s hat kein aktives oder ausstehendes Abonnement und die Anwendung: %s hat keine Standardpreisgestaltung",
|
||||
"the application for user %s is not found": "Die Anwendung für Benutzer %s wurde nicht gefunden",
|
||||
"the organization: %s is not found": "Die Organisation: %s wurde nicht gefunden"
|
||||
"the organization: %s is not found": "Die Organisation: %s wurde nicht gefunden",
|
||||
"The login method: login with Kerberos is not enabled for the application": "Die Anmeldemethode: Anmelden mit Kerberos ist für die Anwendung nicht aktiviert",
|
||||
"Kerberos authentication failed: %s": "Kerberos-Authentifizierung fehlgeschlagen: %s"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "Service %s und %s stimmen nicht überein"
|
||||
@@ -227,4 +229,4 @@
|
||||
"Found no credentials for this user": "Für diesen Benutzer wurden keine Anmeldeinformationen gefunden",
|
||||
"Please call WebAuthnSigninBegin first": "Bitte rufen Sie zuerst WebAuthnSigninBegin auf"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,9 @@
|
||||
"UserCode Invalid": "UserCode Invalid",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
|
||||
"the application for user %s is not found": "the application for user %s is not found",
|
||||
"the organization: %s is not found": "the organization: %s is not found"
|
||||
"the organization: %s is not found": "the organization: %s is not found",
|
||||
"The login method: login with Kerberos is not enabled for the application": "The login method: login with Kerberos is not enabled for the application",
|
||||
"Kerberos authentication failed: %s": "Kerberos authentication failed: %s"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "Service %s and %s do not match"
|
||||
@@ -227,4 +229,4 @@
|
||||
"Found no credentials for this user": "Found no credentials for this user",
|
||||
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,9 @@
|
||||
"UserCode Invalid": "Código de usuario inválido",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "El usuario de pago %s no tiene una suscripción activa o pendiente y la aplicación %s no tiene precios predeterminados",
|
||||
"the application for user %s is not found": "no se encontró la aplicación para el usuario %s",
|
||||
"the organization: %s is not found": "no se encontró la organización: %s"
|
||||
"the organization: %s is not found": "no se encontró la organización: %s",
|
||||
"The login method: login with Kerberos is not enabled for the application": "El método de inicio de sesión: iniciar sesión con Kerberos no está habilitado para la aplicación",
|
||||
"Kerberos authentication failed: %s": "La autenticación Kerberos falló: %s"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "Los servicios %s y %s no coinciden"
|
||||
@@ -227,4 +229,4 @@
|
||||
"Found no credentials for this user": "No se encontraron credenciales para este usuario",
|
||||
"Please call WebAuthnSigninBegin first": "Por favor, llama primero a WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,9 @@
|
||||
"UserCode Invalid": "Code utilisateur invalide",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "L'utilisateur payant %s n'a pas d'abonnement actif ou en attente et l'application %s n'a pas de tarification par défaut",
|
||||
"the application for user %s is not found": "L'application pour l'utilisateur %s est introuvable",
|
||||
"the organization: %s is not found": "L'organisation : %s est introuvable"
|
||||
"the organization: %s is not found": "L'organisation : %s est introuvable",
|
||||
"The login method: login with Kerberos is not enabled for the application": "La méthode de connexion : connexion avec Kerberos n'est pas activée pour l'application",
|
||||
"Kerberos authentication failed: %s": "Échec de l'authentification Kerberos: %s"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "Les services %s et %s ne correspondent pas"
|
||||
@@ -227,4 +229,4 @@
|
||||
"Found no credentials for this user": "Aucune information d'identification trouvée pour cet utilisateur",
|
||||
"Please call WebAuthnSigninBegin first": "Veuillez d'abord appeler WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,9 @@
|
||||
"UserCode Invalid": "ユーザーコードが無効です",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "有料ユーザー「%s」には有効または保留中のサブスクリプションがなく、アプリケーション「%s」にはデフォルトの価格設定がありません",
|
||||
"the application for user %s is not found": "ユーザー「%s」のアプリケーションが見つかりません",
|
||||
"the organization: %s is not found": "組織「%s」が見つかりません"
|
||||
"the organization: %s is not found": "組織「%s」が見つかりません",
|
||||
"The login method: login with Kerberos is not enabled for the application": "ログイン方法: Kerberosでのログインはこのアプリケーションで有効になっていません",
|
||||
"Kerberos authentication failed: %s": "Kerberos認証に失敗しました: %s"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "サービス%sと%sは一致しません"
|
||||
@@ -227,4 +229,4 @@
|
||||
"Found no credentials for this user": "このユーザーの認証情報が見つかりませんでした",
|
||||
"Please call WebAuthnSigninBegin first": "最初にWebAuthnSigninBeginを呼び出してください"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,9 @@
|
||||
"UserCode Invalid": "Nieprawidłowy kod użytkownika",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "płatny użytkownik %s nie ma aktywnej lub oczekującej subskrypcji, a aplikacja: %s nie ma domyślnego cennika",
|
||||
"the application for user %s is not found": "aplikacja dla użytkownika %s nie została znaleziona",
|
||||
"the organization: %s is not found": "organizacja: %s nie została znaleziona"
|
||||
"the organization: %s is not found": "organizacja: %s nie została znaleziona",
|
||||
"The login method: login with Kerberos is not enabled for the application": "Metoda logowania: logowanie przez Kerberos nie jest włączone dla aplikacji",
|
||||
"Kerberos authentication failed: %s": "Uwierzytelnianie Kerberos nie powiodło się: %s"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "Usługa %s i %s nie pasują do siebie"
|
||||
@@ -227,4 +229,4 @@
|
||||
"Found no credentials for this user": "Nie znaleziono danych uwierzytelniających dla tego użytkownika",
|
||||
"Please call WebAuthnSigninBegin first": "Najpierw wywołaj WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,9 @@
|
||||
"UserCode Invalid": "Código de usuário inválido",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "O usuário pago %s não possui assinatura ativa ou pendente e o aplicativo: %s não possui preço padrão",
|
||||
"the application for user %s is not found": "o aplicativo para o usuário %s não foi encontrado",
|
||||
"the organization: %s is not found": "a organização: %s não foi encontrada"
|
||||
"the organization: %s is not found": "a organização: %s não foi encontrada",
|
||||
"The login method: login with Kerberos is not enabled for the application": "O método de login: login com Kerberos não está habilitado para a aplicação",
|
||||
"Kerberos authentication failed: %s": "A autenticação Kerberos falhou: %s"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "O serviço %s e %s não correspondem"
|
||||
@@ -227,4 +229,4 @@
|
||||
"Found no credentials for this user": "Nenhuma credencial encontrada para este usuário",
|
||||
"Please call WebAuthnSigninBegin first": "Por favor, inicie com WebAuthnSigninBegin primeiro"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,9 @@
|
||||
"UserCode Invalid": "Kullanıcı Kodu Geçersiz",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "Ücretli kullanıcı %s aktif veya bekleyen bir aboneliğe sahip değil ve uygulama: %s varsayılan fiyatlandırmaya sahip değil",
|
||||
"the application for user %s is not found": "%s kullanıcısı için uygulama bulunamadı",
|
||||
"the organization: %s is not found": "Organizasyon: %s bulunamadı"
|
||||
"the organization: %s is not found": "Organizasyon: %s bulunamadı",
|
||||
"The login method: login with Kerberos is not enabled for the application": "Giriş yöntemi: Kerberos ile giriş bu uygulama için etkin değil",
|
||||
"Kerberos authentication failed: %s": "Kerberos kimlik doğrulaması başarısız oldu: %s"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "Servis %s ve %s eşleşmiyor"
|
||||
@@ -227,4 +229,4 @@
|
||||
"Found no credentials for this user": "Bu kullanıcı için kimlik bilgisi bulunamadı",
|
||||
"Please call WebAuthnSigninBegin first": "Lütfen önce WebAuthnSigninBegin çağırın"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,9 @@
|
||||
"UserCode Invalid": "UserCode недійсний",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "Користувач %s не має активної або очікуваної підписки, а додаток: %s не має типової ціни",
|
||||
"the application for user %s is not found": "Додаток для користувача %s не знайдено",
|
||||
"the organization: %s is not found": "Організація: %s не знайдена"
|
||||
"the organization: %s is not found": "Організація: %s не знайдена",
|
||||
"The login method: login with Kerberos is not enabled for the application": "Метод входу: вхід за допомогою Kerberos не увімкнено для цього застосунку",
|
||||
"Kerberos authentication failed: %s": "Помилка автентифікації Kerberos: %s"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "Сервіс %s і %s не збігаються"
|
||||
@@ -227,4 +229,4 @@
|
||||
"Found no credentials for this user": "Облікові дані для цього користувача не знайдено",
|
||||
"Please call WebAuthnSigninBegin first": "Спочатку викличте WebAuthnSigninBegin"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,9 @@
|
||||
"UserCode Invalid": "Mã người dùng không hợp lệ",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "người dùng trả phí %s không có đăng ký đang hoạt động hoặc đang chờ và ứng dụng: %s không có giá mặc định",
|
||||
"the application for user %s is not found": "không tìm thấy ứng dụng cho người dùng %s",
|
||||
"the organization: %s is not found": "không tìm thấy tổ chức: %s"
|
||||
"the organization: %s is not found": "không tìm thấy tổ chức: %s",
|
||||
"The login method: login with Kerberos is not enabled for the application": "Phương thức đăng nhập: đăng nhập bằng Kerberos không được bật cho ứng dụng này",
|
||||
"Kerberos authentication failed: %s": "Xác thực Kerberos thất bại: %s"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "Dịch sang tiếng Việt: Dịch vụ %s và %s không khớp"
|
||||
@@ -227,4 +229,4 @@
|
||||
"Found no credentials for this user": "Không tìm thấy thông tin xác thực cho người dùng này",
|
||||
"Please call WebAuthnSigninBegin first": "Vui lòng gọi WebAuthnSigninBegin trước"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,9 @@
|
||||
"UserCode Invalid": "用户代码无效",
|
||||
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "付费用户 %s 没有激活或待处理的订阅,且应用 %s 没有默认定价",
|
||||
"the application for user %s is not found": "未找到用户 %s 的应用程序",
|
||||
"the organization: %s is not found": "组织: %s 不存在"
|
||||
"the organization: %s is not found": "组织: %s 不存在",
|
||||
"The login method: login with Kerberos is not enabled for the application": "应用程序未启用 Kerberos 登录方式",
|
||||
"Kerberos authentication failed: %s": "Kerberos 认证失败:%s"
|
||||
},
|
||||
"cas": {
|
||||
"Service %s and %s do not match": "服务%s与%s不匹配"
|
||||
@@ -227,4 +229,4 @@
|
||||
"Found no credentials for this user": "无法找到此用户的证书",
|
||||
"Please call WebAuthnSigninBegin first": "请先调用WebAuthnSigninBegin函数"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -943,6 +943,17 @@ func (application *Application) IsFaceIdEnabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (application *Application) IsKerberosEnabled() bool {
|
||||
if len(application.SigninMethods) > 0 {
|
||||
for _, signinMethod := range application.SigninMethods {
|
||||
if signinMethod.Name == "Kerberos" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func IsOriginAllowed(origin string) (bool, error) {
|
||||
applications, err := GetApplications("")
|
||||
if err != nil {
|
||||
|
||||
93
object/kerberos.go
Normal file
93
object/kerberos.go
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright 2025 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package object
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/jcmturner/gokrb5/v8/credentials"
|
||||
"github.com/jcmturner/gokrb5/v8/gssapi"
|
||||
"github.com/jcmturner/gokrb5/v8/keytab"
|
||||
"github.com/jcmturner/gokrb5/v8/service"
|
||||
"github.com/jcmturner/gokrb5/v8/spnego"
|
||||
)
|
||||
|
||||
// ctxKeyKerberosCreds is the context key used by gokrb5 to store credentials.
|
||||
// This matches the unexported constant in the spnego package.
|
||||
const ctxKeyKerberosCreds = "github.com/jcmturner/gokrb5/v8/ctxCredentials"
|
||||
|
||||
// CheckKerberosToken validates a SPNEGO/Kerberos token and returns the authenticated username.
|
||||
// The token is the base64-encoded value from the "Authorization: Negotiate <token>" header.
|
||||
// Returns the username (without realm) on success, or an error on failure.
|
||||
func CheckKerberosToken(org *Organization, tokenBase64 string) (string, error) {
|
||||
if org.KerberosKeytab == "" {
|
||||
return "", fmt.Errorf("Kerberos keytab is not configured for organization: %s", org.Name)
|
||||
}
|
||||
|
||||
// Decode the base64 keytab
|
||||
keytabBytes, err := base64.StdEncoding.DecodeString(org.KerberosKeytab)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to decode Kerberos keytab: %v", err)
|
||||
}
|
||||
|
||||
// Load the keytab
|
||||
kt := keytab.New()
|
||||
if err = kt.Unmarshal(keytabBytes); err != nil {
|
||||
return "", fmt.Errorf("failed to parse Kerberos keytab: %v", err)
|
||||
}
|
||||
|
||||
// Decode the SPNEGO token from base64
|
||||
tokenBytes, err := base64.StdEncoding.DecodeString(tokenBase64)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to decode Kerberos token: %v", err)
|
||||
}
|
||||
|
||||
// Create SPNEGO service using the keytab
|
||||
settings := []func(*service.Settings){}
|
||||
if org.KerberosServiceName != "" {
|
||||
settings = append(settings, service.SName(org.KerberosServiceName))
|
||||
}
|
||||
s := spnego.SPNEGOService(kt, settings...)
|
||||
|
||||
// Unmarshal the SPNEGO token
|
||||
var st spnego.SPNEGOToken
|
||||
if err = st.Unmarshal(tokenBytes); err != nil {
|
||||
return "", fmt.Errorf("failed to parse SPNEGO token: %v", err)
|
||||
}
|
||||
|
||||
// Validate the token
|
||||
authed, ctx, status := s.AcceptSecContext(&st)
|
||||
if status.Code != gssapi.StatusComplete && status.Code != gssapi.StatusContinueNeeded {
|
||||
return "", fmt.Errorf("Kerberos authentication failed: %s", status.Message)
|
||||
}
|
||||
if !authed {
|
||||
return "", fmt.Errorf("Kerberos authentication rejected")
|
||||
}
|
||||
|
||||
// Extract credentials from context using the gokrb5 internal key
|
||||
creds, ok := ctx.Value(ctxKeyKerberosCreds).(*credentials.Credentials)
|
||||
if !ok || creds == nil {
|
||||
return "", fmt.Errorf("failed to extract credentials from Kerberos context")
|
||||
}
|
||||
|
||||
username := creds.UserName()
|
||||
// Strip realm suffix if present (e.g., "user@REALM.COM" → "user")
|
||||
if idx := strings.Index(username, "@"); idx != -1 {
|
||||
username = username[:idx]
|
||||
}
|
||||
return username, nil
|
||||
}
|
||||
@@ -98,6 +98,11 @@ type Organization struct {
|
||||
UserBalance float64 `json:"userBalance"`
|
||||
BalanceCredit float64 `json:"balanceCredit"`
|
||||
BalanceCurrency string `xorm:"varchar(100)" json:"balanceCurrency"`
|
||||
|
||||
KerberosRealm string `xorm:"varchar(100)" json:"kerberosRealm"`
|
||||
KerberosKdcHost string `xorm:"varchar(100)" json:"kerberosKdcHost"`
|
||||
KerberosKeytab string `xorm:"mediumtext" json:"kerberosKeytab"`
|
||||
KerberosServiceName string `xorm:"varchar(200)" json:"kerberosServiceName"`
|
||||
}
|
||||
|
||||
func GetOrganizationCount(owner, name, field, value string) (int64, error) {
|
||||
|
||||
@@ -64,6 +64,7 @@ func InitAPI() {
|
||||
web.Router("/api/get-captcha-status", &controllers.ApiController{}, "GET:GetCaptchaStatus")
|
||||
web.Router("/api/callback", &controllers.ApiController{}, "POST:Callback")
|
||||
web.Router("/api/device-auth", &controllers.ApiController{}, "POST:DeviceAuth")
|
||||
web.Router("/api/kerberos-login", &controllers.ApiController{}, "GET:GetKerberosLogin")
|
||||
|
||||
web.Router("/api/get-organizations", &controllers.ApiController{}, "GET:GetOrganizations")
|
||||
web.Router("/api/get-organization", &controllers.ApiController{}, "GET:GetOrganization")
|
||||
|
||||
@@ -1673,7 +1673,7 @@ class ApplicationEditPage extends React.Component {
|
||||
submitApplicationEdit(exitAfterSave) {
|
||||
const application = Setting.deepCopy(this.state.application);
|
||||
application.providers = application.providers?.filter(provider => this.state.providers.map(provider => provider.name).includes(provider.name));
|
||||
application.signinMethods = application.signinMethods?.filter(signinMethod => ["Password", "Verification code", "WebAuthn", "LDAP", "Face ID", "WeChat"].includes(signinMethod.name));
|
||||
application.signinMethods = application.signinMethods?.filter(signinMethod => ["Password", "Verification code", "WebAuthn", "LDAP", "Kerberos", "Face ID", "WeChat"].includes(signinMethod.name));
|
||||
const customScopeValidation = this.validateCustomScopes(application.customScopes);
|
||||
application.customScopes = customScopeValidation.scopes;
|
||||
if (!customScopeValidation.ok) {
|
||||
|
||||
@@ -762,6 +762,46 @@ class OrganizationEditPage extends React.Component {
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("organization:Kerberos realm"), i18next.t("organization:Kerberos realm - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.organization.kerberosRealm} placeholder={"e.g. EXAMPLE.COM"} onChange={e => {
|
||||
this.updateOrganizationField("kerberosRealm", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("organization:Kerberos KDC host"), i18next.t("organization:Kerberos KDC host - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.organization.kerberosKdcHost} placeholder={"e.g. kdc.example.com"} onChange={e => {
|
||||
this.updateOrganizationField("kerberosKdcHost", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("organization:Kerberos service name"), i18next.t("organization:Kerberos service name - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.organization.kerberosServiceName} placeholder={"e.g. HTTP/casdoor.example.com"} onChange={e => {
|
||||
this.updateOrganizationField("kerberosServiceName", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("organization:Kerberos keytab"), i18next.t("organization:Kerberos keytab - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input.TextArea rows={4} value={this.state.organization.kerberosKeytab} placeholder={i18next.t("organization:Kerberos keytab placeholder")} onChange={e => {
|
||||
this.updateOrganizationField("kerberosKeytab", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1476,6 +1476,10 @@ export function isLdapEnabled(application) {
|
||||
return isSigninMethodEnabled(application, "LDAP");
|
||||
}
|
||||
|
||||
export function isKerberosEnabled(application) {
|
||||
return isSigninMethodEnabled(application, "Kerberos");
|
||||
}
|
||||
|
||||
export function isFaceIdEnabled(application) {
|
||||
return isSigninMethodEnabled(application, "Face ID");
|
||||
}
|
||||
|
||||
@@ -131,6 +131,18 @@ export function getSamlLogin(providerId, relayState) {
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function kerberosLogin(values, oAuthParams) {
|
||||
const oAuthQuery = oAuthParamsToQuery(oAuthParams);
|
||||
const separator = oAuthQuery ? "&" : "?";
|
||||
return fetch(`${authConfig.serverUrl}/api/kerberos-login${oAuthQuery}${separator}application=${encodeURIComponent(values["application"])}`, {
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
headers: {
|
||||
"Accept-Language": Setting.getAcceptLanguage(),
|
||||
},
|
||||
}).then(res => res.json());
|
||||
}
|
||||
|
||||
export function loginWithSaml(values, param) {
|
||||
return fetch(`${authConfig.serverUrl}/api/login${param}`, {
|
||||
method: "POST",
|
||||
|
||||
@@ -258,6 +258,7 @@ class LoginPage extends React.Component {
|
||||
case "WebAuthn": return "webAuthn";
|
||||
case "LDAP": return "ldap";
|
||||
case "Face ID": return "faceId";
|
||||
case "Kerberos": return "kerberos";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,6 +274,8 @@ class LoginPage extends React.Component {
|
||||
return "WebAuthn";
|
||||
} else if (this.state.loginMethod === "ldap") {
|
||||
return "LDAP";
|
||||
} else if (this.state.loginMethod === "kerberos") {
|
||||
return "Kerberos";
|
||||
} else if (this.state.loginMethod === "faceId") {
|
||||
return "Face ID";
|
||||
} else {
|
||||
@@ -422,6 +425,10 @@ class LoginPage extends React.Component {
|
||||
this.signInWithWebAuthn(username, values);
|
||||
return;
|
||||
}
|
||||
if (this.state.loginMethod === "kerberos") {
|
||||
this.signInWithKerberos(values);
|
||||
return;
|
||||
}
|
||||
if (this.state.loginMethod === "faceId") {
|
||||
let username = this.state.username;
|
||||
if (username === null || username === "") {
|
||||
@@ -711,6 +718,10 @@ class LoginPage extends React.Component {
|
||||
return (<WeChatLoginPanel application={application} loginMethod={this.state.loginMethod} />);
|
||||
}
|
||||
|
||||
if (this.state.loginMethod === "kerberos") {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.state.loginMethod === "verificationCodePhone") {
|
||||
return <Form.Item className="signin-phone" required={true}>
|
||||
<Input.Group compact>
|
||||
@@ -890,7 +901,8 @@ class LoginPage extends React.Component {
|
||||
{
|
||||
this.state.loginMethod === "webAuthn" ? i18next.t("login:Sign in with WebAuthn") :
|
||||
this.state.loginMethod === "faceId" ? i18next.t("login:Sign in with Face ID") :
|
||||
signinItem.label ? signinItem.label : i18next.t("login:Sign In")
|
||||
this.state.loginMethod === "kerberos" ? i18next.t("login:Sign in with Kerberos") :
|
||||
signinItem.label ? signinItem.label : i18next.t("login:Sign In")
|
||||
}
|
||||
</Button>
|
||||
{
|
||||
@@ -924,7 +936,7 @@ class LoginPage extends React.Component {
|
||||
</Form.Item>
|
||||
);
|
||||
} else if (signinItem.name === "Providers") {
|
||||
const showForm = Setting.isPasswordEnabled(application) || Setting.isCodeSigninEnabled(application) || Setting.isWebAuthnEnabled(application) || Setting.isLdapEnabled(application);
|
||||
const showForm = Setting.isPasswordEnabled(application) || Setting.isCodeSigninEnabled(application) || Setting.isWebAuthnEnabled(application) || Setting.isLdapEnabled(application) || Setting.isKerberosEnabled(application);
|
||||
if (signinItem.rule === "None" || signinItem.rule === "") {
|
||||
signinItem.rule = showForm ? "small" : "big";
|
||||
}
|
||||
@@ -1316,6 +1328,37 @@ class LoginPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
signInWithKerberos(values) {
|
||||
const oAuthParams = Util.getOAuthGetParameters();
|
||||
this.populateOauthValues(values);
|
||||
AuthBackend.kerberosLogin(values, oAuthParams)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
const responseType = values["type"];
|
||||
if (responseType === "login") {
|
||||
Setting.showMessage("success", i18next.t("application:Logged in successfully"));
|
||||
this.props.onLoginSuccess();
|
||||
} else if (responseType === "code") {
|
||||
this.postCodeLoginAction(res);
|
||||
} else if (responseType === "token" || responseType === "id_token") {
|
||||
const accessToken = res.data;
|
||||
Setting.goToLink(`${oAuthParams.redirectUri}#${responseType}=${accessToken}&state=${oAuthParams.state}&token_type=bearer`);
|
||||
} else {
|
||||
Setting.showMessage("success", i18next.t("application:Logged in successfully"));
|
||||
Setting.goToLink("/");
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("application:Failed to sign in")}: ${res.msg}`);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to connect to server")}${error}`);
|
||||
})
|
||||
.finally(() => {
|
||||
this.setState({loginLoading: false});
|
||||
});
|
||||
}
|
||||
|
||||
hasVerificationCodeSigninItem(application) {
|
||||
const targetApp = application || this.getApplicationObj();
|
||||
if (!targetApp || !targetApp.signinItems) {
|
||||
@@ -1417,6 +1460,7 @@ class LoginPage extends React.Component {
|
||||
[generateItemKey("Verification code", "Phone only"), {label: i18next.t("login:Verification code"), key: "verificationCodePhone"}],
|
||||
[generateItemKey("WebAuthn", "None"), {label: i18next.t("login:WebAuthn"), key: "webAuthn"}],
|
||||
[generateItemKey("LDAP", "None"), {label: i18next.t("login:LDAP"), key: "ldap"}],
|
||||
[generateItemKey("Kerberos", "None"), {label: i18next.t("login:Kerberos"), key: "kerberos"}],
|
||||
[generateItemKey("Face ID", "None"), {label: i18next.t("login:Face ID"), key: "faceId"}],
|
||||
[generateItemKey("WeChat", "Tab"), {label: i18next.t("login:WeChat"), key: "wechat"}],
|
||||
[generateItemKey("WeChat", "None"), {label: i18next.t("login:WeChat"), key: "wechat"}],
|
||||
|
||||
@@ -570,7 +570,7 @@
|
||||
"Physical": "Physisch",
|
||||
"Show all": "Alle anzeigen",
|
||||
"Virtual": "Virtuell",
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "Sie müssen zuerst alle Untergruppen löschen. Sie können die Untergruppen im linken Gruppenbaum unter [Organisationen] -\u003e [Gruppen] anzeigen."
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -> [Groups] page": "Sie müssen zuerst alle Untergruppen löschen. Sie können die Untergruppen im linken Gruppenbaum unter [Organisationen] -> [Gruppen] anzeigen."
|
||||
},
|
||||
"home": {
|
||||
"New users past 30 days": "Neue Benutzer der letzten 30 Tage",
|
||||
@@ -686,7 +686,9 @@
|
||||
"WeChat": "WeChat",
|
||||
"WebAuthn": "WebAuthn",
|
||||
"sign up now": "Melde dich jetzt an",
|
||||
"username, Email or phone": "Benutzername, E-Mail oder Telefon"
|
||||
"username, Email or phone": "Benutzername, E-Mail oder Telefon",
|
||||
"Kerberos": "Kerberos",
|
||||
"Sign in with Kerberos": "Mit Windows-Authentifizierung anmelden"
|
||||
},
|
||||
"mfa": {
|
||||
"Each time you sign in to your Account, you'll need your password and a authentication code": "Jedes Mal, wenn Sie sich anmelden, benötigen Sie Ihr Passwort und einen Authentifizierungscode.",
|
||||
@@ -1504,4 +1506,4 @@
|
||||
"Single org only - Tooltip": "Nur in der Organisation auslösen, zu der der Webhook gehört",
|
||||
"Value": "Wert"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@
|
||||
"Physical": "Physical",
|
||||
"Show all": "Show all",
|
||||
"Virtual": "Virtual",
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page"
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -> [Groups] page": "You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -> [Groups] page"
|
||||
},
|
||||
"home": {
|
||||
"New users past 30 days": "New users past 30 days",
|
||||
@@ -686,7 +686,9 @@
|
||||
"WeChat": "WeChat",
|
||||
"WebAuthn": "WebAuthn",
|
||||
"sign up now": "sign up now",
|
||||
"username, Email or phone": "username, Email or phone"
|
||||
"username, Email or phone": "username, Email or phone",
|
||||
"Kerberos": "Kerberos",
|
||||
"Sign in with Kerberos": "Sign in with Windows Authentication"
|
||||
},
|
||||
"mfa": {
|
||||
"Each time you sign in to your Account, you'll need your password and a authentication code": "Each time you sign in to your Account, you'll need your password and a authentication code",
|
||||
@@ -795,7 +797,16 @@
|
||||
"Website URL": "Website URL",
|
||||
"Website URL - Tooltip": "The homepage URL of the organization. This field is not used in Casdoor",
|
||||
"Widget items": "Widget items",
|
||||
"Widget items - Tooltip": "Items displayed in the widget"
|
||||
"Widget items - Tooltip": "Items displayed in the widget",
|
||||
"Kerberos realm": "Kerberos Realm",
|
||||
"Kerberos realm - Tooltip": "The Kerberos realm (Active Directory domain name), e.g. EXAMPLE.COM",
|
||||
"Kerberos KDC host": "KDC Host",
|
||||
"Kerberos KDC host - Tooltip": "The Kerberos Key Distribution Center (KDC) hostname. Leave empty to use DNS discovery.",
|
||||
"Kerberos service name": "Service Principal Name",
|
||||
"Kerberos service name - Tooltip": "The Kerberos Service Principal Name (SPN) for this Casdoor instance, e.g. HTTP/casdoor.example.com",
|
||||
"Kerberos keytab": "Keytab (Base64)",
|
||||
"Kerberos keytab - Tooltip": "The service keytab file encoded in Base64, used to validate Kerberos tokens",
|
||||
"Kerberos keytab placeholder": "Paste the Base64-encoded keytab file content here"
|
||||
},
|
||||
"payment": {
|
||||
"Confirm your invoice information": "Confirm your invoice information",
|
||||
@@ -1504,4 +1515,4 @@
|
||||
"Single org only - Tooltip": "Triggered only in the organization that the webhook belongs to",
|
||||
"Value": "Value"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@
|
||||
"Physical": "Físico",
|
||||
"Show all": "Mostrar todos",
|
||||
"Virtual": "Virtual",
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "Necesitas eliminar todos los subgrupos primero. Puedes ver los subgrupos en el árbol de grupos a la izquierda en la página [Organizaciones] -\u003e [Grupos]"
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -> [Groups] page": "Necesitas eliminar todos los subgrupos primero. Puedes ver los subgrupos en el árbol de grupos a la izquierda en la página [Organizaciones] -> [Grupos]"
|
||||
},
|
||||
"home": {
|
||||
"New users past 30 days": "Nuevos usuarios en los últimos 30 días",
|
||||
@@ -686,7 +686,9 @@
|
||||
"WeChat": "WeChat",
|
||||
"WebAuthn": "WebAuthn",
|
||||
"sign up now": "Regístrate ahora",
|
||||
"username, Email or phone": "Nombre de usuario, correo electrónico o teléfono"
|
||||
"username, Email or phone": "Nombre de usuario, correo electrónico o teléfono",
|
||||
"Kerberos": "Kerberos",
|
||||
"Sign in with Kerberos": "Iniciar sesión con autenticación de Windows"
|
||||
},
|
||||
"mfa": {
|
||||
"Each time you sign in to your Account, you'll need your password and a authentication code": "Cada vez que inicies sesión en tu cuenta, necesitarás tu contraseña y un código de autenticación",
|
||||
@@ -1504,4 +1506,4 @@
|
||||
"Single org only - Tooltip": "Activado solo en la organización a la que pertenece el webhook",
|
||||
"Value": "Valor"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@
|
||||
"Physical": "Physique",
|
||||
"Show all": "Afficher tout",
|
||||
"Virtual": "Virtuel",
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "Vous devez d'abord supprimer tous les sous-groupes. Vous pouvez voir les sous-groupes dans l'arborescence des groupes à gauche de la page [Organisations] -\u003e [Groupes]"
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -> [Groups] page": "Vous devez d'abord supprimer tous les sous-groupes. Vous pouvez voir les sous-groupes dans l'arborescence des groupes à gauche de la page [Organisations] -> [Groupes]"
|
||||
},
|
||||
"home": {
|
||||
"New users past 30 days": "Nouveaux utilisateurs ces 30 derniers jours",
|
||||
@@ -686,7 +686,9 @@
|
||||
"WeChat": "WeChat",
|
||||
"WebAuthn": "WebAuthn",
|
||||
"sign up now": "Inscrivez-vous maintenant",
|
||||
"username, Email or phone": "identifiant, adresse e-mail ou téléphone"
|
||||
"username, Email or phone": "identifiant, adresse e-mail ou téléphone",
|
||||
"Kerberos": "Kerberos",
|
||||
"Sign in with Kerberos": "Se connecter avec l'authentification Windows"
|
||||
},
|
||||
"mfa": {
|
||||
"Each time you sign in to your Account, you'll need your password and a authentication code": "Chaque fois que vous vous connectez à votre compte, vous aurez besoin de votre mot de passe et d'un code d'authentification",
|
||||
@@ -1504,4 +1506,4 @@
|
||||
"Single org only - Tooltip": "Déclenché uniquement dans l'organisation à laquelle appartient le webhook",
|
||||
"Value": "Valeur"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@
|
||||
"Physical": "物理",
|
||||
"Show all": "すべて表示",
|
||||
"Virtual": "仮想",
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "最初にすべてのサブグループを削除する必要があります。[組織] -\u003e [グループ]ページの左側のグループツリーでサブグループを確認できます"
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -> [Groups] page": "最初にすべてのサブグループを削除する必要があります。[組織] -> [グループ]ページの左側のグループツリーでサブグループを確認できます"
|
||||
},
|
||||
"home": {
|
||||
"New users past 30 days": "過去30日間の新規ユーザー",
|
||||
@@ -686,7 +686,9 @@
|
||||
"WeChat": "微信",
|
||||
"WebAuthn": "ウェブオーセン",
|
||||
"sign up now": "今すぐサインアップ",
|
||||
"username, Email or phone": "ユーザー名、メールアドレス、または電話番号"
|
||||
"username, Email or phone": "ユーザー名、メールアドレス、または電話番号",
|
||||
"Kerberos": "Kerberos",
|
||||
"Sign in with Kerberos": "Windows認証でサインイン"
|
||||
},
|
||||
"mfa": {
|
||||
"Each time you sign in to your Account, you'll need your password and a authentication code": "アカウントにサインインするたびに、パスワードと認証コードが必要です",
|
||||
@@ -1504,4 +1506,4 @@
|
||||
"Single org only - Tooltip": "Webhookが属する組織でのみトリガーされます",
|
||||
"Value": "値"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@
|
||||
"Physical": "Fizyczna",
|
||||
"Show all": "Pokaż wszystko",
|
||||
"Virtual": "Wirtualna",
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "Musisz najpierw usunąć wszystkie podgrupy. Możesz przeglądać podgrupy w lewym drzewie grup na stronie [Organizacje] -\u003e [Grupy]"
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -> [Groups] page": "Musisz najpierw usunąć wszystkie podgrupy. Możesz przeglądać podgrupy w lewym drzewie grup na stronie [Organizacje] -> [Grupy]"
|
||||
},
|
||||
"home": {
|
||||
"New users past 30 days": "Nowi użytkownicy w ciągu ostatnich 30 dni",
|
||||
@@ -686,7 +686,9 @@
|
||||
"WeChat": "WeChat",
|
||||
"WebAuthn": "WebAuthn",
|
||||
"sign up now": "zarejestruj się teraz",
|
||||
"username, Email or phone": "nazwa użytkownika, e-mail lub telefon"
|
||||
"username, Email or phone": "nazwa użytkownika, e-mail lub telefon",
|
||||
"Kerberos": "Kerberos",
|
||||
"Sign in with Kerberos": "Zaloguj się przy użyciu uwierzytelniania Windows"
|
||||
},
|
||||
"mfa": {
|
||||
"Each time you sign in to your Account, you'll need your password and a authentication code": "Za każdym razem, gdy logujesz się na swoje konto, potrzebujesz hasła i kodu uwierzytelniającego",
|
||||
@@ -1504,4 +1506,4 @@
|
||||
"Single org only - Tooltip": "Wyzwalane tylko w organizacji, do której należy webhook",
|
||||
"Value": "Wartość"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@
|
||||
"Physical": "Físico",
|
||||
"Show all": "Mostrar todos",
|
||||
"Virtual": "Virtual",
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "Você precisa excluir todos os subgrupos primeiro. Você pode visualizar os subgrupos na árvore de grupos à esquerda na página [Organizações] -\u003e [Grupos]"
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -> [Groups] page": "Você precisa excluir todos os subgrupos primeiro. Você pode visualizar os subgrupos na árvore de grupos à esquerda na página [Organizações] -> [Grupos]"
|
||||
},
|
||||
"home": {
|
||||
"New users past 30 days": "Novos usuários nos últimos 30 dias",
|
||||
@@ -686,7 +686,9 @@
|
||||
"WeChat": "WeChat",
|
||||
"WebAuthn": "WebAuthn",
|
||||
"sign up now": "Inscreva-se agora",
|
||||
"username, Email or phone": "Nome de usuário, email ou telefone"
|
||||
"username, Email or phone": "Nome de usuário, email ou telefone",
|
||||
"Kerberos": "Kerberos",
|
||||
"Sign in with Kerberos": "Entrar com autenticação do Windows"
|
||||
},
|
||||
"mfa": {
|
||||
"Each time you sign in to your Account, you'll need your password and a authentication code": "Cada vez que você entrar na sua conta, precisará da sua senha e de um código de autenticação",
|
||||
@@ -1504,4 +1506,4 @@
|
||||
"Single org only - Tooltip": "Acionado apenas na organização a qual o webhook pertence",
|
||||
"Value": "Valor"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@
|
||||
"Physical": "Fiziksel",
|
||||
"Show all": "Tümünü göster",
|
||||
"Virtual": "Sanal",
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "Önce tüm alt grupları silmeniz gerekir. Alt grupları [Organizasyonlar] -\u003e [Gruplar] sayfasının sol grup ağacından görüntüleyebilirsiniz."
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -> [Groups] page": "Önce tüm alt grupları silmeniz gerekir. Alt grupları [Organizasyonlar] -> [Gruplar] sayfasının sol grup ağacından görüntüleyebilirsiniz."
|
||||
},
|
||||
"home": {
|
||||
"New users past 30 days": "Son 30 gündeki yeni kullanıcılar",
|
||||
@@ -686,7 +686,9 @@
|
||||
"WeChat": "WeChat",
|
||||
"WebAuthn": "WebAuthn",
|
||||
"sign up now": "hemen kaydolun",
|
||||
"username, Email or phone": "kullanıcı adınız, Eposta adresiniz ve telefon numaranız"
|
||||
"username, Email or phone": "kullanıcı adınız, Eposta adresiniz ve telefon numaranız",
|
||||
"Kerberos": "Kerberos",
|
||||
"Sign in with Kerberos": "Windows Kimlik Doğrulaması ile giriş yap"
|
||||
},
|
||||
"mfa": {
|
||||
"Each time you sign in to your Account, you'll need your password and a authentication code": "Hesabınıza her oturum açtığınızda şifreniz ve bir doğrulama kodu gerekecek",
|
||||
@@ -1504,4 +1506,4 @@
|
||||
"Single org only - Tooltip": "Webhook'un ait olduğu organizasyonda yalnızca tetiklenir",
|
||||
"Value": "Değer"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@
|
||||
"Physical": "фізичний",
|
||||
"Show all": "Покажи все",
|
||||
"Virtual": "Віртуальний",
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "Спочатку потрібно видалити всі підгрупи. Підгрупи можна переглянути у лівому дереві груп на сторінці [Організації] -\u003e [Групи]"
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -> [Groups] page": "Спочатку потрібно видалити всі підгрупи. Підгрупи можна переглянути у лівому дереві груп на сторінці [Організації] -> [Групи]"
|
||||
},
|
||||
"home": {
|
||||
"New users past 30 days": "Нові користувачі за останні 30 днів",
|
||||
@@ -686,7 +686,9 @@
|
||||
"WeChat": "Вейчат",
|
||||
"WebAuthn": "WebAuthn",
|
||||
"sign up now": "Зареєструйся зараз",
|
||||
"username, Email or phone": "ім'я користувача, електронну пошту або телефон"
|
||||
"username, Email or phone": "ім'я користувача, електронну пошту або телефон",
|
||||
"Kerberos": "Kerberos",
|
||||
"Sign in with Kerberos": "Увійти через автентифікацію Windows"
|
||||
},
|
||||
"mfa": {
|
||||
"Each time you sign in to your Account, you'll need your password and a authentication code": "Кожного разу, коли ви входите в обліковий запис, вам знадобляться пароль і код автентифікації",
|
||||
@@ -1504,4 +1506,4 @@
|
||||
"Single org only - Tooltip": "Активується лише в організації, якій належить вебхук",
|
||||
"Value": "Значення"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@
|
||||
"Physical": "Vật lý",
|
||||
"Show all": "Hiển thị tất cả",
|
||||
"Virtual": "Ảo",
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "Bạn cần xóa tất cả nhóm con trước. Bạn có thể xem các nhóm con trong cây nhóm bên trái của trang [Tổ chức] -\u003e [Nhóm]"
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -> [Groups] page": "Bạn cần xóa tất cả nhóm con trước. Bạn có thể xem các nhóm con trong cây nhóm bên trái của trang [Tổ chức] -> [Nhóm]"
|
||||
},
|
||||
"home": {
|
||||
"New users past 30 days": "Người dùng mới trong 30 ngày qua",
|
||||
@@ -686,7 +686,9 @@
|
||||
"WeChat": "WeChat",
|
||||
"WebAuthn": "WebAuthn",
|
||||
"sign up now": "Đăng ký ngay bây giờ",
|
||||
"username, Email or phone": "Tên đăng nhập, Email hoặc điện thoại"
|
||||
"username, Email or phone": "Tên đăng nhập, Email hoặc điện thoại",
|
||||
"Kerberos": "Kerberos",
|
||||
"Sign in with Kerberos": "Đăng nhập bằng xác thực Windows"
|
||||
},
|
||||
"mfa": {
|
||||
"Each time you sign in to your Account, you'll need your password and a authentication code": "Mỗi lần đăng nhập vào Tài khoản của bạn, bạn sẽ cần mật khẩu và mã xác thực",
|
||||
@@ -1504,4 +1506,4 @@
|
||||
"Single org only - Tooltip": "Chỉ kích hoạt trong tổ chức mà webhook thuộc về",
|
||||
"Value": "Giá trị"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@
|
||||
"Physical": "实体组",
|
||||
"Show all": "显示全部",
|
||||
"Virtual": "虚拟组",
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -\u003e [Groups] page": "您需要先删除所有子组。您可以在 [组织] -\u003e [群组] 页面左侧的群组树中查看子组"
|
||||
"You need to delete all subgroups first. You can view the subgroups in the left group tree of the [Organizations] -> [Groups] page": "您需要先删除所有子组。您可以在 [组织] -> [群组] 页面左侧的群组树中查看子组"
|
||||
},
|
||||
"home": {
|
||||
"New users past 30 days": "过去 30 天新增的用户",
|
||||
@@ -686,7 +686,9 @@
|
||||
"WeChat": "微信",
|
||||
"WebAuthn": "Web身份验证",
|
||||
"sign up now": "立即注册",
|
||||
"username, Email or phone": "用户名、Email或手机号"
|
||||
"username, Email or phone": "用户名、Email或手机号",
|
||||
"Kerberos": "Kerberos",
|
||||
"Sign in with Kerberos": "使用Windows集成认证登录"
|
||||
},
|
||||
"mfa": {
|
||||
"Each time you sign in to your Account, you'll need your password and a authentication code": "每次登录帐户时,都需要密码和认证码",
|
||||
@@ -795,7 +797,16 @@
|
||||
"Website URL": "主页地址",
|
||||
"Website URL - Tooltip": "组织的主页地址URL,该字段在Casdoor平台中未被使用",
|
||||
"Widget items": "功能按钮",
|
||||
"Widget items - Tooltip": "小部件中显示的项目"
|
||||
"Widget items - Tooltip": "小部件中显示的项目",
|
||||
"Kerberos realm": "Kerberos 域",
|
||||
"Kerberos realm - Tooltip": "Kerberos 域(Active Directory 域名),例如 EXAMPLE.COM",
|
||||
"Kerberos KDC host": "KDC 主机",
|
||||
"Kerberos KDC host - Tooltip": "Kerberos 密钥分发中心(KDC)主机名,留空则使用 DNS 自动发现",
|
||||
"Kerberos service name": "服务主体名称",
|
||||
"Kerberos service name - Tooltip": "此 Casdoor 实例的 Kerberos 服务主体名称(SPN),例如 HTTP/casdoor.example.com",
|
||||
"Kerberos keytab": "Keytab(Base64)",
|
||||
"Kerberos keytab - Tooltip": "Base64 编码的服务 keytab 文件,用于验证 Kerberos 令牌",
|
||||
"Kerberos keytab placeholder": "在此处粘贴 Base64 编码的 keytab 文件内容"
|
||||
},
|
||||
"payment": {
|
||||
"Confirm your invoice information": "确认您的发票信息",
|
||||
@@ -1504,4 +1515,4 @@
|
||||
"Single org only - Tooltip": "仅在Webhook所在组织触发",
|
||||
"Value": "值"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,7 @@ class SigninMethodTable extends React.Component {
|
||||
{name: "Verification code", displayName: i18next.t("login:Verification code")},
|
||||
{name: "WebAuthn", displayName: i18next.t("login:WebAuthn")},
|
||||
{name: "LDAP", displayName: i18next.t("login:LDAP")},
|
||||
{name: "Kerberos", displayName: i18next.t("login:Kerberos")},
|
||||
{name: "Face ID", displayName: i18next.t("login:Face ID")},
|
||||
{name: "WeChat", displayName: i18next.t("login:WeChat")},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user